<commit_before>/*--------------------------------------------
* @ SproutSlide-jQuery-Plugin
* @ version 2.1.0
--------------------------------------------*/

$.fn.hasAttr = function(name) {
   return this.attr(name) !== undefined;
};

(function($){
$.fn.sproutSlide = function(options) {
// jQuery.fn.extend({
	// sproutSlide: function (options) {
		var settings = $.extend({
			animateStyle: "slide",
			width: "auto",
			slideNum: 4,
			duration:700,
			autovalue:true,
			interval:3000,
			enableDot:true,
			enableArrow:true,
			enablePageNo:false,
			enableLoop:true,
			hoverShowArrow:false,
			clickToNext:false,
			onInit:false,
			beforeAnimate:false,
			afterAnimate:false
		}, options);
		// if (options){$.extend(config, options);}

		return this.each(function(){
			var slider = $(this);
			var mainContent = $(this).find('.sprout-slide');
			var animateLoop;
			var animateStyle = settings.animateStyle;
			var duration = settings.duration;
			var autoplay = settings.autovalue;
			var autoInterval = settings.interval;
			var enableDot = settings.enableDot;
			var enableArrow = settings.enableArrow;
			var enablePageNo = settings.enablePageNo;
			var enableLoop = settings.enableLoop;
			var hoverShowArrow = settings.hoverShowArrow;
			slider.addClass('animate-'+animateStyle);

			var width = settings.width;
			if(width == 'auto'){
				width = slider.parent().width();
			} else {
				width = parseInt(width)
			}
			slider.css('width', width);
			slider.find('.sprout-slide-wrapper').css('width', width);

			if (animateStyle == 'slide'){
				var slideNum = settings.slideNum;
				var itemNum = slider.find('.sprout-slide > li').length;
				var pageNum = Math.ceil(itemNum/slideNum);
				var lastItemNum = itemNum%slideNum;
				var currentDot = 0;
				var copyFront = false;
				var copyEnd = false;
				var sliderFullWidth = width* pageNum;

				// //先補上空白的 li for 除不盡
				if (lastItemNum == 0){
					var missli = 0;
				} else {
					var missli = slideNum - lastItemNum;
					for ( k = 1 ; k <= missli ; k++ ){
						slider.find('.sprout-slide > li:last').after('

');
					}
				}

				//Initial Layout
				mainContent.css('width', sliderFullWidth);
				slider.find('.sprout-slide > li').css('width', width/slideNum);
			} else if (animateStyle == 'fade'){
				var currentDot = 0;
				var nextPage;
				var sliderH = 0;
				var pageNum = slider.find('.sprout-slide > li').length;

				slider.hide();
				slider.find('.sprout-slide li').css('display','none');
				slider.find('.sprout-slide li').eq(0).css('display','block');

				slider.delay(0).fadeIn(100,function(){
					sliderH = slider.find('.sprout-slide li').eq(0).height();
					mainContent.height(sliderH);
				});
			}

			//清空 舊的 page li
			//解決：如果有重新叫同一個 sider 時出現的 兩倍 li 問題
			slider.find('.sprout-dots').html('');

			//Create Page li
			if (pageNum > 1){
				// SET page attr in li
				// 可能會有需要重複呼叫 slider 針對同一個 element,
				// 所以需要確認是否需要重新編列 Attr --> page, 先算出之前有幾頁。
				if (animateStyle == 'slide'){
					var oldpage = 0;
					$(slider.find('.sprout-slide > li')).each(function(){
						if($(this).hasAttr('page')){
							oldpage++;
						}
					});

					if( oldpage == pageNum) {
						//如果頁數一樣的話就不重新編列
					} else {
						//第一次建立這個 slider，或是頁數不一樣。
						slider.find('.sprout-slide > li').removeAttr('page');
						for( i=1 ; i <= pageNum ; i++ ){
							slider.find('.sprout-slide > li').eq((i-1)*slideNum).attr('page',(i-1));
						};
					}

					//解決：如果有重新叫同一個 sider 時出現的問題，一開始要把 ul margin-left 位置 歸0;
					mainContent.css('margin-left','0px');
				}

				//Fade In Slider
				slider.delay(2000).fadeIn(500);

				//Create Dots;
				for( i=1 ; i <= pageNum ; i++ ){
					if(enablePageNo){
						slider.find('.sprout-dots').addClass('hasNumber');
						slider.find('.sprout-dots').append('
'+i+'
');
					} else {
						slider.find('.sprout-dots').append('

');
					}
				};
				slider.find('.sprout-dots div').eq(0).addClass('active');	//Active First dots

				if(!enableLoop){
					checkArrowDisplay();
				}

				if(hoverShowArrow){
					if(enableDot){
						slider.find('.sprout-dots').show();
					}
					if(enableArrow){
						slider.hover(function(){
							slider.find('.sprout-arrow').fadeIn('fast');
						},function(){
							slider.find('.sprout-arrow').fadeOut('fast');
						});
					}
				} else {
					if(enableDot){
						slider.find('.sprout-dots').show();
					}
					if(enableArrow){
						slider.find('.sprout-arrow').show();
					}
				}

				// true --> false || true --> true 都先清掉最後一個 timer;
				// 解決 如果第一次呼叫是 autoplay 然後再次呼叫成為不 autoplay 的錯誤;
				if(slider.attr('slide-loop-id') != null){
					clearInterval(parseInt(slider.attr('slide-loop-id')));
				}

				// //Autoplay Slider
				if (autoplay) {
					restartInterval();
				};
			}

			//unbind 舊的 function, 解決：如果有重新叫同一個 sider 時出現的 duplicated function
			if(settings.clickToNext){
				mainContent.unbind("click").bind("click",nextClick);
				mainContent.addClass('hasCursor');
			}
			slider.find('.sprout-next').unbind("click").bind("click",nextClick);
			slider.find('.sprout-prev').unbind("click").bind("click",prevClick);
			slider.find('.sprout-dots div').unbind("click").bind("click",dotsClick);

			//mobile touch slide
			slider.swipe({
				swipe:function(event, direction, distance, duration, fingerCount) {
					//alert("You swiped " + direction);
					if (direction == 'left'){
						animateSlide('right');
					} else if (direction == 'right'){
						animateSlide('left');
					}
				},
				excludedElements:[],
				threshold:75  	//Default is 75px, set to 0 for demo so any distance triggers swipe
			});

			if($.isFunction( settings.onInit )){
				settings.onInit.call(this,slider,currentDot,pageNum);
			}

			function checkArrowDisplay(){
				if(currentDot == 0){
					slider.find('.sprout-prev').hide();
				} else{
					slider.find('.sprout-prev').show();
				}
				if(currentDot == pageNum-1){
					slider.find('.sprout-next').hide();
				} else{
					slider.find('.sprout-next').show();
				}
			}

			function nextClick(){
				//console.debug('right');
				animateSlide('right');
			}
			function prevClick(){
				//console.debug('left');
				animateSlide('left');
			}
			function dotsClick(){
				//console.debug('dots');
				if ( $(this).index() == currentDot){
					//console.debug('no move');
				} else {
					animateSlide($(this).index());
				}
			}

			function restartInterval(){
				//console.debug('last-loop'+animateLoop);
				//clearInterval(animateLoop);
				animateLoop = setInterval(function(){animateSlide('right');},autoInterval);
				slider.attr('slide-loop-id',animateLoop);
				//console.debug('new-loop'+animateLoop);
			}

			function animateSlide(where){
				//console.debug('last-loop'+animateLoop);
				clearInterval(animateLoop);
				slider.find('.sprout-next').unbind("click",nextClick);
				slider.find('.sprout-prev').unbind("click",prevClick);
				slider.find('.sprout-dots div').unbind("click",dotsClick);

				if (animateStyle == 'slide'){
					//add animateTimer function to end of animation queue
					if (autoplay) {
						restartInterval();
					};

					//移除所有 active;
					slider.find('.sprout-dots div').removeClass('active');

					/* using a if statement and the where variable check
					we will check where the user wants to slide (left or right)*/
					if(where == 'left'){
						//...calculating the new left indent of the unordered list (ul) for left sliding
						var left_indent = parseInt(mainContent.css('margin-left')) + width;
						currentDot = currentDot-1;
						if (currentDot < 0){
							currentDot = currentDot+pageNum;
						}
					} else if (where == 'right'){
						//...calculating the new left indent of the unordered list (ul) for right sliding
						var left_indent = parseInt(mainContent.css('margin-left')) - width;
						currentDot = currentDot+1;
						if (currentDot >= pageNum){
							currentDot = 0;
						}
					} else {
						//console.log('currentDot'+currentDot);
						//console.log('where'+where);
						var old_indent = parseInt(slider.find('.sprout-slide li[page="'+currentDot+'"]').offset().left);
						var new_indent = parseInt(slider.find('.sprout-slide li[page="'+where+'"]').offset().left);
						var left_indent = parseInt(mainContent.css('margin-left')) - (new_indent - old_indent);

						//console.log('old_indent'+old_indent);
						currentDot = where;
					}

					if(left_indent > 0){
						//alert('左邊沒了');
						copyFront = true;
						for (j = 0 ; j < slideNum*(pageNum-1) ; j++ ){
							slider.find('.sprout-slide > li:first').before(slider.find('.sprout-slide > li:last'));
						}
						mainContent.css('margin-left',(pageNum-1)*(-1)*width);
						var left_indent = parseInt(mainContent.css('margin-left')) + width;
					} else if(left_indent <= sliderFullWidth*(-1)){
						//alert('右邊沒了');
						copyEnd = true;
						for (j = 0 ; j < slideNum*(pageNum-1) ; j++ ){
							slider.find('.sprout-slide > li:last').after(slider.find('.sprout-slide > li:first'));
						}
						mainContent.css('margin-left','0px');
						var left_indent = parseInt(mainContent.css('margin-left')) - width;
					}

					checkArrowDisplay();

					if($.isFunction( settings.beforeAnimate )){
						settings.beforeAnimate.call(this,slider,currentDot,pageNum);
					}

					//make the sliding effect using jQuery's animate function... '
					slider.find('.sprout-slide:not(:animated)').animate({'margin-left' : left_indent},duration,function(){

						//...and then just get back the default left indent
						slider.find('.sprout-dots div:eq('+currentDot+')').addClass('active');

						if(copyFront){
							//恢復原狀
							//alert('恢復原狀copyFront');
							for (j = 0 ; j < slideNum ; j++ ){
								slider.find('.sprout-slide > li:first').before(slider.find('.sprout-slide > li:last'));
							}
							mainContent.css('margin-left',(pageNum-1)*(-1)*width);
							copyFront = false;
						} else if(copyEnd){
							//恢復原狀
							//alert('恢復原狀copyEnd');
							for (j = 0 ; j < slideNum ; j++ ){
								slider.find('.sprout-slide > li:last').after(slider.find('.sprout-slide > li:first'));
							}
							mainContent.css('margin-left','0px');
							copyEnd = false;
						}

						if($.isFunction( settings.afterAnimate )){
							settings.afterAnimate.call(this,slider,currentDot,pageNum);
						}

						slider.find('.sprout-next').bind("click",nextClick);
						slider.find('.sprout-prev').bind("click",prevClick);
						slider.find('.sprout-dots div').bind("click",dotsClick);
					});
				} else if (animateStyle == 'fade'){
					//Get Next Page;
					if(where == 'left'){
						nextPage = currentDot-1;
					} else if (where == 'right'){
						nextPage = currentDot+1;
					} else {
						nextPage = where;
					}

					if(nextPage < 0){
						nextPage = pageNum-1;
					} else if(nextPage >= pageNum){
						nextPage = 0;
					}

					if($.isFunction( settings.beforeAnimate )){
						settings.beforeAnimate.call(this,slider,currentDot,pageNum);
					}

					//取得現在 active 的點, 並且移除所有 active;
					slider.find('.sprout-dots div').removeClass('active');
					slider.find('.sprout-dots div:eq('+nextPage+')').addClass('active');

					sliderH = slider.find('.sprout-slide li').eq(nextPage).height();
					mainContent.animate({'height':sliderH},500);

					slider.find('.sprout-slide li').eq(currentDot).fadeOut(300).end().eq(nextPage).hide().fadeIn(duration, function(){
						currentDot = nextPage;
						checkArrowDisplay();

						slider.find('.sprout-next').bind("click",nextClick);
						slider.find('.sprout-prev').bind("click",prevClick);
						slider.find('.sprout-dots div').bind("click",dotsClick);

						if($.isFunction( settings.afterAnimate )){
							settings.afterAnimate.call(this,slider,currentDot,pageNum);
						}

						//add animateTimer function to end of animation queue
						if (autoplay) {
							restartInterval();
						};
					});
				}
			}
		});
	}
}(jQuery));
// });<commit_msg>modify comment in js<commit_after>/*--------------------------------------------
* @ SproutSlide-jQuery-Plugin
* @ version 2.1.0
This is git testing
--------------------------------------------*/

$.fn.hasAttr = function(name) {
   return this.attr(name) !== undefined;
};

(function($){
$.fn.sproutSlide = function(options) {
// jQuery.fn.extend({
	// sproutSlide: function (options) {
		var settings = $.extend({
			animateStyle: "slide",
			width: "auto",
			slideNum: 4,
			duration:700,
			autovalue:true,
			interval:3000,
			enableDot:true,
			enableArrow:true,
			enablePageNo:false,
			enableLoop:true,
			hoverShowArrow:false,
			clickToNext:false,
			onInit:false,
			beforeAnimate:false,
			afterAnimate:false
		}, options);
		// if (options){$.extend(config, options);}

		return this.each(function(){
			var slider = $(this);
			var mainContent = $(this).find('.sprout-slide');
			var animateLoop;
			var animateStyle = settings.animateStyle;
			var duration = settings.duration;
			var autoplay = settings.autovalue;
			var autoInterval = settings.interval;
			var enableDot = settings.enableDot;
			var enableArrow = settings.enableArrow;
			var enablePageNo = settings.enablePageNo;
			var enableLoop = settings.enableLoop;
			var hoverShowArrow = settings.hoverShowArrow;
			slider.addClass('animate-'+animateStyle);

			var width = settings.width;
			if(width == 'auto'){
				width = slider.parent().width();
			} else {
				width = parseInt(width)
			}
			slider.css('width', width);
			slider.find('.sprout-slide-wrapper').css('width', width);

			if (animateStyle == 'slide'){
				var slideNum = settings.slideNum;
				var itemNum = slider.find('.sprout-slide > li').length;
				var pageNum = Math.ceil(itemNum/slideNum);
				var lastItemNum = itemNum%slideNum;
				var currentDot = 0;
				var copyFront = false;
				var copyEnd = false;
				var sliderFullWidth = width* pageNum;

				// //先補上空白的 li for 除不盡
				if (lastItemNum == 0){
					var missli = 0;
				} else {
					var missli = slideNum - lastItemNum;
					for ( k = 1 ; k <= missli ; k++ ){
						slider.find('.sprout-slide > li:last').after('

');
					}
				}

				//Initial Layout
				mainContent.css('width', sliderFullWidth);
				slider.find('.sprout-slide > li').css('width', width/slideNum);
			} else if (animateStyle == 'fade'){
				var currentDot = 0;
				var nextPage;
				var sliderH = 0;
				var pageNum = slider.find('.sprout-slide > li').length;

				slider.hide();
				slider.find('.sprout-slide li').css('display','none');
				slider.find('.sprout-slide li').eq(0).css('display','block');

				slider.delay(0).fadeIn(100,function(){
					sliderH = slider.find('.sprout-slide li').eq(0).height();
					mainContent.height(sliderH);
				});
			}

			//清空 舊的 page li
			//解決：如果有重新叫同一個 sider 時出現的 兩倍 li 問題
			slider.find('.sprout-dots').html('');

			//Create Page li
			if (pageNum > 1){
				// SET page attr in li
				// 可能會有需要重複呼叫 slider 針對同一個 element,
				// 所以需要確認是否需要重新編列 Attr --> page, 先算出之前有幾頁。
				if (animateStyle == 'slide'){
					var oldpage = 0;
					$(slider.find('.sprout-slide > li')).each(function(){
						if($(this).hasAttr('page')){
							oldpage++;
						}
					});

					if( oldpage == pageNum) {
						//如果頁數一樣的話就不重新編列
					} else {
						//第一次建立這個 slider，或是頁數不一樣。
						slider.find('.sprout-slide > li').removeAttr('page');
						for( i=1 ; i <= pageNum ; i++ ){
							slider.find('.sprout-slide > li').eq((i-1)*slideNum).attr('page',(i-1));
						};
					}

					//解決：如果有重新叫同一個 sider 時出現的問題，一開始要把 ul margin-left 位置 歸0;
					mainContent.css('margin-left','0px');
				}

				//Fade In Slider
				slider.delay(2000).fadeIn(500);

				//Create Dots;
				for( i=1 ; i <= pageNum ; i++ ){
					if(enablePageNo){
						slider.find('.sprout-dots').addClass('hasNumber');
						slider.find('.sprout-dots').append('
'+i+'
');
					} else {
						slider.find('.sprout-dots').append('

');
					}
				};
				slider.find('.sprout-dots div').eq(0).addClass('active');	//Active First dots

				if(!enableLoop){
					checkArrowDisplay();
				}

				if(hoverShowArrow){
					if(enableDot){
						slider.find('.sprout-dots').show();
					}
					if(enableArrow){
						slider.hover(function(){
							slider.find('.sprout-arrow').fadeIn('fast');
						},function(){
							slider.find('.sprout-arrow').fadeOut('fast');
						});
					}
				} else {
					if(enableDot){
						slider.find('.sprout-dots').show();
					}
					if(enableArrow){
						slider.find('.sprout-arrow').show();
					}
				}

				// true --> false || true --> true 都先清掉最後一個 timer;
				// 解決 如果第一次呼叫是 autoplay 然後再次呼叫成為不 autoplay 的錯誤;
				if(slider.attr('slide-loop-id') != null){
					clearInterval(parseInt(slider.attr('slide-loop-id')));
				}

				// //Autoplay Slider
				if (autoplay) {
					restartInterval();
				};
			}

			//unbind 舊的 function, 解決：如果有重新叫同一個 sider 時出現的 duplicated function
			if(settings.clickToNext){
				mainContent.unbind("click").bind("click",nextClick);
				mainContent.addClass('hasCursor');
			}
			slider.find('.sprout-next').unbind("click").bind("click",nextClick);
			slider.find('.sprout-prev').unbind("click").bind("click",prevClick);
			slider.find('.sprout-dots div').unbind("click").bind("click",dotsClick);

			//mobile touch slide
			slider.swipe({
				swipe:function(event, direction, distance, duration, fingerCount) {
					//alert("You swiped " + direction);
					if (direction == 'left'){
						animateSlide('right');
					} else if (direction == 'right'){
						animateSlide('left');
					}
				},
				excludedElements:[],
				threshold:75  	//Default is 75px, set to 0 for demo so any distance triggers swipe
			});

			if($.isFunction( settings.onInit )){
				settings.onInit.call(this,slider,currentDot,pageNum);
			}

			function checkArrowDisplay(){
				if(currentDot == 0){
					slider.find('.sprout-prev').hide();
				} else{
					slider.find('.sprout-prev').show();
				}
				if(currentDot == pageNum-1){
					slider.find('.sprout-next').hide();
				} else{
					slider.find('.sprout-next').show();
				}
			}

			function nextClick(){
				//console.debug('right');
				animateSlide('right');
			}
			function prevClick(){
				//console.debug('left');
				animateSlide('left');
			}
			function dotsClick(){
				//console.debug('dots');
				if ( $(this).index() == currentDot){
					//console.debug('no move');
				} else {
					animateSlide($(this).index());
				}
			}

			function restartInterval(){
				//console.debug('last-loop'+animateLoop);
				//clearInterval(animateLoop);
				animateLoop = setInterval(function(){animateSlide('right');},autoInterval);
				slider.attr('slide-loop-id',animateLoop);
				//console.debug('new-loop'+animateLoop);
			}

			function animateSlide(where){
				//console.debug('last-loop'+animateLoop);
				clearInterval(animateLoop);
				slider.find('.sprout-next').unbind("click",nextClick);
				slider.find('.sprout-prev').unbind("click",prevClick);
				slider.find('.sprout-dots div').unbind("click",dotsClick);

				if (animateStyle == 'slide'){
					//add animateTimer function to end of animation queue
					if (autoplay) {
						restartInterval();
					};

					//移除所有 active;
					slider.find('.sprout-dots div').removeClass('active');

					/* using a if statement and the where variable check
					we will check where the user wants to slide (left or right)*/
					if(where == 'left'){
						//...calculating the new left indent of the unordered list (ul) for left sliding
						var left_indent = parseInt(mainContent.css('margin-left')) + width;
						currentDot = currentDot-1;
						if (currentDot < 0){
							currentDot = currentDot+pageNum;
						}
					} else if (where == 'right'){
						//...calculating the new left indent of the unordered list (ul) for right sliding
						var left_indent = parseInt(mainContent.css('margin-left')) - width;
						currentDot = currentDot+1;
						if (currentDot >= pageNum){
							currentDot = 0;
						}
					} else {
						//console.log('currentDot'+currentDot);
						//console.log('where'+where);
						var old_indent = parseInt(slider.find('.sprout-slide li[page="'+currentDot+'"]').offset().left);
						var new_indent = parseInt(slider.find('.sprout-slide li[page="'+where+'"]').offset().left);
						var left_indent = parseInt(mainContent.css('margin-left')) - (new_indent - old_indent);

						//console.log('old_indent'+old_indent);
						currentDot = where;
					}

					if(left_indent > 0){
						//alert('左邊沒了');
						copyFront = true;
						for (j = 0 ; j < slideNum*(pageNum-1) ; j++ ){
							slider.find('.sprout-slide > li:first').before(slider.find('.sprout-slide > li:last'));
						}
						mainContent.css('margin-left',(pageNum-1)*(-1)*width);
						var left_indent = parseInt(mainContent.css('margin-left')) + width;
					} else if(left_indent <= sliderFullWidth*(-1)){
						//alert('右邊沒了');
						copyEnd = true;
						for (j = 0 ; j < slideNum*(pageNum-1) ; j++ ){
							slider.find('.sprout-slide > li:last').after(slider.find('.sprout-slide > li:first'));
						}
						mainContent.css('margin-left','0px');
						var left_indent = parseInt(mainContent.css('margin-left')) - width;
					}

					checkArrowDisplay();

					if($.isFunction( settings.beforeAnimate )){
						settings.beforeAnimate.call(this,slider,currentDot,pageNum);
					}

					//make the sliding effect using jQuery's animate function... '
					slider.find('.sprout-slide:not(:animated)').animate({'margin-left' : left_indent},duration,function(){

						//...and then just get back the default left indent
						slider.find('.sprout-dots div:eq('+currentDot+')').addClass('active');

						if(copyFront){
							//恢復原狀
							//alert('恢復原狀copyFront');
							for (j = 0 ; j < slideNum ; j++ ){
								slider.find('.sprout-slide > li:first').before(slider.find('.sprout-slide > li:last'));
							}
							mainContent.css('margin-left',(pageNum-1)*(-1)*width);
							copyFront = false;
						} else if(copyEnd){
							//恢復原狀
							//alert('恢復原狀copyEnd');
							for (j = 0 ; j < slideNum ; j++ ){
								slider.find('.sprout-slide > li:last').after(slider.find('.sprout-slide > li:first'));
							}
							mainContent.css('margin-left','0px');
							copyEnd = false;
						}

						if($.isFunction( settings.afterAnimate )){
							settings.afterAnimate.call(this,slider,currentDot,pageNum);
						}

						slider.find('.sprout-next').bind("click",nextClick);
						slider.find('.sprout-prev').bind("click",prevClick);
						slider.find('.sprout-dots div').bind("click",dotsClick);
					});
				} else if (animateStyle == 'fade'){
					//Get Next Page;
					if(where == 'left'){
						nextPage = currentDot-1;
					} else if (where == 'right'){
						nextPage = currentDot+1;
					} else {
						nextPage = where;
					}

					if(nextPage < 0){
						nextPage = pageNum-1;
					} else if(nextPage >= pageNum){
						nextPage = 0;
					}

					if($.isFunction( settings.beforeAnimate )){
						settings.beforeAnimate.call(this,slider,currentDot,pageNum);
					}

					//取得現在 active 的點, 並且移除所有 active;
					slider.find('.sprout-dots div').removeClass('active');
					slider.find('.sprout-dots div:eq('+nextPage+')').addClass('active');

					sliderH = slider.find('.sprout-slide li').eq(nextPage).height();
					mainContent.animate({'height':sliderH},500);

					slider.find('.sprout-slide li').eq(currentDot).fadeOut(300).end().eq(nextPage).hide().fadeIn(duration, function(){
						currentDot = nextPage;
						checkArrowDisplay();

						slider.find('.sprout-next').bind("click",nextClick);
						slider.find('.sprout-prev').bind("click",prevClick);
						slider.find('.sprout-dots div').bind("click",dotsClick);

						if($.isFunction( settings.afterAnimate )){
							settings.afterAnimate.call(this,slider,currentDot,pageNum);
						}

						//add animateTimer function to end of animation queue
						if (autoplay) {
							restartInterval();
						};
					});
				}
			}
		});
	}
}(jQuery));
// });<|endoftext|>


<commit_before>import cx from 'classnames';
import React from 'react';
import SoundCloudAudio from 'soundcloud-audio';
import VideoBackdrop from '../VideoBackdrop';

import SongInfo from './SongInfo';

const debug = require('debug')('uwave:component:video:soundcloud');

const CLIENT_ID = '9d883cdd4c3c54c6dddda2a5b3a11200';

let sc;

function getTrack(media, cb) {
  sc._jsonp(`${sc._baseUrl}/tracks/${media.sourceID}.json?client_id=${CLIENT_ID}`, data => {
    sc._track = data;
    cb(data);
  });
}

export default class SoundCloudPlayer extends React.Component {
  static propTypes = {
    className: React.PropTypes.string,
    enabled: React.PropTypes.bool,
    media: React.PropTypes.object,
    seek: React.PropTypes.number,
    volume: React.PropTypes.number
  };

  state = { track: null };

  componentWillMount() {
    if (!sc && typeof document !== 'undefined') {
      sc = new SoundCloudAudio(CLIENT_ID);
      sc.audio.autoplay = true;
    }
  }

  componentDidMount() {
    this.play();
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.media.sourceID !== this.props.media.sourceID) {
      this.play();
    }
  }

  componentDidUpdate(prevProps) {
    if (prevProps.volume !== this.props.volume) {
      sc.audio.volume = this.props.volume / 100;
    }
    if (prevProps.enabled !== this.props.enabled) {
      if (this.props.enabled) {
        this.play();
      } else {
        this.stop();
      }
    }
  }

  play() {
    this.setState({ track: null });
    if (this.props.enabled) {
      getTrack(this.props.media, track => {
        this.setState({ track: track });
        sc.play();
        debug('currentTime', this.props.seek);
        sc.audio.currentTime = this.props.seek;
        sc.audio.volume = this.props.volume / 100;
      });
    } else {
      this.stop();
    }
  }

  stop() {
    sc.stop();
  }

  render() {
    const { track } = this.state;
    if (!track) {
      return
;
    }
    const user = track.user;
    return (

        <VideoBackdrop url={track.artwork_url} />

            <SongInfo
              artist={user.username}
              title={track.title}
              artistUrl={user.permalink_url}
              trackUrl={track.permalink_url}
            />

            View on

    );
  }
}
<commit_msg>video: stop playing soundcloud tracks on unmount, fixes #113<commit_after>import cx from 'classnames';
import React from 'react';
import SoundCloudAudio from 'soundcloud-audio';
import VideoBackdrop from '../VideoBackdrop';

import SongInfo from './SongInfo';

const debug = require('debug')('uwave:component:video:soundcloud');

const CLIENT_ID = '9d883cdd4c3c54c6dddda2a5b3a11200';

let sc;

function getTrack(media, cb) {
  sc._jsonp(`${sc._baseUrl}/tracks/${media.sourceID}.json?client_id=${CLIENT_ID}`, data => {
    sc._track = data;
    cb(data);
  });
}

export default class SoundCloudPlayer extends React.Component {
  static propTypes = {
    className: React.PropTypes.string,
    enabled: React.PropTypes.bool,
    media: React.PropTypes.object,
    seek: React.PropTypes.number,
    volume: React.PropTypes.number
  };

  state = { track: null };

  componentWillMount() {
    if (!sc && typeof document !== 'undefined') {
      sc = new SoundCloudAudio(CLIENT_ID);
      sc.audio.autoplay = true;
    }
  }

  componentDidMount() {
    this.play();
  }

  componentDidUpdate(prevProps) {
    if (prevProps.volume !== this.props.volume) {
      sc.audio.volume = this.props.volume / 100;
    }
    if (prevProps.media.sourceID !== this.props.media.sourceID ||
        prevProps.enabled !== this.props.enabled) {
      if (this.props.enabled) {
        this.play();
      } else {
        this.stop();
      }
    }
  }

  componentWillUnmount() {
    this.stop();
  }

  play() {
    this.setState({ track: null });
    if (this.props.enabled) {
      getTrack(this.props.media, track => {
        this.setState({ track: track });
        sc.play();
        debug('currentTime', this.props.seek);
        sc.audio.currentTime = this.props.seek;
        sc.audio.volume = this.props.volume / 100;
      });
    } else {
      this.stop();
    }
  }

  stop() {
    sc.stop();
  }

  render() {
    const { track } = this.state;
    if (!track) {
      return
;
    }
    const user = track.user;
    return (

        <VideoBackdrop url={track.artwork_url} />

            <SongInfo
              artist={user.username}
              title={track.title}
              artistUrl={user.permalink_url}
              trackUrl={track.permalink_url}
            />

            View on

    );
  }
}
<|endoftext|>


<commit_before>/* eslint-disable @typescript-eslint/no-var-requires */
const Git = require('release-it/lib/plugin/git/Git')
const { format } = require('release-it/lib/util')
const { resolve, basename } = require('path')
const yaml = require('js-yaml')
const fs = require('fs/promises')
const { promisify } = require('util')
const glob = promisify(require('glob'))
const { EOL } = require('os')
const prependFile = require('prepend-file')

const fixArgs = args => (args ? (typeof args === 'string' ? args.split(' ') : args) : [])
const staged = resolve(__dirname, './staged')
const root = resolve(__dirname, '../')
const workspace = resolve(root, 'pnpm-workspace.yaml')

class GitPNPMMonorepo extends Git {
  static disablePlugin() {
    return ['git']
  }

  getInitialOptions(options, namespace) {
    options[namespace] = options.git
    return options[namespace]
  }

  async init() {
    await super.init()

    if (!await this.isPNPMAuthentication()) {
      throw new Error('Not authenticated with npm. Ensure NPM_TOKEN is set')
    }

    const packages = yaml.load(await fs.readFile(workspace, 'utf-8')).packages.map(x => basename(x))
    const stagedJSONs = await glob(`${staged}/*.json`)
      .then(files => Promise.all(files.map(file => fs.readFile(file))))
      .then(files => files.map((file) => JSON.parse(file)))

    const stagedChanges = stagedJSONs
      .filter(fileData => packages.find(x => fileData.name.includes(x)))

    this.config.setContext({
      stagedChanges,
      affectedModules: stagedChanges.length,
      updateLog: stagedChanges.map(fileData => `${fileData.name}: ${fileData.latestVersion} -> ${fileData.version}`).join('\n'),
      aggregateChangelog: stagedChanges.flatMap(fileData => [
        `# ${fileData.name} ${fileData.version}`,
        fileData.changelog
      ]).join('\n\n')
    })
  }

  // overwrites changelog for release notes
  async beforeRelease() {
    this.config.setContext({
      changelog: this.config.getContext('aggregateChangelog'),
    })

    return super.beforeRelease()
  }

  async release() {
    const { commit, tag, push, pnpm, changelog } = this.options
    await this.step({ enabled: changelog, task: () => this.writeChangelog(), label: 'Aggregated Changelog' })
    await this.step({ enabled: commit, task: () => this.commit(), label: 'Git commit' })
    await this.step({ enabled: tag, task: () => this.tag(), label: 'Git tag' })
    await this.step({ enabled: pnpm, task: () => this.pnpm(), label: 'Publish PNPM' })
    return !!(await this.step({ enabled: push, task: () => this.push(), label: 'Git push' }))
  }

  async tag({ annotation = this.options.tagAnnotation, args = this.options.tagArgs } = {}) {
    const context = this.config.getContext()
    const { stagedChanges } = context
    for (const stagedModule of stagedChanges.values()) {
      const message = format(annotation, { ...context, stagedModule })
      const tagName = format('${name}@${version}', stagedModule)

      try {
        await this.exec(['git', 'tag', '--annotate', '--message', message, ...fixArgs(args), tagName])
      } catch (e) {
        if (/tag '.+' already exists/.test(e)) {
          this.log.warn(`Tag "${tagName}" already exists`)
        } else {
          throw e
        }
      }
    }

    const message = format('Release ${version}', context)
    await this.exec(['git', 'tag', '--annotate', '--message', message, ...fixArgs(args), context.tagName])

    this.setContext({ isTagged: true })
  }

  async isPNPMAuthentication() {
    try {
      const username = await this.exec('pnpm whoami', { options: { write: false } })
      this.setContext({ username: username ? username.trim() : null })
    } catch (err) {
      this.debug(err)
      if (/code E40[04]/.test(err)) {
        this.log.warn('Ignoring response from unsupported `pnpm whoami` command.')
        return true
      }
      return false
    }

    return !!this.getContext('username')
  }

  async pnpm() {
    await this.exec(['pnpm', '-r', 'publish'])
  }

  async writeChangelog() {
    const { infile } = this.options
    const { isDryRun } = this.config
    const { aggregateChangelog } = this.config.getContext()

    let hasInfile = false
    try {
      await fs.access(infile)
      hasInfile = true
    } catch (err) {
      this.debug(err)
    }

    if (!isDryRun) {
      await prependFile(infile, aggregateChangelog + EOL + EOL)
    }

    if (!hasInfile) {
      await this.exec(`git add ${infile}`)
    }
  }

  commit({ message = this.options.commitMessage, args = this.options.commitArgs } = {}) {
    const msg = format(message, this.config.getContext())
    return this.exec(['git', 'commit', '--message', msg, ...fixArgs(args)]).then(
      () => this.setContext({ isCommitted: true }),
      err => {
        this.debug(err)
        if (/nothing (added )?to commit/.test(err) || /nichts zu committen/.test(err)) {
          this.log.warn('No changes to commit. The latest commit will be tagged.')
        } else {
          throw new Error(err)
        }
      }
    )
  }

  step(options) {
    const context = Object.assign({}, this.config.getContext(), { [this.namespace]: this.getContext() })
    const opts = Object.assign({}, options, { context })
    return this.spinner.show(opts)
  }
}

module.exports = GitPNPMMonorepo
<commit_msg>chore(tooling): write changelog in beforeRelease<commit_after>/* eslint-disable @typescript-eslint/no-var-requires */
const Git = require('release-it/lib/plugin/git/Git')
const { format } = require('release-it/lib/util')
const { resolve, basename } = require('path')
const yaml = require('js-yaml')
const fs = require('fs/promises')
const { promisify } = require('util')
const glob = promisify(require('glob'))
const { EOL } = require('os')
const prependFile = require('prepend-file')

const fixArgs = args => (args ? (typeof args === 'string' ? args.split(' ') : args) : [])
const staged = resolve(__dirname, './staged')
const root = resolve(__dirname, '../')
const workspace = resolve(root, 'pnpm-workspace.yaml')

class GitPNPMMonorepo extends Git {
  static disablePlugin() {
    return ['git']
  }

  getInitialOptions(options, namespace) {
    options[namespace] = options.git
    return options[namespace]
  }

  async init() {
    await super.init()

    if (!await this.isPNPMAuthentication()) {
      throw new Error('Not authenticated with npm. Ensure NPM_TOKEN is set')
    }

    const packages = yaml.load(await fs.readFile(workspace, 'utf-8')).packages.map(x => basename(x))
    const stagedJSONs = await glob(`${staged}/*.json`)
      .then(files => Promise.all(files.map(file => fs.readFile(file))))
      .then(files => files.map((file) => JSON.parse(file)))

    const stagedChanges = stagedJSONs
      .filter(fileData => packages.find(x => fileData.name.includes(x)))

    this.config.setContext({
      stagedChanges,
      affectedModules: stagedChanges.length,
      updateLog: stagedChanges.map(fileData => `${fileData.name}: ${fileData.latestVersion} -> ${fileData.version}`).join('\n'),
      aggregateChangelog: stagedChanges.flatMap(fileData => [
        `# ${fileData.name} ${fileData.version}`,
        fileData.changelog
      ]).join('\n\n')
    })
  }

  // overwrites changelog for release notes
  async beforeRelease() {
    const { changelog } = this.options

    this.config.setContext({
      changelog: this.config.getContext('aggregateChangelog'),
    })
    await this.step({ enabled: changelog, task: () => this.writeChangelog(), label: 'Aggregated Changelog' })

    return super.beforeRelease()
  }

  async release() {
    const { commit, tag, push, pnpm } = this.options
    await this.step({ enabled: commit, task: () => this.commit(), label: 'Git commit' })
    await this.step({ enabled: tag, task: () => this.tag(), label: 'Git tag' })
    await this.step({ enabled: pnpm, task: () => this.pnpm(), label: 'Publish PNPM' })
    return !!(await this.step({ enabled: push, task: () => this.push(), label: 'Git push' }))
  }

  async tag({ annotation = this.options.tagAnnotation, args = this.options.tagArgs } = {}) {
    const context = this.config.getContext()
    const { stagedChanges } = context
    for (const stagedModule of stagedChanges.values()) {
      const message = format(annotation, { ...context, stagedModule })
      const tagName = format('${name}@${version}', stagedModule)

      try {
        await this.exec(['git', 'tag', '--annotate', '--message', message, ...fixArgs(args), tagName])
      } catch (e) {
        if (/tag '.+' already exists/.test(e)) {
          this.log.warn(`Tag "${tagName}" already exists`)
        } else {
          throw e
        }
      }
    }

    const message = format('Release ${version}', context)
    await this.exec(['git', 'tag', '--annotate', '--message', message, ...fixArgs(args), context.tagName])

    this.setContext({ isTagged: true })
  }

  async isPNPMAuthentication() {
    try {
      const username = await this.exec('pnpm whoami', { options: { write: false } })
      this.setContext({ username: username ? username.trim() : null })
    } catch (err) {
      this.debug(err)
      if (/code E40[04]/.test(err)) {
        this.log.warn('Ignoring response from unsupported `pnpm whoami` command.')
        return true
      }
      return false
    }

    return !!this.getContext('username')
  }

  async pnpm() {
    await this.exec(['pnpm', '-r', 'publish'])
  }

  async writeChangelog() {
    const { infile } = this.options
    const { isDryRun } = this.config
    const { aggregateChangelog } = this.config.getContext()

    let hasInfile = false
    try {
      await fs.access(infile)
      hasInfile = true
    } catch (err) {
      this.debug(err)
    }

    if (!isDryRun) {
      await prependFile(infile, aggregateChangelog + EOL + EOL)
    }

    if (!hasInfile) {
      await this.exec(`git add ${infile}`)
    }
  }

  commit({ message = this.options.commitMessage, args = this.options.commitArgs } = {}) {
    const msg = format(message, this.config.getContext())
    return this.exec(['git', 'commit', '--message', msg, ...fixArgs(args)]).then(
      () => this.setContext({ isCommitted: true }),
      err => {
        this.debug(err)
        if (/nothing (added )?to commit/.test(err) || /nichts zu committen/.test(err)) {
          this.log.warn('No changes to commit. The latest commit will be tagged.')
        } else {
          throw new Error(err)
        }
      }
    )
  }

  step(options) {
    const context = Object.assign({}, this.config.getContext(), { [this.namespace]: this.getContext() })
    const opts = Object.assign({}, options, { context })
    return this.spinner.show(opts)
  }
}

module.exports = GitPNPMMonorepo
<|endoftext|>


<commit_before>function Autostereogram() {
    this.setXdpi = function(xdpi) {
	this.eyeSep = xdpi * 2.5;
	this.obsDist = xdpi * 12;
	this.maxdepth = xdpi * 12;
	this.maxsep = Math.floor((this.eyeSep * this.maxdepth)/
				 (this.maxdepth + this.obsDist));
	this.sepfactor = 0.55;
	this.mindepth=(this.sepfactor*this.maxdepth*this.obsDist)/
	    ((1-this.sepfactor)*this.maxdepth+this.obsDist);
    }
    this.invert = false;
    this.setXdpi(200);

    // member functions
    this.getSeparation = function (idx, depthData) {
	var z = (depthData.data[idx + 0] + depthData.data[idx + 1] +
		 depthData.data[idx + 2]) / 3;
	if(this.invert) { z = 256 - z; }
	var zdepth = this.maxdepth - z * (this.maxdepth - this.mindepth)/256;

	return Math.round((this.eyeSep * zdepth) / (zdepth + this.obsDist));
    }

    this.calculateLinksForRow = function (width, y, depthData, lookL, lookR) {
	for(var x = 0; x < width; x++) {
	    lookL[x] = x;
	    lookR[x] = x;
	}

	for(var x = 0; x < width; x++) {
	    var separation = this.getSeparation(index(x, y, width), depthData);
	    var left = Math.floor(x - separation/2);
	    var right = left + separation;
	    var visible = true;
	    if((left >= 0) && (right < width)) {
		if (lookL[right]!=right) // right pt already linked
		{
		    if (lookL[right]<left) // deeper than current
		    {
			lookR[lookL[right]]=lookL[right]; // break old links
			lookL[right]=right;
		    } else { visible = false; }
		}

		if (lookR[left]!=left) // left pt already linked
		{
		    if (lookR[left]>right) // deeper than current
		    {
			lookL[lookR[left]]=lookR[left]; // break old links
			lookR[left]=left;
		    } else { visible = false; }
		}
		if (visible) { // make link
		    lookL[right]=left;
		    lookR[left]=right;
		}
	    }
	}
    }

    this.generate = function(canvas, pattern, depthmap) {
	var ctx = canvas.getContext('2d');

	var pData =
	    pattern.getContext('2d').getImageData(0, 0, pattern.width, pattern.height);
	var depthData =
	    depthmap.getContext('2d').getImageData(0, 0, depthmap.width, depthmap.height);
	var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);

	var width = depthmap.width;
	for(var y = 0; y < depthmap.height; y++) {
	    // Initialize linked pixels for row
	    var lookL = new Array(width);
	    var lookR = new Array(width);
	    this.calculateLinksForRow(width, y, depthData, lookL, lookR);

	    var lastlinked = 0;
	    var color = new Array(width);
	    for(var x = 0; x < width; x++) {
		if(lookL[x] == x) {
		    if(lastlinked == x-1) {
			color[x] = color[x-1]
		    } else {
			color[x] = x % this.maxsep;
		    }
		} else {
		    color[x] = color[lookL[x]];
		    lastlinked = x;
		}
		copy_idx(index(color[x], y % pData.height, pData.width), pData,
	     		 index(x, y, canvas.width), canvasData);
	    }
	}
	ctx.putImageData(canvasData, 0, 0);
    }
}

function selected_image(group) {
    var group_form = document.getElementById(group);

    var selector = group_form.selector;
    var index = 0;
    for(var i = 0; i < selector.length; i++) {
	if(selector[i].checked) {
	    index = i;
	    break;
	}
    }

    return group_form.getElementsByTagName("img")[index];
}

function run() {
    var pattern = create_canvas_from_image(selected_image('pattern_group'));
    var depthmap = create_canvas_from_image(selected_image('depthmap_group'));
    var canvas = document.getElementById('magiceye');

    var invert = document.getElementById("invert");
    var width = document.getElementById("width").value;
    var height = document.getElementById("height").value;
    canvas.width = width;
    canvas.height = height;

    depthmap = scale_canvas(depthmap, width / depthmap.width, height / depthmap.height);

    var autostereogram = new Autostereogram();
    autostereogram.invert = invert.checked;
    autostereogram.generate(canvas, pattern, depthmap);

    canvas.onclick = function() {
	canvas.getContext('2d').drawImage(depthmap, 0, 0);
	canvas.onclick = function() {
	    run();
	}
    }

    document.getElementById('depthmap_files').
	addEventListener('change',
			 function(evt) { file_selector(evt, "depthmap_group") },
			 false);
    document.getElementById('pattern_files').
	addEventListener('change',
			 function(evt) { file_selector(evt, "pattern_group") },
			 false);
}

function index(x,y,width) {
    return (x + y * width) * 4;
}

function copy_idx(src_idx, src, dst_idx, dst) {
    dst.data[dst_idx + 0] = src.data[src_idx + 0];
    dst.data[dst_idx + 1] = src.data[src_idx + 1];
    dst.data[dst_idx + 2] = src.data[src_idx + 2];
    dst.data[dst_idx + 3] = src.data[src_idx + 3];
}

function create_canvas_from_image(img) {
    var canvas = document.createElement('canvas');
    var context = canvas.getContext('2d');

    // real_img is a hack to get back the original image size, and not
    // the computed thumbnail size
    var real_img = new Image();
    real_img.src = (img.getAttribute ? img.getAttribute("src") : false) || img.src;
    img = real_img;

    canvas.width = img.width;
    canvas.height = img.height;

    context.drawImage(img, 0, 0, img.width, img.height);

    return canvas;
}

function scale_canvas(canvas, xscale, yscale) {
    var ctx = canvas.getContext('2d');
    ctx.scale(xscale,yscale);
    var scaled = document.createElement('canvas');
    scaled.width = canvas.width * xscale;
    scaled.height = canvas.height * yscale;
    scaled.getContext('2d').drawImage(canvas, 0, 0, scaled.width, scaled.height);
    return scaled;
}

// modified from http://www.html5rocks.com/tutorials/file/dndfiles/#toc-selecting-files-input
function file_selector(evt, group) {
    var files = evt.target.files; // FileList object

    // Loop through the FileList and render image files as thumbnails.
    for (var i = 0, f; f = files[i]; i++) {

	// Only process image files.
	if (!f.type.match('image.*')) {
	    continue;
	}

	var reader = new FileReader();

	// Closure to capture the file information.
	reader.onload = (function(theFile) {
	    return function(e) {
		// Render thumbnail.
		var span = document.createElement('span');
		span.innerHTML = ['<input type="radio" name="selector"/>',
				  ''].join('');
		document.getElementById(group).appendChild(span, null);
	    };
	})(f);

	// Read in the image file as a data URL.
	reader.readAsDataURL(f);
    }
}
<commit_msg>indentation fix for autostereogram<commit_after>function Autostereogram() {
    this.setXdpi = function(xdpi) {
        this.eyeSep = xdpi * 2.5;
        this.obsDist = xdpi * 12;
        this.maxdepth = xdpi * 12;
        this.maxsep = Math.floor((this.eyeSep * this.maxdepth)/
                                 (this.maxdepth + this.obsDist));
        this.sepfactor = 0.55;
        this.mindepth=(this.sepfactor*this.maxdepth*this.obsDist)/
            ((1-this.sepfactor)*this.maxdepth+this.obsDist);
    };
    this.invert = false;
    this.setXdpi(200);

    // member functions
    this.getSeparation = function (idx, depthData) {
        var z = (depthData.data[idx + 0] + depthData.data[idx + 1] +
                 depthData.data[idx + 2]) / 3;
        if(this.invert) { z = 256 - z; }
        var zdepth = this.maxdepth - z * (this.maxdepth - this.mindepth)/256;

        return Math.round((this.eyeSep * zdepth) / (zdepth + this.obsDist));
    }

    this.calculateLinksForRow = function (width, y, depthData, lookL, lookR) {
        for(var x = 0; x < width; x++) {
            lookL[x] = x;
            lookR[x] = x;
        }

        for(var x = 0; x < width; x++) {
            var separation = this.getSeparation(index(x, y, width), depthData);
            var left = Math.floor(x - separation/2);
            var right = left + separation;
            var visible = true;
            if((left >= 0) && (right < width)) {
                if (lookL[right]!=right) { // right pt already linked
                    if (lookL[right]<left) // deeper than current
                    {
                        lookR[lookL[right]]=lookL[right]; // break old links
                        lookL[right]=right;
                    } else { visible = false; }
                }

                if (lookR[left]!=left) // left pt already linked
                {
                    if (lookR[left]>right) // deeper than current
                    {
                        lookL[lookR[left]]=lookR[left]; // break old links
                        lookR[left]=left;
                    } else { visible = false; }
                }
                if (visible) { // make link
                    lookL[right]=left;
                    lookR[left]=right;
                }
            }
        }
    }

    this.generate = function(canvas, pattern, depthmap) {
        var ctx = canvas.getContext('2d');

        var pData =
                pattern.getContext('2d').getImageData(0, 0, pattern.width, pattern.height);
        var depthData =
                depthmap.getContext('2d').getImageData(0, 0, depthmap.width, depthmap.height);
        var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);

        var width = depthmap.width;
        for(var y = 0; y < depthmap.height; y++) {
            // Initialize linked pixels for row
            var lookL = new Array(width);
            var lookR = new Array(width);
            this.calculateLinksForRow(width, y, depthData, lookL, lookR);

            var lastlinked = 0;
            var color = new Array(width);
            for(var x = 0; x < width; x++) {
                if(lookL[x] == x) {
                    if(lastlinked == x-1) {
                        color[x] = color[x-1]
                    } else {
                        color[x] = x % this.maxsep;
                    }
                } else {
                    color[x] = color[lookL[x]];
                    lastlinked = x;
                }
                copy_idx(index(color[x], y % pData.height, pData.width), pData,
                         index(x, y, canvas.width), canvasData);
            }
        }
        ctx.putImageData(canvasData, 0, 0);
    }
}

function selected_image(group) {
    var group_form = document.getElementById(group);

    var selector = group_form.selector;
    var index = 0;
    for(var i = 0; i < selector.length; i++) {
        if(selector[i].checked) {
            index = i;
            break;
        }
    }

    return group_form.getElementsByTagName("img")[index];
}

function run() {
    var pattern = create_canvas_from_image(selected_image('pattern_group'));
    var depthmap = create_canvas_from_image(selected_image('depthmap_group'));
    var canvas = document.getElementById('magiceye');

    var invert = document.getElementById("invert");
    var width = document.getElementById("width").value;
    var height = document.getElementById("height").value;
    canvas.width = width;
    canvas.height = height;

    depthmap = scale_canvas(depthmap, width / depthmap.width, height / depthmap.height);

    var autostereogram = new Autostereogram();
    autostereogram.invert = invert.checked;
    autostereogram.generate(canvas, pattern, depthmap);

    canvas.onclick = function() {
        canvas.getContext('2d').drawImage(depthmap, 0, 0);
        canvas.onclick = function() {
            run();
        }
    }

    document.getElementById('depthmap_files').
        addEventListener('change',
                         function(evt) { file_selector(evt, "depthmap_group") },
                         false);
    document.getElementById('pattern_files').
        addEventListener('change',
                         function(evt) { file_selector(evt, "pattern_group") },
                         false);
}

function index(x,y,width) {
    return (x + y * width) * 4;
}

function copy_idx(src_idx, src, dst_idx, dst) {
    dst.data[dst_idx + 0] = src.data[src_idx + 0];
    dst.data[dst_idx + 1] = src.data[src_idx + 1];
    dst.data[dst_idx + 2] = src.data[src_idx + 2];
    dst.data[dst_idx + 3] = src.data[src_idx + 3];
}

function create_canvas_from_image(img) {
    var canvas = document.createElement('canvas');
    var context = canvas.getContext('2d');

    // real_img is a hack to get back the original image size, and not
    // the computed thumbnail size
    var real_img = new Image();
    real_img.src = (img.getAttribute ? img.getAttribute("src") : false) || img.src;
    img = real_img;

    canvas.width = img.width;
    canvas.height = img.height;

    context.drawImage(img, 0, 0, img.width, img.height);

    return canvas;
}

function scale_canvas(canvas, xscale, yscale) {
    var ctx = canvas.getContext('2d');
    ctx.scale(xscale,yscale);
    var scaled = document.createElement('canvas');
    scaled.width = canvas.width * xscale;
    scaled.height = canvas.height * yscale;
    scaled.getContext('2d').drawImage(canvas, 0, 0, scaled.width, scaled.height);
    return scaled;
}

// modified from http://www.html5rocks.com/tutorials/file/dndfiles/#toc-selecting-files-input
function file_selector(evt, group) {
    var files = evt.target.files; // FileList object

    // Loop through the FileList and render image files as thumbnails.
    for (var i = 0, f; f = files[i]; i++) {

        // Only process image files.
        if (!f.type.match('image.*')) {
            continue;
        }

        var reader = new FileReader();

        // Closure to capture the file information.
        reader.onload = (function(theFile) {
            return function(e) {
                // Render thumbnail.
                var span = document.createElement('span');
                span.innerHTML = ['<input type="radio" name="selector"/>',
                                  ''].join('');
                document.getElementById(group).appendChild(span, null);
            };
        })(f);

        // Read in the image file as a data URL.
        reader.readAsDataURL(f);
    }
}
<|endoftext|>


<commit_before>
describe('bail', function(){
  it('should only display this error', function(done){
    throw new Error('this should be displayed');
  })

  it('should not display this error', function(done){
    throw new Error('this should not be displayed');
  })
})

describe('bail-2', function(){

	before(function (done) {
    throw new Error('this hook should not be displayed');
	})

  it('should not display this error', function(done){
    throw new Error('this should not be displayed');
  })
})
<commit_msg>style<commit_after>
describe('bail', function(){
  it('should only display this error', function(done){
    throw new Error('this should be displayed');
  })

  it('should not display this error', function(done){
    throw new Error('this should not be displayed');
  })
})

describe('bail-2', function(){

	before(function(done){
    throw new Error('this hook should not be displayed');
	})

  it('should not display this error', function(done){
    throw new Error('this should not be displayed');
  })
})
<|endoftext|>


<commit_before>(function(){

    "use strict";

    /** This class will create an xml3d element on top of the given one.
     *  It will forward any mouse events that don't hit an xml3d element to the target
     *  element. Also it will mirror and track the target element's view.
     *
     *  This implementation will attach listeners to the canvas element, that is
     *  created for xml3d. The graph looks as follows:
     *  o canvas: the visible stuff
     *  o invisible div: container for the xml3d tree
     *      - xml3d: the actual xml3d element
     *
     *  This is wanted because the xml3d element itself will receive other mouse
     *  events. For example an mouseout event of geometry in the overlay will
     *  probably not be a mouseout event in the underlying element.
     *  Thus, we will simply forward the unfiltered events, that the canvas itself
     *  receives.
     *
     *  PROBLEM
     *  There is a general problem with overlays: multiple ones on top of each other.
     *  Now the propagation to underlying elements is done by making itself invisible.
     *  However, if multiple overlays are present that causes an infinite loop (switch
     *  the overlay below another one invisible...).
     */
    XML3D.tools.xml3doverlay.XML3DOverlay = new XML3D.tools.Class(
        XML3D.tools.util.Attachable, {

        /**
         *  @this {XML3D.tools.xml3doverlay.XML3DOverlay}
         */
        initialize: function(targetXML3DElement)
        {
            this.xml3dTarget = targetXML3DElement;
            this.xml3d = this._createXML3DElement();

            this._xml3dCanvas = null; // set in _registerEventListeners()

            this._mirroredView = new XML3D.tools.interaction.behaviors.MirroredView(
                targetXML3DElement, this.xml3d);
        },

        /**
         *  @this {XML3D.tools.xml3doverlay.XML3DOverlay}
         *  @override
         *  @protected
         */
        onAttach: function()
        {
            document.body.appendChild(this.xml3d);
            this._mirroredView.attach();
            this._registerEventListeners(true);
        },

        /**
         *  @this {XML3D.tools.xml3doverlay.XML3DOverlay}
         *  @override
         *  @protected
         */
        onDetach: function()
        {
            this._registerEventListeners(false);

            this._mirroredView.detach();
            var canvas = this.xml3d.parentNode.previousSibling;

            document.body.removeChild(this.xml3d.parentNode);
            document.body.removeChild(canvas);
        },

        /**
         *  @this {XML3D.tools.xml3doverlay.XML3DOverlay}
         *  @private
         */
        _createXML3DElement: function()
        {
            var targetWidth = this.xml3dTarget.offsetWidth;
            var targetHeight = this.xml3dTarget.offsetHeight;
            var targetOffset = this._calculateOffset(this.xml3dTarget);
            var zIndex = this._getTargetZIndex();

            var styleAttrib = "width:" + targetWidth + "px;height:" + targetHeight + "px;";
            styleAttrib += "background-color:transparent;";
            styleAttrib += "z-index:" + zIndex + ";";
            styleAttrib += "position:absolute;";
            styleAttrib += "top:" + targetOffset.top + "px;left:" + targetOffset.left + "px;";

            return XML3D.tools.creation.element("xml3d", { style: styleAttrib });
        },

        /**
         *  @this {XML3D.tools.xml3doverlay.XML3DOverlay}
         *  @private
         */
        _registerEventListeners: function(doAddListener)
        {
            if(!this.xml3d.parentNode || !this.xml3d.parentNode.previousElementSibling)
                throw new Error("XML3DOverlay: xml3d element has no parent node or no canvas attached.");

            this._xml3dCanvas = this.xml3d.parentNode.previousElementSibling;

            if(this._xml3dCanvas.tagName.toLowerCase() !== "canvas")
                throw new Error("XML3DOverlay: associated element must be a canvas.");

            var registerFn = this._xml3dCanvas.addEventListener.bind(this._xml3dCanvas);
            if(doAddListener === false)
                registerFn = this._xml3dCanvas.removeEventListener.bind(this._xml3dCanvas);

            registerFn("click", this.callback("_onOverlayMouseEvent"), false);
            registerFn("mousedown", this.callback("_onOverlayMouseEvent"), false);
            registerFn("mouseup", this.callback("_onOverlayMouseEvent"), false);
            registerFn("mouseover", this.callback("_onOverlayMouseEvent"), false);
            registerFn("mousemove", this.callback("_onOverlayMouseEvent"), false);
            registerFn("mouseout", this.callback("_onOverlayMouseEvent"), false);
        },

        /**
         *  @this {XML3D.tools.xml3doverlay.XML3DOverlay}
         *  @private
         */
        _onOverlayMouseEvent: function(evt)
        {
            var elOverlay = this.xml3d.getElementByPoint(evt.pageX, evt.pageY);
            if(elOverlay)
                return; // hit: do not delegate anything

            var oldStyleDisplay = this._xml3dCanvas.style.display;

            this._xml3dCanvas.style.display = "none";
            var newEl = document.elementFromPoint(evt.clientX, evt.clientY);
            this._xml3dCanvas.style.display = oldStyleDisplay;

            if(newEl)
                this._delegateEvent(evt, newEl);
        },

        _delegateEvent: function(evt, newTarget)
        {
            var newEvt = document.createEvent("MouseEvents");
            newEvt.initMouseEvent(evt.type, evt.bubbles, evt.cancelable,
                evt.view, evt.detail, evt.screenX, evt.screenY,
                evt.clientX, evt.clientY, evt.ctrlKey, evt.altKey, evt.shiftKey,
                evt.metaKey, evt.button, evt.relatedTarget);

            newTarget.dispatchEvent(newEvt);
        },

        /**
         *  @this {XML3D.tools.xml3doverlay.XML3DOverlay}
         *  @private
         */
        _getTargetZIndex: function()
        {
            var zIndex = this._getTargetStyleProperty("z-index");
            if(isNaN(zIndex))
                zIndex = 1;
            else
                zIndex++;

            return zIndex;
        },

        /**
         *  @this {XML3D.tools.xml3doverlay.XML3DOverlay}
         *  @private
         */
        _getTargetStyleProperty: function(stylePropertyName)
        {
            if (this.xml3dTarget.currentStyle)
                return this.xml3dTarget.currentStyle[stylePropertyName];
            else if (window.getComputedStyle) {
                var computedStyle = document.defaultView.getComputedStyle(this.xml3dTarget,null);
                return computedStyle.getPropertyValue(stylePropertyName);
            }

            throw new Error("XML3D.tools.xml3doverlay.XML3DOverlay: missing style property '" + stylePropertyName + "' of target element!");
        },

        /** Calculate the offset of the given element and return it.
         *
         *  @param {Object} element
         *  @return {{top:number, left:number}} the offset
         *
         *  This code is taken from http://javascript.info/tutorial/coordinates .
         *  We don't want to do it with the offsetParent way, because the xml3d
         *  element is actually invisible and thus offsetParent will return null
         *  at least in WebKit. Also it's slow. So we use getBoundingClientRect().
         *  However it returns the box relative to the window, not the document.
         *  Thus, we need to incorporate the scroll factor. And because IE is so
         *  awesome some workarounds have to be done and the code gets complicated.
         */
        _calculateOffset: function(element)
        {
            var box = element.getBoundingClientRect();
            var body = document.body;
            var docElem = document.documentElement;

            // get scroll factor (every browser except IE supports page offsets)
            var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop;
            var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;

            // the document (`html` or `body`) can be shifted from left-upper corner in IE. Get the shift.
            var clientTop = docElem.clientTop || body.clientTop || 0;
            var clientLeft = docElem.clientLeft || body.clientLeft || 0;

            var top  = box.top +  scrollTop - clientTop;
            var left = box.left + scrollLeft - clientLeft;

            // for Firefox an additional rounding is sometimes required
            return {top: Math.round(top), left: Math.round(left)};
        }
    });

}());
<commit_msg>util: removed unused class XML3DOverlay<commit_after><|endoftext|>


<commit_before>'use strict';

angular.module('gendex.widgets')
.directive('dextable', function () {
    return {
        restrict: 'A',
        scope: {
            shared: '='
        },
        replace: false,
        templateUrl: '/static/genapp-gendex/partials/directives/dextable.html',
        controller: ['$scope', 'filterByFieldText', 'notify', 'Data', '$routeParams',
        function ($scope, filterByFieldText, notify, Data, $routeParams) {
            $scope.gridOptions = {};
            $scope.data = {};
            $scope.gridVisible = false;
            $scope.fieldsValuesCount = 0;
            // console.log('inside dextable ctrl');

            function initErrorNotify (msg, error) {
                $scope.errorMsg = msg;
                $scope.$on('notifyReady', function (error) {
                    notify.error($scope.errorMsg)(error);
                });
                $scope.gridVisible = false;
            }

            // request JSON data
            Data.get({'id': $routeParams.id}, function (caseData) {
                if (_.contains(caseData.type, 'differentialexpression') && _.contains(caseData.status, 'done')) {
                    // request tab-delimited file
                    Data.download({'id': $routeParams.id, 'file': caseData.output.diffexp.file}, function (raw) {
                        var data = raw.data;
                        // tab header
                        $scope.tabHeader = data.slice(0, data.indexOf('\n')).replace(/\./g, '_').split(/[\t]/);
                        // data
                        var vals = data.slice(data.indexOf('\n') + 1, data.length + 1).split(/[\n]+/);
                        $scope.data.values = vals;
                        // nr. of columns test
                        if (typeof vals[0] !== 'undefined') $scope.colCount = $scope.tabHeader.length;
                        // objective trigger
                        $scope.fieldsValuesCount = $scope.fieldsValuesCount + 1;
                    }, function (error) {
                        initErrorNotify('failed tab file request', error);
                    });
                }
                else initErrorNotify('wrong case id request', 'error');
            }, function (error) {
                initErrorNotify('failed JSON file request via api', error);
            });

            // when upgrading to AngularJS 1.3, replace $watchCollection with $watchGroup
            // wait for both case and control column counts, build column definitions
            $scope.$watch('colCount', function (count) {
                if (typeof count !== 'undefined') {
                    // build column definitions
                    var columnDefs = [],
                        ltcc = 1,
                        ltpc = 1,
                        tabHeader = $scope.tabHeader;

                    for (var i = 0; i < count; i++) {
                        var tH = tabHeader[i].toLowerCase();
                        // case-control columns
                        if (_.contains(tH, 'counts')) {
                            var field = _.contains(tH, 'case') ? ['lt', ltcc++, 'c'] : ['lt', ltpc++, 'p'];
                            field = field.join('');

                            columnDefs.push({field: field, displayName: field.toUpperCase(), width: '*'});
                        }
                        // the rest: {fdr.de, lik.nde} (manual pick for now)
                        else if (_.indexOf(['gene', 'fdr_de', 'lik_nde'], tH) > -1) {
                            columnDefs.push({field: tH, displayName: tH.toUpperCase(), width: '**'});
                        }
                    }
                    // push data to scope
                    $scope.columnDefs = columnDefs;
                    // objective trigger
                    $scope.fieldsValuesCount = $scope.fieldsValuesCount + 1;
                }
            });

            // trigger when both objective triggers
            $scope.$watch('fieldsValuesCount', function (val) {
                // construct table and populate ng-grid
                if (val == 2) {
                    var line = null,
                        newline = null,
                        grid = [];
                    for (var i = 0; i < $scope.data.values.length; i++) {
                        line = $scope.data.values[i].split(/[\t]/);
                        newline = {};
                        for (var j = 0; j < $scope.columnDefs.length; j++) {
                            newline[$scope.columnDefs[j].field] = line[j];
                        }
                        grid.push(newline);
                    }
                    $scope.shared.data = grid;
                    $scope.shared.filteredRows = grid;
                }
            });

            // set ng-grid options
            $scope.$watchCollection('shared.filteredRows', function (data) {
                $scope.gridOptions.data = 'shared.filteredRows';
                $scope.gridOptions.filterOptions = $scope.filterOptions;
                $scope.gridOptions.selectedItems = [];
                $scope.gridOptions.beforeSelectionChange = beforeSelection;
                $scope.gridOptions.columnDefs = 'columnDefs';
            });

            // make ng-grid visible
            $scope.$watch('gridOptions', function (grid) {
                $scope.gridVisible = true;
            });

            function beforeSelection (rowItem, event) {
                if (event.type == 'click') {
                    $scope.shared.selectedRow = rowItem;
                    return false;
                }
                return true;
            }

            $scope.filterOptions = {
                filterText: '',
                useExternalFilter: true
            };

            $scope.$watch('filterOptions.filterText', function (val) {
                if (typeof $scope.shared.filteredRows !== 'undefined') {
                    $scope.shared.filteredRows = filterByFieldText($scope.shared.data, val, true, true);
                }
            });

            $scope.$watch('shared.selectedGenes', function (rows) {
                if ($scope.gridVisible) {
                    // $scope.gridOptions.selectAll(false);
                    for (var i = 0; i < rows.length; i++) {
                        var index = $scope.data.indexOf(rows[i]);
                        $scope.gridOptions.selectItem(index, true);
                    }
                }
            });
        }]
    };
});
<commit_msg>Refactor DexTable<commit_after>'use strict';

angular.module('gendex.widgets')
.directive('dextable', function () {
    return {
        restrict: 'A',
        scope: {
            shared: '='
        },
        replace: false,
        templateUrl: '/static/genapp-gendex/partials/directives/dextable.html',
        controller: ['$scope', 'filterByFieldText', 'notify', 'Data', '$routeParams',
        function ($scope, filterByFieldText, notify, Data, $routeParams) {
            $scope.gridVisible = false;
            // console.log('inside dextable ctrl');

            var split = _.curry(function (delim, str) {
                return str.split(delim);
            });
            var replace = _.curry(function (from, to, str) {
                return str.replace(from, to);
            });
            var zipObject = _.curry(_.zipObject, 2);

            function parseData(data) {
                var lines = data.split(/\n+/);
                var table = _.map(lines, split(/\t/));

                var tabHeader = _.map(table[0], replace(/\./g, '_'));

                var keptHeader = _.filter(tabHeader, function (col) {
                    var lowCol = col.toLowerCase();
                    return /counts/i.test(lowCol) || _.indexOf(['gene', 'fdr_de', 'lik_nde'], lowCol) >= 0;
                });

                var ret = {};
                var ltcc = 1;
                var ltpc = 1;
                return {
                    cols: _.map(keptHeader, function (col) {
                        var ret = {field: col, displayName: col, width: '**'};

                        if (/counts/i.test(col)) {
                            var newColName = /case/i.test(col) ? ['lt', ltcc++, 'c'] : ['lt', ltpc++, 'p'];
                            ret.displayName = newColName.join('').toUpperCase();
                            ret.width = '*';
                        }
                        return ret;
                    }),
                    rows: _.map(table.slice(1), zipObject(keptHeader))
                };
            }

            // request JSON data
            Data.get({'id': $routeParams.id}, function (diffData) {
                if (!diffData || !_.contains(diffData.type, 'differentialexpression') || !_.contains(diffData.status, 'done')) {
                    notify({message: 'Bad data requested', type: 'error'});
                    return;
                }
                if (!diffData.output && diffData.output.diffexp && diffData.output.diffexp.file) {
                    notify({message: 'Differential Expressions file is missing in requested data', type: 'error'});
                    return;
                }
                // request tab-delimited file
                Data.download({'id': $routeParams.id, 'file': diffData.output.diffexp.file}, function (raw) {
                    var parsed = parseData(raw.data);

                    $scope.columnDefs = parsed.cols;
                    $scope.shared.data = parsed.rows;
                    $scope.shared.filteredRows = parsed.rows;
                    $scope.gridVisible = true;

                }, notify.error('get Differential Expressions file'));
            }, notify.error('get Differential Expressions data'));

            $scope.selectedItems = [];
            $scope.gridOptions = {
                data: 'shared.filteredRows',
                filterOptions: { filterText: '', useExternalFilter: true},
                selectedItems: $scope.selectedItems,
                multiSelect: false,
                columnDefs: 'columnDefs'
            };
            $scope.$watchCollection('selectedItems', function (items) {
                $scope.shared.selectedRow = items.length>0 && items[0];
            });

            function refilter() {
                if (!$scope.shared.filteredRows) return;
                $scope.shared.filteredRows = filterByFieldText($scope.shared.data, $scope.gridOptions.filterOptions.filterText, false, true);
            }
            $scope.$watch('gridOptions.filterOptions.filterText', refilter);
            $scope.$watchCollection('shared.data', refilter);

            $scope.$watchCollection('shared.selectedGenes', function (rows) {
                if (!$scope.gridVisible) return;

                var setSelected = _.partialRight($scope.gridOptions.selectItem, true);
                _.map(rows, _.compose(setSelected, $scope.shared.data.indexOf));
            });
        }]
    };
});
<|endoftext|>


<commit_before>console.log( "- easyscan.js START" );

var cell_position_map = { "location": 0, "call_number": 1, "barcode": 2, "availability": 3 }

$(document).ready(
  function() {
    // update_item_table();
    check_already_run();
  }
);

function check_already_run() {
  /* Checks to see if javascript has already been run.
   * Called by document.ready()
   */
  var all_html = $("body").html().toString();
  var index = all_html.indexOf( "Request Scan" );
  if (index != -1) {
    console.log( "- aready run" );
  } else {
    console.log( "- not already run" );
  grab_title();
  }
}

function grab_title() {
  /* Grabs bib title; then continues processing.
   * Called by check_already_run()
   */
  title = "foo-title";
  console.log( "- title, " + title );
  update_item_table( title );
}

function update_item_table( title ) {
  /* Updates bib-item list to show request-scan button.
   * Called by grab_title()
   */
  rows = $( ".bibItemsEntry" );  // jquery already loaded (whew)
  for (var i = 0; i < rows.length; i++) {
    row = rows[i];
    row_dict = extract_row_data( row );
    link_html = build_link_html( title, row_dict )
    last_cell = row.getElementsByTagName("td")[cell_position_map["availability"]];
    $( last_cell ).after( link_html );
    row.deleteCell( cell_position_map["barcode"] );
  }
  delete_header_cell();
}

function extract_row_data( row ) {
  /* Takes row dom-object; extracts and returns fielded data.
   * Called by update_item_table()
   */
  cells = row.getElementsByTagName("td");
  row_data = {}
  map_keys = Object.keys( cell_position_map );  // yeilds [ "location", "call_number", etc. ] - compatible with older browsers?
  for (var i = 0; i < map_keys.length; i++) {
    key = map_keys[i];
    value = cells[ cell_position_map[key] ].textContent.trim();
    row_data[key] = value;
  }
  console.log( "- row_data, " + JSON.stringify(row_data, null, 4) );
  return row_data;
}

function build_link_html( title, row_dict ) {
  /* Takes row dict; returns html link.
   * Called by extract_row_data()
   */
  link = 'Request Scan';
  link = link.replace( "THECALLNUMBER", row_dict["call_number"] );
  link = link.replace( "THEBARCODE", row_dict["barcode"] );
  link = link.replace( "THETITLE", title );
  console.log( "- link end, " + link );
  return link;
}

function delete_header_cell() {
  /* Deletes barcode header cell
   * Called by update_item_table()
   */
  header_row = $( "tr.bibItemsHeader" )[0];
  header_row.deleteCell( cell_position_map["barcode"] );
  console.log( "- barcode header cell deleted" );
}

console.log( "- easyscan.js END" );

// JSON.stringify(obj, null, 4)
<commit_msg>grabs real title.<commit_after>console.log( "- easyscan.js START" );

var cell_position_map = { "location": 0, "call_number": 1, "barcode": 2, "availability": 3 }

$(document).ready(
  function() {
    // update_item_table();
    check_already_run();
  }
);

function check_already_run() {
  /* Checks to see if javascript has already been run.
   * Called by document.ready()
   */
  var all_html = $("body").html().toString();  // jquery already loaded (whew)
  var index = all_html.indexOf( "Request Scan" );
  if (index != -1) {
    console.log( "- aready run" );
  } else {
    console.log( "- not already run" );
  grab_title();
  }
}

function grab_title() {
  /* Grabs bib title; then continues processing.
   * Called by check_already_run()
   */
  title_objs = $("tr").find("td").find("strong");
  title_obj = title_objs[0];
  title = title_obj.textContent.trim();
  console.log( "- title, " + title );
  update_item_table( title );
}

function update_item_table( title ) {
  /* Updates bib-item list to show request-scan button.
   * Called by grab_title()
   */
  rows = $( ".bibItemsEntry" );
  for (var i = 0; i < rows.length; i++) {
    row = rows[i];
    row_dict = extract_row_data( row );
    link_html = build_link_html( title, row_dict )
    last_cell = row.getElementsByTagName("td")[cell_position_map["availability"]];
    $( last_cell ).after( link_html );
    row.deleteCell( cell_position_map["barcode"] );
  }
  delete_header_cell();
}

function extract_row_data( row ) {
  /* Takes row dom-object; extracts and returns fielded data.
   * It runs through the labels of the `var cell_position_map` dict, and builds a row_data dict:
   *   each key is the label; each value is the correct cell's text.
   * Called by update_item_table()
   */
  cells = row.getElementsByTagName("td");
  row_data = {}
  map_keys = Object.keys( cell_position_map );  // yeilds [ "location", "call_number", etc. ] - compatible with older browsers?
  for (var i = 0; i < map_keys.length; i++) {
    key = map_keys[i];
    value = cells[ cell_position_map[key] ].textContent.trim();
    row_data[key] = value;
  }
  console.log( "- row_data, " + JSON.stringify(row_data, null, 4) );
  return row_data;
}

function build_link_html( title, row_dict ) {
  /* Takes row dict; returns html link.
   * Called by extract_row_data()
   */
  link = 'Request Scan';
  link = link.replace( "THECALLNUMBER", row_dict["call_number"] );
  link = link.replace( "THEBARCODE", row_dict["barcode"] );
  link = link.replace( "THETITLE", title );
  console.log( "- link end, " + link );
  return link;
}

function delete_header_cell() {
  /* Deletes barcode header cell
   * Called by update_item_table()
   */
  header_row = $( "tr.bibItemsHeader" )[0];
  header_row.deleteCell( cell_position_map["barcode"] );
  console.log( "- barcode header cell deleted" );
}

console.log( "- easyscan.js END" );

// JSON.stringify(obj, null, 4)
<|endoftext|>


<commit_before>/**
 * Shrimp Paste
 * ------------
 * This is the jQuery variant, supporting older broweser
 * don't need no jQuery? Try the plain version!
 */

 function shrimppasteclass() {

	'use strict';

	var self = this;

	this.steps = {}

	this.createNav = function(type, parent) {
		var button = $('');
		button.attr('href', '#');
		button.addClass('ShrimpPaste-button');
		button.addClass('ShrimpPaste-button--'+type);
		button.addClass('js-'+type);
		button.text(type);
		return button;
	}

	this.setAllNavActive = function(sliderEl) {
		sliderEl.find('.js-next').removeClass('ShrimpPaste-button--inActive');
		sliderEl.find('.js-prev').removeClass('ShrimpPaste-button--inActive');
	}

	this.setNavInactive =  function(event) {
		var button = $(event.target);
		button.addClass('ShrimpPaste-button--inActive');
	}

	this.handleSlideClick = function(event, direction, parent) {
		event.preventDefault();

		self.setAllNavActive(parent);

		if(direction === 'prev') {
			// Check if current step is possible
			if((self.steps.current + self.steps.width) <= 0){
				self.steps.current = self.steps.current + self.steps.width;

				// Check if *next* step is even possible
				if((self.steps.current + self.steps.width) > 0){
					self.setNavInactive(event);
				}
			}
			else {
				// Current step not possible, keep button inactive
				self.setNavInactive(event);
			}
		}
		else {
			// Check if current step is possible
			if(self.steps.current - self.steps.width >= -1 * self.steps.max){
				self.steps.current = self.steps.current - self.steps.width;

				// Check if *next* step is even possible
				if(self.steps.current - self.steps.width <= -1 * self.steps.max){
					self.setNavInactive(event);
				}
			}
			else {
				// Current step not possible, keep button inactive
				self.setNavInactive(event);
			}
		}

		var slidesWrap = parent.find('.js-shrimppaste-wrap');
		slidesWrap.css('transform', 'translateX('+self.steps.current+'px)');
	}

	this.build = function (sliderEl, opts) {
		var slidesViewport = sliderEl.find('.js-shrimppaste-viewport');
		var maxWidth = Math.round(slidesViewport.width());
		var slideWidth = Math.round(maxWidth / opts.slides);
		var slides = sliderEl.find('.js-shrimppaste-item');
		var totWidth = Math.round(slideWidth * slides.length);
		var slidesWrap = sliderEl.find('.js-shrimppaste-wrap');

		slidesWrap.css('width', totWidth.toString() + 'px');
		sliderEl.addClass('is-active');
		self.steps.width = slideWidth;
		self.steps.max = totWidth - maxWidth;
		self.steps.current = 0;

		if(self.steps.max > slideWidth) {
			var prevButton = self.createNav('prev',sliderEl);
			var nextButton = self.createNav('next',sliderEl);
			sliderEl.append(prevButton);
			sliderEl.append(nextButton);

			prevButton.addClass('ShrimpPaste-button--inActive');

			nextButton.on('click', function(event){ self.handleSlideClick(event, 'next', sliderEl); });
			prevButton.on('click', function(event){ self.handleSlideClick(event, 'prev', sliderEl); });
		}

		slides.each(function() {
			$(this).css('width', slideWidth.toString() +'px');
		});
	}

};

window.shrimppaste = (function (window, document, undefined) {

	'use strict';

	var shrimppaste = {
		steps : {}
	}

	shrimppaste.init = function (opts) {
		$('.js-shrimppaste').each(function(){
			var shrimppasteinstance = new shrimppasteclass();
			shrimppasteinstance.build($(this), opts);
		});
	}

	return shrimppaste;

})(window, document);

shrimppaste.init({ 'slides' : 4 });
<commit_msg>Remove obsolete function call.<commit_after>/**
 * Shrimp Paste
 * ------------
 * This is the jQuery variant, supporting older broweser
 * don't need no jQuery? Try the plain version!
 */

 function shrimppasteclass() {

	'use strict';

	var self = this;

	this.steps = {}

	this.createNav = function(type, parent) {
		var button = $('');
		button.attr('href', '#');
		button.addClass('ShrimpPaste-button');
		button.addClass('ShrimpPaste-button--'+type);
		button.addClass('js-'+type);
		button.text(type);
		return button;
	}

	this.setAllNavActive = function(sliderEl) {
		sliderEl.find('.js-next').removeClass('ShrimpPaste-button--inActive');
		sliderEl.find('.js-prev').removeClass('ShrimpPaste-button--inActive');
	}

	this.setNavInactive =  function(event) {
		var button = $(event.target);
		button.addClass('ShrimpPaste-button--inActive');
	}

	this.handleSlideClick = function(event, direction, parent) {
		event.preventDefault();

		self.setAllNavActive(parent);

		if(direction === 'prev') {
			// Check if current step is possible
			if((self.steps.current + self.steps.width) <= 0){
				self.steps.current = self.steps.current + self.steps.width;

				// Check if *next* step is even possible
				if((self.steps.current + self.steps.width) > 0){
					self.setNavInactive(event);
				}
			}
			else {
				// Current step not possible, keep button inactive
				self.setNavInactive(event);
			}
		}
		else {
			// Check if current step is possible
			if(self.steps.current - self.steps.width >= -1 * self.steps.max){
				self.steps.current = self.steps.current - self.steps.width;

				// Check if *next* step is even possible
				if(self.steps.current - self.steps.width <= -1 * self.steps.max){
					self.setNavInactive(event);
				}
			}
			else {
				// Current step not possible, keep button inactive
				self.setNavInactive(event);
			}
		}

		var slidesWrap = parent.find('.js-shrimppaste-wrap');
		slidesWrap.css('transform', 'translateX('+self.steps.current+'px)');
	}

	this.build = function (sliderEl, opts) {
		var slidesViewport = sliderEl.find('.js-shrimppaste-viewport');
		var maxWidth = Math.round(slidesViewport.width());
		var slideWidth = Math.round(maxWidth / opts.slides);
		var slides = sliderEl.find('.js-shrimppaste-item');
		var totWidth = Math.round(slideWidth * slides.length);
		var slidesWrap = sliderEl.find('.js-shrimppaste-wrap');

		slidesWrap.css('width', totWidth.toString() + 'px');
		sliderEl.addClass('is-active');
		self.steps.width = slideWidth;
		self.steps.max = totWidth - maxWidth;
		self.steps.current = 0;

		if(self.steps.max > slideWidth) {
			var prevButton = self.createNav('prev',sliderEl);
			var nextButton = self.createNav('next',sliderEl);
			sliderEl.append(prevButton);
			sliderEl.append(nextButton);

			prevButton.addClass('ShrimpPaste-button--inActive');

			nextButton.on('click', function(event){ self.handleSlideClick(event, 'next', sliderEl); });
			prevButton.on('click', function(event){ self.handleSlideClick(event, 'prev', sliderEl); });
		}

		slides.each(function() {
			$(this).css('width', slideWidth.toString() +'px');
		});
	}

};

window.shrimppaste = (function (window, document, undefined) {

	'use strict';

	var shrimppaste = {
		steps : {}
	}

	shrimppaste.init = function (opts) {
		$('.js-shrimppaste').each(function(){
			var shrimppasteinstance = new shrimppasteclass();
			shrimppasteinstance.build($(this), opts);
		});
	}

	return shrimppaste;

})(window, document);
<|endoftext|>