<commit_before>( function( mw, $ ) {"use strict";

	mw.PluginManager.add( 'related', mw.KBaseScreen.extend({

		defaultConfig: {
			parent: "topBarContainer",
			order: 4,
			align: "right",
			tooltip: 'Related',
			showTooltip: true,
			//visible: false,
			itemsLimit: 12,
			displayOnPlaybackDone: true,
			autoContinueEnabled: true,
			autoContinueTime: null,
			templatePath: 'components/related/related.tmpl.html',
			playlistId: null,
			formatCountdown : false,
			clickUrl : null,
			enableAccessControlExclusion:false,
			storeSession: false
		},
		viewedEntries: [],
		iconBtnClass: 'icon-related',
		confPrefix: 'related',
		timerRunning:false,

		setup: function(){
			var _this = this;
			// check for storedSession of viewed entries:
			if( this.getConfig('storeSession') ){
				var rawViewed = $.cookie( this.confPrefix + '_viewedEntries' );
				if( rawViewed ){
					this.viewedEntries = JSON.parse( rawViewed );
				}
			}

			this.bind('playerReady', function(){
				// Stop timer
				_this.stopTimer();

				// Reset our items data
				_this.templateData = null;

				// Load items data
				_this.getItemsData();
			});

			this.bind('onOpenFullScreen', function() {
				setTimeout(function(){
					$('.item-inner img').each(function() {
						$(this).css("margin-top", 0 +"px");
						$(this).css("margin-left", 0 +"px");
						$(this).width("100%");
						$(this).height("100%");
					});
					_this.resizeThumbs();
				},200);

			});
			this.bind('onCloseFullScreen', function() {
				setTimeout(function(){
					$('.item-inner img').each(function() {
						$(this).css("margin-top", 0 +"px");
						$(this).css("margin-left", 0 +"px");
						$(this).width("100%");
						$(this).height("100%");
					});
					_this.resizeThumbs();
				},200);
			});

			if( this.getConfig('displayOnPlaybackDone') ){
				this.bind('onEndedDone', function(){
					if ( _this.error ) {
						return;
					}
					_this.showScreen();
					if( _this.getConfig('autoContinueEnabled') && _this.getConfig('autoContinueTime') ){
						_this.startTimer();
					}
				});
			}

			this.bind('replayEvent preSequence', function(){
				_this.stopTimer();
			});
		},

		showScreen: function(){
			this._super(); // this is an override of showScreen in mw.KBaseScreen.js - call super
			this.resizeThumbs();
		},

		resizeThumbs: function(){
			// resize and crop from center all thumbnails
			$('.item-inner').each(function() {
				// set css class according to image aspect ratio
				var cssClass = $(this).width() / $(this).height() > 1.45 ? 'wide' : 'square';
				$(this).find("img").removeClass().addClass(cssClass);
				var img = $(this).find("img")[0];

				var divWidth = $(this).width();    // save img div container width for cropping logic
				var divHeight = $(this).height();  // save img div container height for cropping logic

				// crop image from center. use a timeout to make sure the image is already resized before changing its margins
				setTimeout(function() {
					var heightOffset, widthOffset;
					var $img = $( img );
					if ( cssClass === 'wide' ) {
						heightOffset = ($img.height() - divHeight) / 2;
						if ( heightOffset > 0 ) {
							$img.css( "margin-top" , heightOffset * (-1) + 'px' );
						} else {
							$img.width( $img.width() * divHeight / $img.height() );
							$img.height( divHeight );
							widthOffset = ($img.width() - divWidth) / 2;
							$img.css( "margin-left" , widthOffset * (-1) + 'px' );
						}
					} else {
						widthOffset = ($img.width() - divWidth) / 2;
						if ( widthOffset > 0 ) {
							$img.css( "margin-left" , widthOffset * (-1) + 'px' );
						} else {
							$img.height( $img.height() * divWidth / $img.width() );
							$img.width( divWidth );
							heightOffset = ($img.height() - divHeight) / 2;
							$img.css( "margin-top" , heightOffset * (-1) + 'px' );
						}
					}
				},300);
			});
		},

		startTimer: function(){
			if (this.timerRunning){
				return;
			}
			this.timerRunning = true;
			var _this = this;
			var updateTimeRemaining = function(){
				var ct = _this.getConfig('timeRemaining');
				if( ct > 0 ){
					_this.setConfig('timeRemaining', --ct);
					_this.timeRemainingMonitor = setTimeout(updateTimeRemaining, 1000);
				} else {
					_this.stopTimer();
					// Make sure we change media only if related is visible and we have next item
					if( _this.isScreenVisible() && _this.templateData && _this.templateData.nextItem ){
						_this.changeMedia( null, {entryId: _this.templateData.nextItem.id} );
						_this.viewedEntries.push(_this.templateData.nextItem.id);
						// update the session var if storing sessions:
						if( _this.getConfig('storeSession') ){
							$.cookie( _this.confPrefix + '_viewedEntries', JSON.stringify( _this.viewedEntries ) );
						}
					}
				}
			};
			setTimeout(updateTimeRemaining, 1000);
		},
		pauseTimer: function(){
			// Clear our interval
			clearTimeout(this.timeRemainingMonitor);
			this.timeRemainingMonitor = null;
		},
		disableAutoContinue: function() {
			this.setConfig('autoContinueEnabled', false);
			this.pauseTimer();
		},
		enableAutoContinue: function(){
			this.setConfig('autoContinueEnabled', true);
			this.startTimer();
		},
		toggleAutoContinue: function(){
			if( this.getConfig('autoContinueEnabled') ){
				this.disableAutoContinue();
			} else {
				this.enableAutoContinue();
			}
		},
		stopTimer: function(){
			this.timerRunning = false;
			this.pauseTimer();
			// Set remaining time to auto continue time
			this.setConfig('timeRemaining', this.getConfig('autoContinueTime'));
		},
		getItemsData: function( callback ){
			callback = callback || function(){};
			if( !this.templateData ){
				var _this = this;

				// Allow other plugins to inject data
				this.getPlayer().triggerQueueCallback( 'relatedData', function( args ){
					// Get data from event
					if( args ){
						_this.templateData = args[0];
						callback();
						return ;
					}
					_this.getDataFromApi( function(data){
						// make sure entries that were already viewed are the last in the data array
						for (var i = 0; i < _this.viewedEntries.length; i++){
							for (var j = 0; j < data.length; j++){
								if (data[j].id === _this.viewedEntries[i]){ // entry was already viewed - move it to the last place in the data array
									var entry = data.splice(j,1)[0];
									data.push(entry);
								}
							}
						}
						_this.templateData = {
							nextItem: data.splice(0,1)[0],
							moreItems: data
						};
					});
				});
				return;
			}
			callback();
			return;
		},
		getDataFromApi: function( callback ){
			var _this = this;
			// check for valid playlist id:
			if( this.getConfig( 'playlistId' ) ){
				return this.getEntriesFromPlaylistId( this.getConfig( 'playlistId' ), callback);
			}
			// check for entry list:
			if( this.getConfig( 'entryList' ) ){
				return this.getEntriesFromList( this.getConfig( 'entryList' ), callback );
			}
			// if no playlist is defined used the magic related video playlistd id:
			return this.getEntriesFromPlaylistId( '_KDP_CTXPL', callback, true);
		},
		isValidResult: function( data ){
			// Check if we got error
			if( !data
				||
				( data.code && data.message )
				){
				this.log('Error getting related items: ' + data.message);
				this.getBtn().hide();
				this.error = true;
				return false;
			}
			this.error = false;
			return true;
		},
		getEntriesFromList: function( entryList, callback){
			var _this =this;
			this.getKalturaClient().doRequest( {
				'service': 'baseEntry',
				'action': 'getbyids',
				'entryIds': entryList
			}, function( data ){
				// Validate result
				if( ! _this.isValidResult( data ) ) {
					return ;
				}

				// restore "entryList" order
				var orderedData = [];
				var entrylistArry = entryList.split(',');
				for(var i in entrylistArry){
					if (i >= parseInt(_this.getConfig('itemsLimit'))){
						break;
					}
					var entryId = entrylistArry[i];
					for(var j in data){
						if( data[j]['id'] == entryId){
							orderedData.push( data.splice( j, 1)[0] );
						}
					}
				}
				if  (_this.getConfig("enableAccessControlExclusion") ) {
					_this.filterAccessControl(orderedData ).then(function(acData){
						callback(acData);
					})

				} else {
					callback( orderedData );
				}

			});
		},
		getEntriesFromPlaylistId: function( playlistId, callback, sendContext ){
			var _this = this;
			var requestObject = {
				'service' : 'playlist',
				'action' : 'execute',
				'id' : playlistId,
				'filter:objectType': 'KalturaMediaEntryFilterForPlaylist',
				'filter:idNotIn': this.getPlayer().kentryid,
				'filter:limit': this.getConfig('itemsLimit')
			}
			if ( sendContext ) {
				requestObject['playlistContext:objectType'] = 'KalturaEntryContext';
				requestObject['playlistContext:entryId'] = this.getPlayer().kentryid;
			}
			this.getKalturaClient().doRequest( requestObject, function( data ) {
				// Validate result, don't issue callback if not valid.
				if ( !_this.isValidResult( data ) ) {
					return;
				}
				// Work around for PLAT-1680 limit not being respected:
				if ( data.length > parseInt( _this.getConfig( 'itemsLimit' ) ) ) {
					data = data.slice( 0 , parseInt( _this.getConfig( 'itemsLimit' ) ) );
				}
				if ( _this.getConfig( "enableAccessControlExclusion" ) ) {
					_this.filterAccessControl( data ).then( function ( acData ) {
						callback( acData );
					});
				} else {
					callback( data );
				}

			});
		},

		changeMedia: function( e, data ){
			this.stopTimer();
			var _this = this;
			//look for the entry in case this is a click
			if(this.getConfig('clickUrl')){
				if(this.templateData.nextItem.id && this.templateData.nextItem.id == data.entryId ){
					//search in the next item
					data = this.templateData.nextItem;
					this.setConfig('selectedEntry',this.templateData.nextItem);
				} else if(this.templateData.moreItems) {
					// look for the entry in the other items
					for (var i = 0; i < this.templateData.moreItems.length;  i++) {
						if(data.entryId == this.templateData.moreItems[i].id ){
							data = this.templateData.moreItems[i];
							this.setConfig('selectedEntry',this.templateData.moreItems[i]);
						}
					}
				}
			}

			this.getPlayer().sendNotification('relatedVideoSelect', data);

			if(this.getConfig('clickUrl')){
				try {
					window.parent.location.href = this.getConfig('clickUrl');
					return;
				}catch(err){
					window.open(this.getConfig('clickUrl'));
					return;
				}
			}

			this.getPlayer().sendNotification('changeMedia', data);
			this.bind('onChangeMediaDone', function(){
				_this.getPlayer().play();
				_this.unbind('onChangeMediaDone');
			});
			this.hideScreen();
		},
		onConfigChange: function( property, value ){
			this._super( property, value );
			if( !this.isScreenVisible() ) {
				return;
			}

			if( property == 'timeRemaining' ){
				if( this.getConfig('formatCountdown')){
					var timeFormat = mw.KDPMapping.prototype.formatFunctions.timeFormat;
					this.getScreen().find('.remaining').html(timeFormat(value));
				}else{
					this.getScreen().find('.remaining').html(value);
				}
			}
		},
		filterAccessControl:function(data) {
			var defer = $.Deferred();
			var acList = {};
			var acIndex = [];
			for (var i in data){
				if ( !acList[ data[i].accessControlId ] ) {
					acList[ data[i].accessControlId ] = data[i].id;
					acIndex[ acIndex.length ] = data[i].accessControlId;
				}
			}
			var requestArray = [];
			for(var i in acList) {
				var requestObject = {
					'service' : 'baseEntry',
					'action' : 'getContextData',
					'contextDataParams':{
						'referrer' : window.kWidgetSupport.getHostPageUrl(),
						'objectType' : 'KalturaEntryContextDataParams',
						'flavorTags': "all"},
					'streamerType': "http",
					"entryId": acList[i]
				};
				requestArray.push( requestObject );
			}
			if ( requestArray.length ) {
				this.getKalturaClient().doRequest( requestArray, function( EntryContextDataArray ) {
					$.each( EntryContextDataArray , function( index , EntryContextData ) {
						var isRestricted = false;
						var checkFalse = ['isCountryRestricted','isIpAddressRestricted','isSessionRestricted','isSiteRestricted','isUserAgentRestricted'];
						var checkTrue = ['isScheduledNow'];
						$.each(checkFalse,function(index,item){
							if ( EntryContextData[item] ){
								isRestricted = true;
							}
						});
						$.each(checkTrue,function(index,item){
							if ( !EntryContextData[item] ){
								isRestricted = true;
							}
						});
						for (var i in acList){
							if (acList[i] === requestArray[index].entryId){
								acList[i] = isRestricted;
							}
						}
					});
					var verifiedEntryList = [];
					$.each(data,function(index,entry){
						if ( !acList[entry.accessControlId] ){
							verifiedEntryList.push(entry);
						}
					});
					defer.resolve(verifiedEntryList);
				});
			}
			return defer;
		}
	}));

} )( window.mw, window.jQuery );<commit_msg>#FEC-2291 #time 1h #comment update viewed entries list on all change media options: autoContinue, user click and clickUrl<commit_after>( function( mw, $ ) {"use strict";

	mw.PluginManager.add( 'related', mw.KBaseScreen.extend({

		defaultConfig: {
			parent: "topBarContainer",
			order: 4,
			align: "right",
			tooltip: 'Related',
			showTooltip: true,
			//visible: false,
			itemsLimit: 12,
			displayOnPlaybackDone: true,
			autoContinueEnabled: true,
			autoContinueTime: null,
			templatePath: 'components/related/related.tmpl.html',
			playlistId: null,
			formatCountdown : false,
			clickUrl : null,
			enableAccessControlExclusion:false,
			storeSession: false
		},
		viewedEntries: [],
		iconBtnClass: 'icon-related',
		confPrefix: 'related',
		timerRunning:false,

		setup: function(){
			var _this = this;
			// check for storedSession of viewed entries:
			if( this.getConfig('storeSession') ){
				var rawViewed = $.cookie( this.confPrefix + '_viewedEntries' );
				if( rawViewed ){
					this.viewedEntries = JSON.parse( rawViewed );
				}
			}

			this.bind('playerReady', function(){
				// Stop timer
				_this.stopTimer();

				// Reset our items data
				_this.templateData = null;

				// Load items data
				_this.getItemsData();
			});

			this.bind('onOpenFullScreen', function() {
				setTimeout(function(){
					$('.item-inner img').each(function() {
						$(this).css("margin-top", 0 +"px");
						$(this).css("margin-left", 0 +"px");
						$(this).width("100%");
						$(this).height("100%");
					});
					_this.resizeThumbs();
				},200);

			});
			this.bind('onCloseFullScreen', function() {
				setTimeout(function(){
					$('.item-inner img').each(function() {
						$(this).css("margin-top", 0 +"px");
						$(this).css("margin-left", 0 +"px");
						$(this).width("100%");
						$(this).height("100%");
					});
					_this.resizeThumbs();
				},200);
			});

			if( this.getConfig('displayOnPlaybackDone') ){
				this.bind('onEndedDone', function(){
					if ( _this.error ) {
						return;
					}
					_this.showScreen();
					if( _this.getConfig('autoContinueEnabled') && _this.getConfig('autoContinueTime') ){
						_this.startTimer();
					}
				});
			}

			this.bind('replayEvent preSequence', function(){
				_this.stopTimer();
			});
		},

		showScreen: function(){
			this._super(); // this is an override of showScreen in mw.KBaseScreen.js - call super
			this.resizeThumbs();
		},

		resizeThumbs: function(){
			// resize and crop from center all thumbnails
			$('.item-inner').each(function() {
				// set css class according to image aspect ratio
				var cssClass = $(this).width() / $(this).height() > 1.45 ? 'wide' : 'square';
				$(this).find("img").removeClass().addClass(cssClass);
				var img = $(this).find("img")[0];

				var divWidth = $(this).width();    // save img div container width for cropping logic
				var divHeight = $(this).height();  // save img div container height for cropping logic

				// crop image from center. use a timeout to make sure the image is already resized before changing its margins
				setTimeout(function() {
					var heightOffset, widthOffset;
					var $img = $( img );
					if ( cssClass === 'wide' ) {
						heightOffset = ($img.height() - divHeight) / 2;
						if ( heightOffset > 0 ) {
							$img.css( "margin-top" , heightOffset * (-1) + 'px' );
						} else {
							$img.width( $img.width() * divHeight / $img.height() );
							$img.height( divHeight );
							widthOffset = ($img.width() - divWidth) / 2;
							$img.css( "margin-left" , widthOffset * (-1) + 'px' );
						}
					} else {
						widthOffset = ($img.width() - divWidth) / 2;
						if ( widthOffset > 0 ) {
							$img.css( "margin-left" , widthOffset * (-1) + 'px' );
						} else {
							$img.height( $img.height() * divWidth / $img.width() );
							$img.width( divWidth );
							heightOffset = ($img.height() - divHeight) / 2;
							$img.css( "margin-top" , heightOffset * (-1) + 'px' );
						}
					}
				},300);
			});
		},

		startTimer: function(){
			if (this.timerRunning){
				return;
			}
			this.timerRunning = true;
			var _this = this;
			var updateTimeRemaining = function(){
				var ct = _this.getConfig('timeRemaining');
				if( ct > 0 ){
					_this.setConfig('timeRemaining', --ct);
					_this.timeRemainingMonitor = setTimeout(updateTimeRemaining, 1000);
				} else {
					_this.stopTimer();
					// Make sure we change media only if related is visible and we have next item
					if( _this.isScreenVisible() && _this.templateData && _this.templateData.nextItem ){
						_this.changeMedia( null, {entryId: _this.templateData.nextItem.id} );
					}
				}
			};
			setTimeout(updateTimeRemaining, 1000);
		},
		pauseTimer: function(){
			// Clear our interval
			clearTimeout(this.timeRemainingMonitor);
			this.timeRemainingMonitor = null;
		},
		disableAutoContinue: function() {
			this.setConfig('autoContinueEnabled', false);
			this.pauseTimer();
		},
		enableAutoContinue: function(){
			this.setConfig('autoContinueEnabled', true);
			this.startTimer();
		},
		toggleAutoContinue: function(){
			if( this.getConfig('autoContinueEnabled') ){
				this.disableAutoContinue();
			} else {
				this.enableAutoContinue();
			}
		},
		stopTimer: function(){
			this.timerRunning = false;
			this.pauseTimer();
			// Set remaining time to auto continue time
			this.setConfig('timeRemaining', this.getConfig('autoContinueTime'));
		},
		getItemsData: function( callback ){
			callback = callback || function(){};
			if( !this.templateData ){
				var _this = this;

				// Allow other plugins to inject data
				this.getPlayer().triggerQueueCallback( 'relatedData', function( args ){
					// Get data from event
					if( args ){
						_this.templateData = args[0];
						callback();
						return ;
					}
					_this.getDataFromApi( function(data){
						// make sure entries that were already viewed are the last in the data array
						for (var i = 0; i < _this.viewedEntries.length; i++){
							for (var j = 0; j < data.length; j++){
								if (data[j].id === _this.viewedEntries[i]){ // entry was already viewed - move it to the last place in the data array
									var entry = data.splice(j,1)[0];
									data.push(entry);
								}
							}
						}
						_this.templateData = {
							nextItem: data.splice(0,1)[0],
							moreItems: data
						};
					});
				});
				return;
			}
			callback();
			return;
		},
		getDataFromApi: function( callback ){
			var _this = this;
			// check for valid playlist id:
			if( this.getConfig( 'playlistId' ) ){
				return this.getEntriesFromPlaylistId( this.getConfig( 'playlistId' ), callback);
			}
			// check for entry list:
			if( this.getConfig( 'entryList' ) ){
				return this.getEntriesFromList( this.getConfig( 'entryList' ), callback );
			}
			// if no playlist is defined used the magic related video playlistd id:
			return this.getEntriesFromPlaylistId( '_KDP_CTXPL', callback, true);
		},
		isValidResult: function( data ){
			// Check if we got error
			if( !data
				||
				( data.code && data.message )
				){
				this.log('Error getting related items: ' + data.message);
				this.getBtn().hide();
				this.error = true;
				return false;
			}
			this.error = false;
			return true;
		},
		getEntriesFromList: function( entryList, callback){
			var _this =this;
			this.getKalturaClient().doRequest( {
				'service': 'baseEntry',
				'action': 'getbyids',
				'entryIds': entryList
			}, function( data ){
				// Validate result
				if( ! _this.isValidResult( data ) ) {
					return ;
				}

				// restore "entryList" order
				var orderedData = [];
				var entrylistArry = entryList.split(',');
				for(var i in entrylistArry){
					if (i >= parseInt(_this.getConfig('itemsLimit'))){
						break;
					}
					var entryId = entrylistArry[i];
					for(var j in data){
						if( data[j]['id'] == entryId){
							orderedData.push( data.splice( j, 1)[0] );
						}
					}
				}
				if  (_this.getConfig("enableAccessControlExclusion") ) {
					_this.filterAccessControl(orderedData ).then(function(acData){
						callback(acData);
					})

				} else {
					callback( orderedData );
				}

			});
		},
		getEntriesFromPlaylistId: function( playlistId, callback, sendContext ){
			var _this = this;
			var requestObject = {
				'service' : 'playlist',
				'action' : 'execute',
				'id' : playlistId,
				'filter:objectType': 'KalturaMediaEntryFilterForPlaylist',
				'filter:idNotIn': this.getPlayer().kentryid,
				'filter:limit': this.getConfig('itemsLimit')
			}
			if ( sendContext ) {
				requestObject['playlistContext:objectType'] = 'KalturaEntryContext';
				requestObject['playlistContext:entryId'] = this.getPlayer().kentryid;
			}
			this.getKalturaClient().doRequest( requestObject, function( data ) {
				// Validate result, don't issue callback if not valid.
				if ( !_this.isValidResult( data ) ) {
					return;
				}
				// Work around for PLAT-1680 limit not being respected:
				if ( data.length > parseInt( _this.getConfig( 'itemsLimit' ) ) ) {
					data = data.slice( 0 , parseInt( _this.getConfig( 'itemsLimit' ) ) );
				}
				if ( _this.getConfig( "enableAccessControlExclusion" ) ) {
					_this.filterAccessControl( data ).then( function ( acData ) {
						callback( acData );
					});
				} else {
					callback( data );
				}

			});
		},

		updateViewedEntries: function (entryId) {
			this.viewedEntries.push(entryId);
			// update the session var if storing sessions:
			if (this.getConfig('storeSession')) {
				$.cookie(this.confPrefix + '_viewedEntries', JSON.stringify(this.viewedEntries));
			}
		},

		changeMedia: function( e, data ){
			this.stopTimer();
			var _this = this;
			//look for the entry in case this is a click
			if(this.getConfig('clickUrl')){
				if(this.templateData.nextItem.id && this.templateData.nextItem.id == data.entryId ){
					//search in the next item
					data = this.templateData.nextItem;
					this.setConfig('selectedEntry',this.templateData.nextItem);
				} else if(this.templateData.moreItems) {
					// look for the entry in the other items
					for (var i = 0; i < this.templateData.moreItems.length;  i++) {
						if(data.entryId == this.templateData.moreItems[i].id ){
							data = this.templateData.moreItems[i];
							this.setConfig('selectedEntry',this.templateData.moreItems[i]);
						}
					}
				}
			}

			this.getPlayer().sendNotification('relatedVideoSelect', data);

			if(this.getConfig('clickUrl')){
				this.updateViewedEntries(data.entryId);
				try {
					window.parent.location.href = this.getConfig('clickUrl');
					return;
				}catch(err){
					window.open(this.getConfig('clickUrl'));
					return;
				}
			}

			this.getPlayer().sendNotification('changeMedia', data);
			this.bind('onChangeMediaDone', function(){
				_this.updateViewedEntries(data.entryId);
				_this.getPlayer().play();
				_this.unbind('onChangeMediaDone');
			});
			this.hideScreen();
		},
		onConfigChange: function( property, value ){
			this._super( property, value );
			if( !this.isScreenVisible() ) {
				return;
			}

			if( property == 'timeRemaining' ){
				if( this.getConfig('formatCountdown')){
					var timeFormat = mw.KDPMapping.prototype.formatFunctions.timeFormat;
					this.getScreen().find('.remaining').html(timeFormat(value));
				}else{
					this.getScreen().find('.remaining').html(value);
				}
			}
		},
		filterAccessControl:function(data) {
			var defer = $.Deferred();
			var acList = {};
			var acIndex = [];
			for (var i in data){
				if ( !acList[ data[i].accessControlId ] ) {
					acList[ data[i].accessControlId ] = data[i].id;
					acIndex[ acIndex.length ] = data[i].accessControlId;
				}
			}
			var requestArray = [];
			for(var i in acList) {
				var requestObject = {
					'service' : 'baseEntry',
					'action' : 'getContextData',
					'contextDataParams':{
						'referrer' : window.kWidgetSupport.getHostPageUrl(),
						'objectType' : 'KalturaEntryContextDataParams',
						'flavorTags': "all"},
					'streamerType': "http",
					"entryId": acList[i]
				};
				requestArray.push( requestObject );
			}
			if ( requestArray.length ) {
				this.getKalturaClient().doRequest( requestArray, function( EntryContextDataArray ) {
					$.each( EntryContextDataArray , function( index , EntryContextData ) {
						var isRestricted = false;
						var checkFalse = ['isCountryRestricted','isIpAddressRestricted','isSessionRestricted','isSiteRestricted','isUserAgentRestricted'];
						var checkTrue = ['isScheduledNow'];
						$.each(checkFalse,function(index,item){
							if ( EntryContextData[item] ){
								isRestricted = true;
							}
						});
						$.each(checkTrue,function(index,item){
							if ( !EntryContextData[item] ){
								isRestricted = true;
							}
						});
						for (var i in acList){
							if (acList[i] === requestArray[index].entryId){
								acList[i] = isRestricted;
							}
						}
					});
					var verifiedEntryList = [];
					$.each(data,function(index,entry){
						if ( !acList[entry.accessControlId] ){
							verifiedEntryList.push(entry);
						}
					});
					defer.resolve(verifiedEntryList);
				});
			}
			return defer;
		}
	}));

} )( window.mw, window.jQuery );<|endoftext|>


<commit_before>/*
 * jQuery doTimeout: Like setTimeout, but better! - v1.0 - 3/3/2010
 * http://benalman.com/projects/jquery-dotimeout-plugin/
 *
 * Copyright (c) 2010 "Cowboy" Ben Alman
 * Dual licensed under the MIT and GPL licenses.
 * http://benalman.com/about/license/
 */
(function($){var a={},c="doTimeout",d=Array.prototype.slice;$[c]=function(){return b.apply(window,[0].concat(d.call(arguments)))};$.fn[c]=function(){var f=d.call(arguments),e=b.apply(this,[c+f[0]].concat(f));return typeof f[0]==="number"||typeof f[1]==="number"?this:e};function b(l){var m=this,h,k={},g=l?$.fn:$,n=arguments,i=4,f=n[1],j=n[2],p=n[3];if(typeof f!=="string"){i--;f=l=0;j=n[1];p=n[2]}if(l){h=m.eq(0);h.data(l,k=h.data(l)||{})}else{if(f){k=a[f]||(a[f]={})}}k.id&&clearTimeout(k.id);delete k.id;function e(){if(l){h.removeData(l)}else{if(f){delete a[f]}}}function o(){k.id=setTimeout(function(){k.fn()},j)}if(p){k.fn=function(q){if(typeof p==="string"){p=g[p]}p.apply(m,d.call(n,i))===true&&!q?o():e()};o()}else{if(k.fn){j===undefined?e():k.fn(j===false);return true}else{e()}}}})(jQuery);

// Making sure that console.log does not throw errors on Firefox + IE etc.
if (typeof console == "undefined") var console = { log: function() {} };

var DiscoJuice = {};

/*
 * Country codes available here http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
 */
DiscoJuice.Constants = {
	"Countries": {
		'AU': 'Australia',
		'AT': 'Austria',
		'CZ': 'Czech',
		'CA': 'Canada',
		'DK': 'Denmark',
		'FI': 'Finland',
		'FR': 'France',
		'DE': 'Germany',
		'GR': 'Greece',
		'HR': 'Croatia',
		'IE': 'Ireland',
		'IT': 'Italy',
		'IS': 'Iceland',
		'JP': 'Japan',
		'HU': 'Hungary',
		'LU': 'Luxembourg',
		'NL': 'Netherlands',
		'NO': 'Norway',
		'NZ': 'New Zealand',
		'PL': 'Poland',
		'PT': 'Portugal',
		'SI': 'Slovenia',
		'ES': 'Spain',
		'SE': 'Sweden',
		'CH': 'Switzerland',
		'TR': 'Turkey',
		'US': 'USA',
		'GB': 'UK',
		'XX': 'Experimental'
	},
	"Flags": {
		'AU': 'au.png',
		'AT': 'at.png',
		'CZ': 'cz.png',
		'CA': 'ca.png',
		'DK': 'dk.png',
		'FI': 'fi.png',
		'FR': 'fr.png',
		'DE': 'de.png',
		'GR': 'gr.png',
		'HR': 'hr.png',
		'IE': 'ie.png',
		'IT': 'it.png',
		'IS': 'is.png',
		'JP': 'jp.png',
		'HU': 'hu.png',
		'LU': 'lu.png',
		'NL': 'nl.png',
		'NZ': 'nz.png',
		'NO': 'no.png',
		'PL': 'pl.png',
		'PT': 'pt.png',
		'SI': 'si.png',
		'ES': 'es.png',
		'SE': 'se.png',
		'CH': 'ch.png',
		'TR': 'tr.png',
		'GB': 'gb.png',
		'US': 'us.png'
	}
};

DiscoJuice.Utils = {
	"log": function(string) {
		console.log(string);
		// opera.postError(string);
	},
	"options": function() {
		var options;
		return {
			"get": function (key, def) {
	//			DiscoJuice.log(options);
	//			DiscoJuice.log('Getting [' + key + '] default [' + def + '] val [' + options[key] + ']');
				if (!options) return def;
				if (!options[key]) return def;
				return options[key];
			},
			"set": function(opts) {
				options = opts;
			},
			"update": function(key, value) {
				options[key] = value;
			}
		}
	}(),

	/* Functions for setting, reading and erasing cookies */
	"createCookie": function(value, type) {
		var type = type || 'EntityID';
		var name = '_DiscoJuice_' + type;
		var days = 1825;
		if (days) {
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			var expires = "; expires="+date.toGMTString();
		}
		else var expires = "";
		document.cookie = name+"="+escape(value)+expires+"; path=/";
	},
	"readCookie": function(type) {
		var type = type || 'EntityID';
		var name = '_DiscoJuice_' + type;
		var days = 1825;
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for(var i=0;i < ca.length;i++) {
			var c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length);
			if (c.indexOf(nameEQ) == 0) return unescape(c.substring(nameEQ.length,c.length));
		}
		return null;
	},
	"eraseCookie": function (type) {
		var type = type || 'EntityID';
		var name = '_DiscoJuice_' + type;
		DiscoJuice.createCookie(name,"",-1);
	},
	/* ------ ------ ------ ------ ------ */

	/*
	 * Performs a search 'term' against an entity.
	 * If no match, return false.
	 * If match return the keyword that matches.
	 */
	"searchMatch": function(item, term) {
		if (item.title.toLowerCase().search(term.toLowerCase()) !== -1) return true;
		if (item.descr && item.descr.toLowerCase().search(term.toLowerCase()) !== -1) return true;
		var key, i, keyword;

		if (item.keywords) {
			for(key in item.keywords) {
				keyword = item.keywords[key];
				for(i = 0; i < keyword.length; i++) {
					if (keyword[i].toLowerCase().search(term.toLowerCase()) !== -1) return keyword[i];
				}
			}
		}
		return false;
	},

	// calculate distance between two locations
	"calculateDistance": function (lat1, lon1, lat2, lon2) {
		var R = 6371; // km
		var dLat = this.toRad(lat2-lat1);
		var dLon = this.toRad(lon2-lon1);
		var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
				Math.cos(this.toRad(lat1)) * Math.cos(this.toRad(lat2)) *
				Math.sin(dLon/2) * Math.sin(dLon/2);
		var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
		var d = R * c;
		return d;
	},

	"toRad": function (deg) {
		return deg * Math.PI/180;
	},

	"waiter": function (completed, waitSeconds) {

		var
		 	my = {},
			parallellActions = [],
			executed = false;

		function execute () {

			if (executed) {
				console.log('Execution cancelled. Already performed.');
				return;
			}

			executed = true;
			completed(my);
		}

		function runAction (act, tooLate) {
			var
				thisAction = {completed: false};

			parallellActions.push(thisAction);
			console.log('Running action ' + parallellActions.length);
			act(function () {
				var i;
				thisAction.completed = true;
				for (i = 0; i < parallellActions.length; i++) {
					if (!parallellActions[i].completed) {
						console.log('Cannot execute because we are waiting for another action to complete.');
						return;
					}
				}
				if (executed) {
					if (my.allowMultiple) {
						console.log('Slow response; but executing anyway!!');
						execute();
					} else if (typeof tooLate === 'function') {
						console.log('All actions completed. Too late for executing...');
						tooLate();
					}
					return;
				}
				console.log('All actions completed. Executing!');
				execute();
			});

		}

		function startTimer() {
			if (parallellActions.length === 0) {
				console.log('Executing because no action is scheduled....');
				if (!executed) execute();
				return;
			}

			setTimeout(function() {
				console.log('Action timeout!');
				if (!executed) execute();
			}, waitSeconds);

		}

		my.allowMultiple = false;

		my.startTimer = startTimer;
		my.runAction = runAction;
		return my;
	}

};

/*
	Plugin for JQuery.
	*/
(function($) {
	$.fn.DiscoJuice = function(options) {
		return this.each(function() {
			DiscoJuice.Utils.options.set(options);

			DiscoJuice.Control.ui = DiscoJuice.UI;
			DiscoJuice.UI.control = DiscoJuice.Control;

			DiscoJuice.UI.enable(this);

		});
	};
})(jQuery);

<commit_msg>adding china<commit_after>/*
 * jQuery doTimeout: Like setTimeout, but better! - v1.0 - 3/3/2010
 * http://benalman.com/projects/jquery-dotimeout-plugin/
 *
 * Copyright (c) 2010 "Cowboy" Ben Alman
 * Dual licensed under the MIT and GPL licenses.
 * http://benalman.com/about/license/
 */
(function($){var a={},c="doTimeout",d=Array.prototype.slice;$[c]=function(){return b.apply(window,[0].concat(d.call(arguments)))};$.fn[c]=function(){var f=d.call(arguments),e=b.apply(this,[c+f[0]].concat(f));return typeof f[0]==="number"||typeof f[1]==="number"?this:e};function b(l){var m=this,h,k={},g=l?$.fn:$,n=arguments,i=4,f=n[1],j=n[2],p=n[3];if(typeof f!=="string"){i--;f=l=0;j=n[1];p=n[2]}if(l){h=m.eq(0);h.data(l,k=h.data(l)||{})}else{if(f){k=a[f]||(a[f]={})}}k.id&&clearTimeout(k.id);delete k.id;function e(){if(l){h.removeData(l)}else{if(f){delete a[f]}}}function o(){k.id=setTimeout(function(){k.fn()},j)}if(p){k.fn=function(q){if(typeof p==="string"){p=g[p]}p.apply(m,d.call(n,i))===true&&!q?o():e()};o()}else{if(k.fn){j===undefined?e():k.fn(j===false);return true}else{e()}}}})(jQuery);

// Making sure that console.log does not throw errors on Firefox + IE etc.
if (typeof console == "undefined") var console = { log: function() {} };

var DiscoJuice = {};

/*
 * Country codes available here http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
 */
DiscoJuice.Constants = {
	"Countries": {
		'AU': 'Australia',
		'AT': 'Austria',
		'CZ': 'Czech',
		'CN': 'China',
		'CA': 'Canada',
		'DK': 'Denmark',
		'FI': 'Finland',
		'FR': 'France',
		'DE': 'Germany',
		'GR': 'Greece',
		'HR': 'Croatia',
		'IE': 'Ireland',
		'IT': 'Italy',
		'IS': 'Iceland',
		'JP': 'Japan',
		'HU': 'Hungary',
		'LU': 'Luxembourg',
		'NL': 'Netherlands',
		'NO': 'Norway',
		'NZ': 'New Zealand',
		'PL': 'Poland',
		'PT': 'Portugal',
		'SI': 'Slovenia',
		'ES': 'Spain',
		'SE': 'Sweden',
		'CH': 'Switzerland',
		'TR': 'Turkey',
		'US': 'USA',
		'GB': 'UK',
		'XX': 'Experimental'
	},
	"Flags": {
		'AU': 'au.png',
		'AT': 'at.png',
		'CZ': 'cz.png',
		'CA': 'ca.png',
		'CN': 'cn.png',
		'DK': 'dk.png',
		'FI': 'fi.png',
		'FR': 'fr.png',
		'DE': 'de.png',
		'GR': 'gr.png',
		'HR': 'hr.png',
		'IE': 'ie.png',
		'IT': 'it.png',
		'IS': 'is.png',
		'JP': 'jp.png',
		'HU': 'hu.png',
		'LU': 'lu.png',
		'NL': 'nl.png',
		'NZ': 'nz.png',
		'NO': 'no.png',
		'PL': 'pl.png',
		'PT': 'pt.png',
		'SI': 'si.png',
		'ES': 'es.png',
		'SE': 'se.png',
		'CH': 'ch.png',
		'TR': 'tr.png',
		'GB': 'gb.png',
		'US': 'us.png'
	}
};

DiscoJuice.Utils = {
	"log": function(string) {
		console.log(string);
		// opera.postError(string);
	},
	"options": function() {
		var options;
		return {
			"get": function (key, def) {
	//			DiscoJuice.log(options);
	//			DiscoJuice.log('Getting [' + key + '] default [' + def + '] val [' + options[key] + ']');
				if (!options) return def;
				if (!options[key]) return def;
				return options[key];
			},
			"set": function(opts) {
				options = opts;
			},
			"update": function(key, value) {
				options[key] = value;
			}
		}
	}(),

	/* Functions for setting, reading and erasing cookies */
	"createCookie": function(value, type) {
		var type = type || 'EntityID';
		var name = '_DiscoJuice_' + type;
		var days = 1825;
		if (days) {
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			var expires = "; expires="+date.toGMTString();
		}
		else var expires = "";
		document.cookie = name+"="+escape(value)+expires+"; path=/";
	},
	"readCookie": function(type) {
		var type = type || 'EntityID';
		var name = '_DiscoJuice_' + type;
		var days = 1825;
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for(var i=0;i < ca.length;i++) {
			var c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length);
			if (c.indexOf(nameEQ) == 0) return unescape(c.substring(nameEQ.length,c.length));
		}
		return null;
	},
	"eraseCookie": function (type) {
		var type = type || 'EntityID';
		var name = '_DiscoJuice_' + type;
		DiscoJuice.createCookie(name,"",-1);
	},
	/* ------ ------ ------ ------ ------ */

	/*
	 * Performs a search 'term' against an entity.
	 * If no match, return false.
	 * If match return the keyword that matches.
	 */
	"searchMatch": function(item, term) {
		if (item.title.toLowerCase().search(term.toLowerCase()) !== -1) return true;
		if (item.descr && item.descr.toLowerCase().search(term.toLowerCase()) !== -1) return true;
		var key, i, keyword;

		if (item.keywords) {
			for(key in item.keywords) {
				keyword = item.keywords[key];
				for(i = 0; i < keyword.length; i++) {
					if (keyword[i].toLowerCase().search(term.toLowerCase()) !== -1) return keyword[i];
				}
			}
		}
		return false;
	},

	// calculate distance between two locations
	"calculateDistance": function (lat1, lon1, lat2, lon2) {
		var R = 6371; // km
		var dLat = this.toRad(lat2-lat1);
		var dLon = this.toRad(lon2-lon1);
		var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
				Math.cos(this.toRad(lat1)) * Math.cos(this.toRad(lat2)) *
				Math.sin(dLon/2) * Math.sin(dLon/2);
		var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
		var d = R * c;
		return d;
	},

	"toRad": function (deg) {
		return deg * Math.PI/180;
	},

	"waiter": function (completed, waitSeconds) {

		var
		 	my = {},
			parallellActions = [],
			executed = false;

		function execute () {

			if (executed) {
				console.log('Execution cancelled. Already performed.');
				return;
			}

			executed = true;
			completed(my);
		}

		function runAction (act, tooLate) {
			var
				thisAction = {completed: false};

			parallellActions.push(thisAction);
			console.log('Running action ' + parallellActions.length);
			act(function () {
				var i;
				thisAction.completed = true;
				for (i = 0; i < parallellActions.length; i++) {
					if (!parallellActions[i].completed) {
						console.log('Cannot execute because we are waiting for another action to complete.');
						return;
					}
				}
				if (executed) {
					if (my.allowMultiple) {
						console.log('Slow response; but executing anyway!!');
						execute();
					} else if (typeof tooLate === 'function') {
						console.log('All actions completed. Too late for executing...');
						tooLate();
					}
					return;
				}
				console.log('All actions completed. Executing!');
				execute();
			});

		}

		function startTimer() {
			if (parallellActions.length === 0) {
				console.log('Executing because no action is scheduled....');
				if (!executed) execute();
				return;
			}

			setTimeout(function() {
				console.log('Action timeout!');
				if (!executed) execute();
			}, waitSeconds);

		}

		my.allowMultiple = false;

		my.startTimer = startTimer;
		my.runAction = runAction;
		return my;
	}

};

/*
	Plugin for JQuery.
	*/
(function($) {
	$.fn.DiscoJuice = function(options) {
		return this.each(function() {
			DiscoJuice.Utils.options.set(options);

			DiscoJuice.Control.ui = DiscoJuice.UI;
			DiscoJuice.UI.control = DiscoJuice.Control;

			DiscoJuice.UI.enable(this);

		});
	};
})(jQuery);

<|endoftext|>


<commit_before>/*!
 * Copyright (c) 2013 Ben Olson (https://github.com/bseth99/backbone-fiber)
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Dependancies: Backbone, jQuery, Underscore, RequireJS
 *
 */

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD.
        define(['jquery', 'underscore', 'backbone', 'base'], factory);
    } else {
        // Browser globals
        root.Backbone.Fiber = factory(root.$, root._, root.Backbone, Base);
    }
}(this, function ($, _, Backbone, Base) {

   // Replace and enhance
   Backbone.View.extend = Base.extend;
   Backbone.View.mix = Base.mix;

   var Fiber,
       _view_defs = {},
       _view_inst = {},
       _view_loading = {};

   // Store the old jQuery.cleanData
   var oldClean = $.cleanData;

   // Overwrites cleanData which is called by jQuery on manipulation methods
   $.cleanData = function( elems ) {
      for ( var i = 0, elem;
      (elem = elems[i]) !== undefined; i++ ) {
         // Trigger the destroyed event
         $(elem).triggerHandler( 'destroyed' );
      }
      // Call the old jQuery.cleanData
      oldClean(elems);
   };

   Backbone.Fiber = Fiber = {

      /**
      *  Set the base path to find views relative to the RequireJS
      *  basePath.  View module IDs will be relative to this location.
      *  For example, if the basePath is scripts and views are in the
      *  scripts/views folder then a view file named shell.js will be
      *  identified by RequireJS as views/shell but Fiber will index it
      *  as shell.
      */
      viewPath: 'views/',

      /**
      *  Given an element from the DOM, find the closest element (either
      *  it or one of its parents) that has a view instance bound and return
      *  that instance.
      */
      getViewFromEl: function( el ) {
         var $el = $( el ),
             dataCid = $el.attr( 'data-cid' ) || $el.closest( '[data-cid]' ).attr( 'data-cid' );

         if ( dataCid ) return _view_inst[dataCid];
      },

      /**
      *  Lookup a view instance from its cid
      */
      getViewFromCid: function( cid ) {

         return _view_inst[cid];
      },

      /**
      *  Get the DOM element a view instance is bound to based on its
      *  cid
      */
      getElFromCid: function( cid ) {

         if ( _view_inst[cid] )
            return _view_inst[cid].$el;
      },

      /**
      *  Return the promise for a view definition.  Only valid while loading,
      *  otherwise, returns nothing.
      */
      getPromise: function( view ) {

         if ( _view_loading[view] )
            return _view_loading[view];
      }
   }

   /**
   *  Wraps RequireJS and loads view modules with their template files.  Modifies the
   *  prototype with the view module name and the pre-compiled template function.
   */
   function load( target ) {

      var dfd = $.Deferred();

      if ( _view_defs[target] ) {

         dfd.resolve( _view_defs[target] );

      } else {

         _view_loading[target] = dfd;
         require( [Fiber.viewPath + target, 'text!' + Fiber.viewPath + target + '.html'], function( view, template ) {

            view.prototype.instanceOf = target;
            view.prototype.template = _.template( template );
            _view_defs[target] = view;

            delete _view_loading[target];
            dfd.resolve( view );
         });
      }

      return dfd.promise();
   }

   /**
   *  View factory method.  Creates instance, sets up the parent/child
   *  relationship and renders the view.
   */
   function create( view, $el, options ) {

      var inst = new view(_.extend( options, { el: $el[0] } )),
          parent;

      $el.attr( 'data-cid', inst.cid );
      _view_inst[inst.cid] = inst;

      parent = $el.parents( '[data-view]' ).first();
      if ( parent.length > 0 ) {
         parent = parent.attr( 'data-cid' );
         _view_inst[parent].addChild( inst );
         inst.setParent( _view_inst[parent] );
      }

      inst.render();
      return inst;
   }

   /**
   *  Finds the binding on the element, loads the view definition, and
   *  then creates the instance of the view with the passed in options and
   *  attaches it to the DOM element.
   */
   function connect( el, opts ) {

      var options = opts || {},
          $el = (el instanceof $ ? el : $(el)),
          dataView = $el.attr( 'data-view' );

      if ( dataView ) {

         load( dataView ).done( function( view ) {

            create( view, $el, options );

         });
      }

   }

   /* Optional if no top level catch-all, "application" view is defined */
   Fiber.start = function() { connect( document.body ); };

   Backbone.View.mix([{

      /**
      *  load() will attach the compiled template to the
      *  prototype of the loaded view.  No need to do anything
      *  with this.
      */
      template: null,

      /**
      *  The top-most view will be null, all others will have the
      *  cid of the nearest parent view instance.  create() sets this
      *  value when generating the instance.
      */
      parent: null,

      /**
      *  As each child is added, the parent view gets a reference to the
      *  cid.  create() also manages adding this while View.removeChild
      *  removes the reference when a child view removes itself.
      */
      children: null,

      /**
      *  Flag to determine if its the first render pass.  Changes the
      *  behavior of render() and how it responds to empty data sets.
      */
      renderedOnce: false,

      /**
      *  Enables dynamically adding new DOM elements that will be
      *  bound to a child view instance.
      *
      *  target [ String | DOMElement | jQuery Object ]
      *
      *     A string value represents the name of the view to bind to the DOM node.
      *     factory() is used to generate the new element with the data-view attribute
      *     set.  Pass a DOMElement or jQuery object to control how the node is inserted
      *     into the DOM (or override factory() if its the primary way to add nodes)
      *
      *  options [ Object ]
      *
      *     This hash will be passed to the view constructor and can be anything you'd
      *     normally pass to a view when creating an instance.  This can include the model
      *     or collection object.
      *
      *  returns a promise which will be resolved in the scope of the parent view and
      *  pass the new view instance as the argument to the callback function.
      */
      connect: function( target, options ) {
         var $el, wait,
             self = this,
             dfd = $.Deferred();

         if ( typeof( target ) == 'string' )
            $el = this.factory( target );
         else
            $el = (target instanceof $ ? target : $(target));

         connect( $el, options );

         if ( ( wait = Fiber.getPromise( $el.attr('data-view') ) ) )
            wait.done(function( view ) {
               dfd.resolveWith( self, [Fiber.getViewFromEl( $el )] );
            });
         else
            dfd.resolveWith( this, [Fiber.getViewFromEl( $el )] );

         return dfd.promise();
      },

      /**
      *  Helper function to ensure multiple views have finished loading before running
      *  certain logic.  Calls the callback function once eveything has loaded in the
      *  children parameter.
      *
      *  children [ Array ]
      *
      *     Array of view names that should be children of the calling view instance.
      *
      *  callback [ Function ]
      *
      *     Function to call once all the view have loaded.
      */
      waitFor: function( children, callback ) {

         var self = this,
             sync = _.compact( _.map( children, function( v ) { return Fiber.getPromise( v ); } ) );

         $.when.apply( this, sync ).done( function() {
            callback.apply( self, arguments );
         });
      },

      /**
      *  Used by connect() to create DOM nodes.  Override to generate something
      *  different.
      */
      factory: function( vmid ) {
         return $('<div>').attr( 'data-view', vmid ).appendTo( this.$el );
      },

      /**
      *  Redefined the standard initialize view function.  Don't override this
      *  unless you know what you're doing.  Override setup() instead to add your
      *  own custom creation logic.
      */
      initialize: function( options ) {

         this.$el.on( 'destroyed', _.bind( this.remove, this ) );

         this.children = [];
         this.setup();
         this.bindData();

         this.trigger('created');
      },

      /**
      *  Internal function to examine the events hash and
      *  look for *.data keys.  Will bind the function identified in the value
      *  to the whatever is defined by the data() function (as long as it has a
      *  trigger function)..
      */
      bindData: function() {

         var self = this,
             dm = this.data();

         if ( dm.trigger ) {

            _.each( this.events, function( method, event ) {

               var idx;

               if ( (idx = event.indexOf( '.data' ) ) > -1 ) {

                  method = $.isFunction( method ) ? method : self[method];
                  self.listenTo( dm, event.slice( 0, idx ), method );
               }
            });
         }
      },

      /**
      *  Override this as necessary
      */
      setup: $.noop,

      /**
      *  Leave this alone.  Use before/after render callbacks instead or bind to the
      *  rendering/rendered events.  Upon rendering, the function will look for children
      *  with a data-view attribute and start connecting views recursively.
      */
      render: function() {

         var data, isa;

         if ( this.beforeRender() !== false ) {

            this.trigger('rendering');

            if ( this.template && typeof(this.template) == 'function' ) {
               data = this.dataSerialized();
               isa = data && $.isArray( data );

               if ( this.renderedOnce && data || ( !this.renderedOnce && ( ( isa && data.length > 0 ) || !isa ) ) )
               {
                  this.$el.empty().html( this.template( data ) );
                  this.renderedOnce = true;

                  this.$el.find( '[data-view]' ).each( function() {
                     connect( this );
                  });
               }
            }

            this.afterRender();
            this.trigger('rendered');
         }

      },

      /**
      *  Add logic that should happen before rendering.  Return false to cancel rendering
      */
      beforeRender: $.noop,

      /**
      *  Add post rendering logic here.
      */
      afterRender: $.noop,

      /**
      *  Default logic to decide what defines the data object used by the
      *  view.  Override if you need something special.
      */
      data: function() {

         if ( this.model )
            return this.model;
         else if ( this.collection )
            return this.collection;
         else
            return {};
      },

      setData: function( data ) {

         if ( data.model )
            this.model = data.model;
         else if ( data.collection )
            this.collection = data.collection;

      },

      /**
      *  Ensures the data is a object
      */
      dataSerialized: function() {

         var dm = this.data();

         if ( dm.toJSON )
            return dm.toJSON();
         else
            return dm;

      },

      /**
      *  Overwrites the normal view remove function.  Tells the parent
      *  to clean up which will call this again to finish cleaning up.
      */
      remove: function() {

         this.destroy();

         if ( this.parent ) {

           _view_inst[this.parent].removeChild( this );

         } else {

            this.trigger('removed');
            this.stopListening();

            delete _view_inst[this.cid];
         }

         this._superStop();
      },

      /**
      *   Put any custom cleanup logic here
      */
      destroy: $.noop,

      trigger: function( topic, data ) {

         //console.log( this.instanceOf, arguments );
         if ( !this.$el.trigger( topic+'.'+this.instanceOf, { view: this, data: data || {} } ) )
            this._superStop();
      },

      /**
      *  Used internally to set the parent attribute on the view instance.
      */
      setParent: function( view ) {
         this.parent = null;
         if ( view ) this.parent = view.cid;
      },

      /**
      *  Used internally to add a child view instance
      */
      addChild: function( view ) {

         if ( !_.contains( view.cid, this.children ) ) {
            this.children.push( view.cid );
         }
      },

      /**
      *  Used internally to remove a child and ensure its cleanup.
      */
      removeChild: function( view ) {

         var idx = _.indexOf( this.children, view.cid );

         if ( idx > -1 ) {
            this.children.splice( idx, 1 );
            view.setParent( null );
            view.remove();
         }
      },

      /**
      *  Helper to retrive an array of all the child view instances
      */
      allChildren: function() {

         return (
            _.map( this.children, function( cid ) {
               return Fiber.getViewFromCid( cid );
            })
         );
      },

      /**
      *  Helper to return an array of child view instance of a given name
      */
      findChildren: function( type ) {

         return (
            _.compact(
               _.map( this.children, function( cid ) {
                  var view;
                  if ( (view = Fiber.getViewFromCid( this.children[i] )) && view.instanceOf == type )
                     return view;
               })
            )
         );

      },

      /**
      *  Helper to return view instance based on the view name or jQuery element.
      */
      findChild: function( target ) {

         var view = null;

         if ( target instanceof $ ) {

            view = Fiber.getViewFromEl( target );

         } else if ( typeof( target ) == 'string' ) {

            view = Fiber.getViewFromCid( target );
            if ( !view ) {

               for ( var i=0;i<this.children.length;i++ ) {

                  var test;
                  if ( (test = Fiber.getViewFromCid( this.children[i] )) && test.instanceOf == target )
                     view = test;

               }
            }
         }

         return view;
      }

   }]);

   return Fiber;

}));
<commit_msg>setData now calls bindData to update<commit_after>/*!
 * Copyright (c) 2013 Ben Olson (https://github.com/bseth99/backbone-fiber)
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Dependancies: Backbone, jQuery, Underscore, RequireJS
 *
 */

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD.
        define(['jquery', 'underscore', 'backbone', 'base'], factory);
    } else {
        // Browser globals
        root.Backbone.Fiber = factory(root.$, root._, root.Backbone, Base);
    }
}(this, function ($, _, Backbone, Base) {

   // Replace and enhance
   Backbone.View.extend = Base.extend;
   Backbone.View.mix = Base.mix;

   var Fiber,
       _view_defs = {},
       _view_inst = {},
       _view_loading = {};

   // Store the old jQuery.cleanData
   var oldClean = $.cleanData;

   // Overwrites cleanData which is called by jQuery on manipulation methods
   $.cleanData = function( elems ) {
      for ( var i = 0, elem;
      (elem = elems[i]) !== undefined; i++ ) {
         // Trigger the destroyed event
         $(elem).triggerHandler( 'destroyed' );
      }
      // Call the old jQuery.cleanData
      oldClean(elems);
   };

   Backbone.Fiber = Fiber = {

      /**
      *  Set the base path to find views relative to the RequireJS
      *  basePath.  View module IDs will be relative to this location.
      *  For example, if the basePath is scripts and views are in the
      *  scripts/views folder then a view file named shell.js will be
      *  identified by RequireJS as views/shell but Fiber will index it
      *  as shell.
      */
      viewPath: 'views/',

      /**
      *  Given an element from the DOM, find the closest element (either
      *  it or one of its parents) that has a view instance bound and return
      *  that instance.
      */
      getViewFromEl: function( el ) {
         var $el = $( el ),
             dataCid = $el.attr( 'data-cid' ) || $el.closest( '[data-cid]' ).attr( 'data-cid' );

         if ( dataCid ) return _view_inst[dataCid];
      },

      /**
      *  Lookup a view instance from its cid
      */
      getViewFromCid: function( cid ) {

         return _view_inst[cid];
      },

      /**
      *  Get the DOM element a view instance is bound to based on its
      *  cid
      */
      getElFromCid: function( cid ) {

         if ( _view_inst[cid] )
            return _view_inst[cid].$el;
      },

      /**
      *  Return the promise for a view definition.  Only valid while loading,
      *  otherwise, returns nothing.
      */
      getPromise: function( view ) {

         if ( _view_loading[view] )
            return _view_loading[view];
      }
   }

   /**
   *  Wraps RequireJS and loads view modules with their template files.  Modifies the
   *  prototype with the view module name and the pre-compiled template function.
   */
   function load( target ) {

      var dfd = $.Deferred();

      if ( _view_defs[target] ) {

         dfd.resolve( _view_defs[target] );

      } else {

         _view_loading[target] = dfd;
         require( [Fiber.viewPath + target, 'text!' + Fiber.viewPath + target + '.html'], function( view, template ) {

            view.prototype.instanceOf = target;
            view.prototype.template = _.template( template );
            _view_defs[target] = view;

            delete _view_loading[target];
            dfd.resolve( view );
         });
      }

      return dfd.promise();
   }

   /**
   *  View factory method.  Creates instance, sets up the parent/child
   *  relationship and renders the view.
   */
   function create( view, $el, options ) {

      var inst = new view(_.extend( options, { el: $el[0] } )),
          parent;

      $el.attr( 'data-cid', inst.cid );
      _view_inst[inst.cid] = inst;

      parent = $el.parents( '[data-view]' ).first();
      if ( parent.length > 0 ) {
         parent = parent.attr( 'data-cid' );
         _view_inst[parent].addChild( inst );
         inst.setParent( _view_inst[parent] );
      }

      inst.render();
      return inst;
   }

   /**
   *  Finds the binding on the element, loads the view definition, and
   *  then creates the instance of the view with the passed in options and
   *  attaches it to the DOM element.
   */
   function connect( el, opts ) {

      var options = opts || {},
          $el = (el instanceof $ ? el : $(el)),
          dataView = $el.attr( 'data-view' );

      if ( dataView ) {

         load( dataView ).done( function( view ) {

            create( view, $el, options );

         });
      }

   }

   /* Optional if no top level catch-all, "application" view is defined */
   Fiber.start = function() { connect( document.body ); };

   Backbone.View.mix([{

      /**
      *  load() will attach the compiled template to the
      *  prototype of the loaded view.  No need to do anything
      *  with this.
      */
      template: null,

      /**
      *  The top-most view will be null, all others will have the
      *  cid of the nearest parent view instance.  create() sets this
      *  value when generating the instance.
      */
      parent: null,

      /**
      *  As each child is added, the parent view gets a reference to the
      *  cid.  create() also manages adding this while View.removeChild
      *  removes the reference when a child view removes itself.
      */
      children: null,

      /**
      *  Flag to determine if its the first render pass.  Changes the
      *  behavior of render() and how it responds to empty data sets.
      */
      renderedOnce: false,

      /**
      *  Enables dynamically adding new DOM elements that will be
      *  bound to a child view instance.
      *
      *  target [ String | DOMElement | jQuery Object ]
      *
      *     A string value represents the name of the view to bind to the DOM node.
      *     factory() is used to generate the new element with the data-view attribute
      *     set.  Pass a DOMElement or jQuery object to control how the node is inserted
      *     into the DOM (or override factory() if its the primary way to add nodes)
      *
      *  options [ Object ]
      *
      *     This hash will be passed to the view constructor and can be anything you'd
      *     normally pass to a view when creating an instance.  This can include the model
      *     or collection object.
      *
      *  returns a promise which will be resolved in the scope of the parent view and
      *  pass the new view instance as the argument to the callback function.
      */
      connect: function( target, options ) {
         var $el, wait,
             self = this,
             dfd = $.Deferred();

         if ( typeof( target ) == 'string' )
            $el = this.factory( target );
         else
            $el = (target instanceof $ ? target : $(target));

         connect( $el, options );

         if ( ( wait = Fiber.getPromise( $el.attr('data-view') ) ) )
            wait.done(function( view ) {
               dfd.resolveWith( self, [Fiber.getViewFromEl( $el )] );
            });
         else
            dfd.resolveWith( this, [Fiber.getViewFromEl( $el )] );

         return dfd.promise();
      },

      /**
      *  Helper function to ensure multiple views have finished loading before running
      *  certain logic.  Calls the callback function once eveything has loaded in the
      *  children parameter.
      *
      *  children [ Array ]
      *
      *     Array of view names that should be children of the calling view instance.
      *
      *  callback [ Function ]
      *
      *     Function to call once all the view have loaded.
      */
      waitFor: function( children, callback ) {

         var self = this,
             sync = _.compact( _.map( children, function( v ) { return Fiber.getPromise( v ); } ) );

         $.when.apply( this, sync ).done( function() {
            callback.apply( self, arguments );
         });
      },

      /**
      *  Used by connect() to create DOM nodes.  Override to generate something
      *  different.
      */
      factory: function( vmid ) {
         return $('<div>').attr( 'data-view', vmid ).appendTo( this.$el );
      },

      /**
      *  Redefined the standard initialize view function.  Don't override this
      *  unless you know what you're doing.  Override setup() instead to add your
      *  own custom creation logic.
      */
      initialize: function( options ) {

         this.$el.on( 'destroyed', _.bind( this.remove, this ) );

         this.children = [];
         this.setup();
         this.bindData();

         this.trigger('created');
      },

      /**
      *  Internal function to examine the events hash and
      *  look for *.data keys.  Will bind the function identified in the value
      *  to the whatever is defined by the data() function (as long as it has a
      *  trigger function)..
      */
      bindData: function() {

         var self = this,
             dm = this.data();

         if ( dm.trigger ) {

            _.each( this.events, function( method, event ) {

               var idx;

               if ( (idx = event.indexOf( '.data' ) ) > -1 ) {

                  method = $.isFunction( method ) ? method : self[method];
                  self.listenTo( dm, event.slice( 0, idx ), method );
               }
            });
         }
      },

      /**
      *  Override this as necessary
      */
      setup: $.noop,

      /**
      *  Leave this alone.  Use before/after render callbacks instead or bind to the
      *  rendering/rendered events.  Upon rendering, the function will look for children
      *  with a data-view attribute and start connecting views recursively.
      */
      render: function() {

         var data, isa;

         if ( this.beforeRender() !== false ) {

            this.trigger('rendering');

            if ( this.template && typeof(this.template) == 'function' ) {
               data = this.dataSerialized();
               isa = data && $.isArray( data );

               if ( this.renderedOnce && data || ( !this.renderedOnce && ( ( isa && data.length > 0 ) || !isa ) ) )
               {
                  this.$el.empty().html( this.template( data ) );
                  this.renderedOnce = true;

                  this.$el.find( '[data-view]' ).each( function() {
                     connect( this );
                  });
               }
            }

            this.afterRender();
            this.trigger('rendered');
         }

      },

      /**
      *  Add logic that should happen before rendering.  Return false to cancel rendering
      */
      beforeRender: $.noop,

      /**
      *  Add post rendering logic here.
      */
      afterRender: $.noop,

      /**
      *  Default logic to decide what defines the data object used by the
      *  view.  Override if you need something special.
      */
      data: function() {

         if ( this.model )
            return this.model;
         else if ( this.collection )
            return this.collection;
         else
            return {};
      },

      setData: function( data ) {

         if ( data.model )
            this.model = data.model;
         else if ( data.collection )
            this.collection = data.collection;

         this.bindData();

      },

      /**
      *  Ensures the data is a object
      */
      dataSerialized: function() {

         var dm = this.data();

         if ( dm.toJSON )
            return dm.toJSON();
         else
            return dm;

      },

      /**
      *  Overwrites the normal view remove function.  Tells the parent
      *  to clean up which will call this again to finish cleaning up.
      */
      remove: function() {

         this.destroy();

         if ( this.parent ) {

           _view_inst[this.parent].removeChild( this );

         } else {

            this.trigger('removed');
            this.stopListening();

            delete _view_inst[this.cid];
         }

         this._superStop();
      },

      /**
      *   Put any custom cleanup logic here
      */
      destroy: $.noop,

      trigger: function( topic, data ) {

         //console.log( this.instanceOf, arguments );
         if ( !this.$el.trigger( topic+'.'+this.instanceOf, { view: this, data: data || {} } ) )
            this._superStop();
      },

      /**
      *  Used internally to set the parent attribute on the view instance.
      */
      setParent: function( view ) {
         this.parent = null;
         if ( view ) this.parent = view.cid;
      },

      /**
      *  Used internally to add a child view instance
      */
      addChild: function( view ) {

         if ( !_.contains( view.cid, this.children ) ) {
            this.children.push( view.cid );
         }
      },

      /**
      *  Used internally to remove a child and ensure its cleanup.
      */
      removeChild: function( view ) {

         var idx = _.indexOf( this.children, view.cid );

         if ( idx > -1 ) {
            this.children.splice( idx, 1 );
            view.setParent( null );
            view.remove();
         }
      },

      /**
      *  Helper to retrive an array of all the child view instances
      */
      allChildren: function() {

         return (
            _.map( this.children, function( cid ) {
               return Fiber.getViewFromCid( cid );
            })
         );
      },

      /**
      *  Helper to return an array of child view instance of a given name
      */
      findChildren: function( type ) {

         return (
            _.compact(
               _.map( this.children, function( cid ) {
                  var view;
                  if ( (view = Fiber.getViewFromCid( this.children[i] )) && view.instanceOf == type )
                     return view;
               })
            )
         );

      },

      /**
      *  Helper to return view instance based on the view name or jQuery element.
      */
      findChild: function( target ) {

         var view = null;

         if ( target instanceof $ ) {

            view = Fiber.getViewFromEl( target );

         } else if ( typeof( target ) == 'string' ) {

            view = Fiber.getViewFromCid( target );
            if ( !view ) {

               for ( var i=0;i<this.children.length;i++ ) {

                  var test;
                  if ( (test = Fiber.getViewFromCid( this.children[i] )) && test.instanceOf == target )
                     view = test;

               }
            }
         }

         return view;
      }

   }]);

   return Fiber;

}));
<|endoftext|>


<commit_before>/**
 * @fileoverview Soundworks client side dialog module
 * @author Sebastien.Robaszkiewicz@ircam.fr, Norbert.Schnell@ircam.fr
 */
'use strict';

var client = require('./client');
var ClientModule = require('./ClientModule');
var audioContext = require('waves-audio').audioContext;

function base64(format, base64) {
  return `data:${format};base64,${base64}`;
}

class ClientDialog extends ClientModule {
  constructor(options = {}) {
    super(options.name || 'dialog', true, options.color);

    this._mustActivateAudio = !!options.activateAudio;
    this._mustWakeLock = !!options.wakeLock;
    this._text = options.text || "Hello!";

    this._clickHandler = this._clickHandler.bind(this);
  }

  start() {
    super.start();
    this.setCenteredViewContent(this._text);

    // initialize video element for wakeLocking
    this._initWakeLock();
    // install click listener
    this.view.addEventListener('click', () => {
      if (this._mustActivateAudio)
        this._activateAudio();

      if (this._mustWakeLock)
        this._requestWakeLock();

      this.done();
    });
  }

  restart() {
    super.restart();
    this.done();
  }

  _activateAudio() {
    var o = audioContext.createOscillator();
    var g = audioContext.createGain();
    g.gain.value = 0;
    o.connect(g);
    g.connect(audioContext.destination);
    o.start(0);
    o.stop(audioContext.currentTime + 0.000001);
  }

  _clickHandler() {
    if (this._mustActivateAudio)
      this._activateAudio();

    this.view.removeEventListener('click', this._clickHandler);
    this.done();
  }

  // cf. https://github.com/borismus/webvr-boilerplate/blob/8abbc74cfa5976b9ab0c388cb0c51944008c6989/js/webvr-manager.js#L268-L289
  _initWakeLock() {
    this._wakeLockVideo = document.createElement('video');

    this._wakeLockVideo.addEventListener('ended', () => {
      this._wakeLockVideo.play();
    });
  }

  _requestWakeLock() {
    const os = client.platform.os;
    this._releaseWakeClock();

    if (os === 'ios') {
      if (this._wakeLockTimer) return;

      this._wakeLockTimer = setInterval(() => {
        window.location = window.location;
        setTimeout(window.stop, 0);
      }, 30000);
    } else if (os === 'android') {
      if (this._wakeLockVideo.paused === false) return;

      this._wakeLockVideo.src = base64('video/webm', 'GkXfowEAAAAAAAAfQoaBAUL3gQFC8oEEQvOBCEKChHdlYm1Ch4ECQoWBAhhTgGcBAAAAAAACWxFNm3RALE27i1OrhBVJqWZTrIHfTbuMU6uEFlSua1OsggEuTbuMU6uEHFO7a1OsggI+7AEAAAAAAACkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVSalmAQAAAAAAAEMq17GDD0JATYCMTGF2ZjU2LjQuMTAxV0GMTGF2ZjU2LjQuMTAxc6SQ20Yv/Elws73A/+KfEjM11ESJiEBkwAAAAAAAFlSuawEAAAAAAABHrgEAAAAAAAA+14EBc8WBAZyBACK1nIN1bmSGhVZfVlA4g4EBI+ODhAT3kNXgAQAAAAAAABKwgRC6gRBTwIEBVLCBEFS6gRAfQ7Z1AQAAAAAAALHngQCgAQAAAAAAAFyho4EAAIAQAgCdASoQABAAAEcIhYWIhYSIAgIADA1gAP7/q1CAdaEBAAAAAAAALaYBAAAAAAAAJO6BAaWfEAIAnQEqEAAQAABHCIWFiIWEiAICAAwNYAD+/7r/QKABAAAAAAAAQKGVgQBTALEBAAEQEAAYABhYL/QACAAAdaEBAAAAAAAAH6YBAAAAAAAAFu6BAaWRsQEAARAQABgAGFgv9AAIAAAcU7trAQAAAAAAABG7j7OBALeK94EB8YIBgfCBAw==');
      this._wakeLockVideo.play();
    }
  }

  _releaseWakeClock() {
    const os = client.platform.os;

    if (os === 'ios') {
      if (this._wakeLockTimer) {
        clearInterval(this._wakeLockTimer);
        this._wakeLockTimer = null;
      }
    } else if (os === 'android') {
      this._wakeLockVideo.pause();
      this._wakeLockVideo.src = '';
    }
  }
}

module.exports = ClientDialog;<commit_msg>Added "touchstart" event handler to ClientDialog to be more responsive on mobile devices<commit_after>/**
 * @fileoverview Soundworks client side dialog module
 * @author Sebastien.Robaszkiewicz@ircam.fr, Norbert.Schnell@ircam.fr
 */
'use strict';

var client = require('./client');
var ClientModule = require('./ClientModule');
var audioContext = require('waves-audio').audioContext;

function base64(format, base64) {
  return `data:${format};base64,${base64}`;
}

class ClientDialog extends ClientModule {
  constructor(options = {}) {
    super(options.name || 'dialog', true, options.color);

    this._mustActivateAudio = !!options.activateAudio;
    this._mustWakeLock = !!options.wakeLock;
    this._text = options.text || "Hello!";

    this._clickHandler = this._clickHandler.bind(this);
  }

  start() {
    super.start();
    this.setCenteredViewContent(this._text);

    // initialize video element for wakeLocking
    this._initWakeLock();
    // install click listener
    if (client.platform.isMobile)
      this.view.addEventListener('touchstart', this._clickHandler);
    else
      this.view.addEventListener('click', this._clickHandler);
  }

  restart() {
    super.restart();
    this.done();
  }

  _activateAudio() {
    var o = audioContext.createOscillator();
    var g = audioContext.createGain();
    g.gain.value = 0;
    o.connect(g);
    g.connect(audioContext.destination);
    o.start(0);
    o.stop(audioContext.currentTime + 0.000001);
  }

  _clickHandler() {
    if (this._mustActivateAudio)
      this._activateAudio();

    if (this._mustWakeLock)
      this._requestWakeLock();

    this.view.removeEventListener('click', this._clickHandler);
    this.done();
  }

  // cf. https://github.com/borismus/webvr-boilerplate/blob/8abbc74cfa5976b9ab0c388cb0c51944008c6989/js/webvr-manager.js#L268-L289
  _initWakeLock() {
    this._wakeLockVideo = document.createElement('video');

    this._wakeLockVideo.addEventListener('ended', () => {
      this._wakeLockVideo.play();
    });
  }

  _requestWakeLock() {
    const os = client.platform.os;
    this._releaseWakeClock();

    if (os === 'ios') {
      if (this._wakeLockTimer) return;

      this._wakeLockTimer = setInterval(() => {
        window.location = window.location;
        setTimeout(window.stop, 0);
      }, 30000);
    } else if (os === 'android') {
      if (this._wakeLockVideo.paused === false) return;

      this._wakeLockVideo.src = base64('video/webm', 'GkXfowEAAAAAAAAfQoaBAUL3gQFC8oEEQvOBCEKChHdlYm1Ch4ECQoWBAhhTgGcBAAAAAAACWxFNm3RALE27i1OrhBVJqWZTrIHfTbuMU6uEFlSua1OsggEuTbuMU6uEHFO7a1OsggI+7AEAAAAAAACkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVSalmAQAAAAAAAEMq17GDD0JATYCMTGF2ZjU2LjQuMTAxV0GMTGF2ZjU2LjQuMTAxc6SQ20Yv/Elws73A/+KfEjM11ESJiEBkwAAAAAAAFlSuawEAAAAAAABHrgEAAAAAAAA+14EBc8WBAZyBACK1nIN1bmSGhVZfVlA4g4EBI+ODhAT3kNXgAQAAAAAAABKwgRC6gRBTwIEBVLCBEFS6gRAfQ7Z1AQAAAAAAALHngQCgAQAAAAAAAFyho4EAAIAQAgCdASoQABAAAEcIhYWIhYSIAgIADA1gAP7/q1CAdaEBAAAAAAAALaYBAAAAAAAAJO6BAaWfEAIAnQEqEAAQAABHCIWFiIWEiAICAAwNYAD+/7r/QKABAAAAAAAAQKGVgQBTALEBAAEQEAAYABhYL/QACAAAdaEBAAAAAAAAH6YBAAAAAAAAFu6BAaWRsQEAARAQABgAGFgv9AAIAAAcU7trAQAAAAAAABG7j7OBALeK94EB8YIBgfCBAw==');
      this._wakeLockVideo.play();
    }
  }

  _releaseWakeClock() {
    const os = client.platform.os;

    if (os === 'ios') {
      if (this._wakeLockTimer) {
        clearInterval(this._wakeLockTimer);
        this._wakeLockTimer = null;
      }
    } else if (os === 'android') {
      this._wakeLockVideo.pause();
      this._wakeLockVideo.src = '';
    }
  }
}

module.exports = ClientDialog;<|endoftext|>


<commit_before>// Include language extensions FIRST
// require('../functions.js')

var m              = require('mithril');
var App            = require('./app.js');
var Auth           = require('../lib/auth.js');
var Outcomes       = require('./views/outcomes/outcomes.js');
var StudentProfile = require('./views/studentProfile/studentProfile.js');
var Outcomes       = require('./views/outcomes/outcomes.js');
var Progress       = require('./views/progress/progress.js');
var Splash         = require('./views/splash/splash.js');
var Fuzzy          = require('../../AutocompleteInput.js');

// TODO: Make sure pages can only be accessed when user is authorized

// var goHome = m.route.papp('/')

var checkAuth = function(authorization, componentsArr) {
  //TODO: Check role of user and redirect correctly
  if(authorization()){
    console.log('authorized')
    return App.layout(componentsArr);
  }else{
    console.log('redirected')
    return  m.component(Splash);
  }
};

var routes = {

  '/': {
    controller: function () {
      var ctrl = this;
      ctrl.user = Auth.currentUser()
    },
    view: function (ctrl) {
      return  m.component(Splash)
    }
  },

  '/profile': {
    controller: function () {
      var ctrl = this;
      ctrl.user = Auth.currentUser();
    },
    view: function (ctrl) {
      console.log( 'js', ctrl)
      return checkAuth(ctrl.user, m.component(StudentProfile, ctrl))
    }
  },

  '/profile/:id': {
    controller: function () {
      var ctrl = this;
      ctrl.user = Auth.currentUser();
      ctrl.thisUserId = m.route.param('id')
    },
    view: function (ctrl) {

      return checkAuth(ctrl.user, m.component(StudentProfile, ctrl))
    }
  },

  '/fuzzy': {
    controller: function () {
      var ctrl = this;
      ctrl.user = Auth.currentUser();

    },
    view: function (ctrl) {
      return checkAuth(ctrl.user, m.component(Fuzzy))
    }
  },

  '/fuzzy': {
    controller: function () {
      var ctrl = this;
      ctrl.user = Auth.currentUser();

    },
    view: function (ctrl) {
      return checkAuth(ctrl.user, m.component(Fuzzy))
    }
  },

  '/outcomes': {
    controller: function () {
      var ctrl = this;
      ctrl.user = Auth.currentUser();
    },
    view: function (ctrl) {
      return checkAuth(ctrl.user, m.component(Outcomes))
    }
  },

  '/signout': {
    controller: function () {
      Auth.signOut();
    },
    view: function () {
      return m.component(Splash)
    }
  }
};

// m.route.mode = 'pathname';
m.route(document.getElementById('app'), '/', routes);
<commit_msg>took out require FE<commit_after>// Include language extensions FIRST
// require('../functions.js')

var m              = require('mithril');
var App            = require('./app.js');
var Auth           = require('../lib/auth.js');
var Outcomes       = require('./views/outcomes/outcomes.js');
var StudentProfile = require('./views/studentProfile/studentProfile.js');
var Outcomes       = require('./views/outcomes/outcomes.js');
var Progress       = require('./views/progress/progress.js');
var Splash         = require('./views/splash/splash.js');

// TODO: Make sure pages can only be accessed when user is authorized

// var goHome = m.route.papp('/')

var checkAuth = function(authorization, componentsArr) {
  //TODO: Check role of user and redirect correctly
  if(authorization()){
    console.log('authorized')
    return App.layout(componentsArr);
  }else{
    console.log('redirected')
    return  m.component(Splash);
  }
};

var routes = {

  '/': {
    controller: function () {
      var ctrl = this;
      ctrl.user = Auth.currentUser()
    },
    view: function (ctrl) {
      return  m.component(Splash)
    }
  },

  '/profile': {
    controller: function () {
      var ctrl = this;
      ctrl.user = Auth.currentUser();
    },
    view: function (ctrl) {
      console.log( 'js', ctrl)
      return checkAuth(ctrl.user, m.component(StudentProfile, ctrl))
    }
  },

  '/profile/:id': {
    controller: function () {
      var ctrl = this;
      ctrl.user = Auth.currentUser();
      ctrl.thisUserId = m.route.param('id')
    },
    view: function (ctrl) {

      return checkAuth(ctrl.user, m.component(StudentProfile, ctrl))
    }
  },

  '/fuzzy': {
    controller: function () {
      var ctrl = this;
      ctrl.user = Auth.currentUser();

    },
    view: function (ctrl) {
      return checkAuth(ctrl.user, m.component(Fuzzy))
    }
  },

  '/fuzzy': {
    controller: function () {
      var ctrl = this;
      ctrl.user = Auth.currentUser();

    },
    view: function (ctrl) {
      return checkAuth(ctrl.user, m.component(Fuzzy))
    }
  },

  '/outcomes': {
    controller: function () {
      var ctrl = this;
      ctrl.user = Auth.currentUser();
    },
    view: function (ctrl) {
      return checkAuth(ctrl.user, m.component(Outcomes))
    }
  },

  '/signout': {
    controller: function () {
      Auth.signOut();
    },
    view: function () {
      return m.component(Splash)
    }
  }
};

// m.route.mode = 'pathname';
m.route(document.getElementById('app'), '/', routes);
<|endoftext|>