<commit_before>/*
	drawdiv.js is able to draw as many divs as you want inside an other div.
	If you want to change the rootdiv, just call changeRootDiv(newRootDiv).
*/

//settings
var rootDivId ='annotationZone';
var rootDivDom = $('#annotationZone');
var rectPrefix = "rect-";
var rectSpanPrefix = "rectspan-";
var divCounter = 0;
var drag = false;

var startXRel;
var startYRel;

var opacityFactor ="0.125";
var opacityFactorHighlight ="0.5";

//Random Values
var tagFontSize = 1;
var tagIffsetTop =4;

var currentCanvasHeight=0;
var min_height_rect_rel=0.06;
var max_height_rect_rel=0.55;
var min_width_rect_rel=0.06;
var max_width_rect_rel=0.75;

var min_height_rect_abs=50;
var max_height_rect_abs=300;
var min_width_rect_abs=50;
var max_width_rect_abs=300;

var currentTagName="";
var currentTagColor="#1E90FF";

var bWidth ="3";
var bRadius = "4";

function absToViewTop(relToView,canvas){
	//console.log(rootDivDom.offset().top);
	return rootDivDom.offset().top+parseInt(relToView,10);
}
function absToViewLeft(relToView,canvas){
	//console.log("CHECK: "+ relToView);
	return rootDivDom.offset().left+parseInt(relToView,10);
}

function getCurrentTagName(){
	return currentTagName;
}

function setCurrentTagName(tTagName){
	currentTagName=tTagName;
}
function getCurrentTagColor(){
	return currentTagColor;
}
function setCurrentTagColor(tTagColor){
	currentTagColor=tTagColor;
}

function initRects() {
	//rootDivDom.bind('mousedown', mouseDown);
	//rootDivDom.bind('mouseup', mouseUp);
	//rootDivDom.bind('mousemove', mouseMove);
	//rootDivDom.bind('mouseleave', mouseLeave);
}
function appendClickEventOnRect(){
	$(".slideRect").each(function(){
		$(this).click(function(){
			var text = $(".activeTextArea").val();
			if(text.slice(-1)==" "){
				$(".activeTextArea").val( text+ $(this).attr("data-tagName"));
			}else{
				$(".activeTextArea").val( text+ " "+ $(this).attr("data-tagName"));
			}

		});
	});
}

function mouseDown(e){
	if(e.which!=3){

		if(e.pageX - rootDivDom.offset().left > (min_width_rect_abs/2)){
			if(e.pageX - rootDivDom.offset().left< parseInt(rootDivDom.width())- (min_width_rect_abs/2)){
				startXRel = e.pageX - rootDivDom.offset().left - (min_width_rect_abs/2);
			}else{
				startXRel = parseInt(rootDivDom.width())- min_width_rect_abs;

			}
		}else{
			startXRel = 0;
		}
		if(e.pageY - rootDivDom.offset().top > (min_height_rect_abs/2)){
			if(e.pageY - rootDivDom.offset().top< parseInt(rootDivDom.height())- (min_height_rect_abs/2)){
				startYRel = e.pageY - rootDivDom.offset().top - (min_height_rect_abs/2);
			}else{
				startYRel = parseInt(rootDivDom.height())- min_height_rect_abs;
			}
		}else{
			startYRel = 0;
		}

		//creating Div with default values
		element = $('<div/>', {
			id: rectPrefix+divCounter,
			position: 'absolute',
			class: 'slideRect debug',
			opacity: opacityFactorHighlight
		});
 //CHANGE LATER
		element.css({
			position: 'absolute',
			backgroundColor: getCurrentTagColor(),
			borderRadius: bWidth+"px solid #C1E0FF",
		});

		//tag
		element.attr("data-tagName","#"+getCurrentTagName());

		//setting drawed div on activeRects
		element.className = element.className+ " activeRect tagname-"+element.attr("data-tagName").slice(1);

		//transition //CHECK IF THIS LINES ARE CORRECT
		element.prop("-moz-transition", "opacity 0.1s linear");
		element.prop("-ms-transition", "opacity 0.1s linear");
		element.prop("-o-transition", "opacity 0.1s linear");
		element.prop("transition", "opacity 0.1s linear");

		element.attr("data-relstartcoord",(startXRel+";"+startYRel));

		element.offset({left: absToViewLeft(startXRel, this)});
		element.offset({top: absToViewLeft(startYRel, this)});
		element.width(min_width_rect_abs);
		element.height(min_height_rect_abs);
		element.appendTo('#annotationZone');

		appendClickEventOnRect();
		drag=true;
	}

}

function mouseUp(e){
		element.appendTo('#annotationZone');
	/*elementTag.style.opacity = 0;
	if(animation){
				var tl = new TimelineMax();
				tl.append(TweenMax.fromTo("#"+element.id,.15, {scale:1.02}, {css:{scale:1}, ease:Quad.easeIn}));
				oTransitionRect(element.id,"tagname-"+element.getAttribute("data-tagName").slice(1), opacityFactor, opacityFactorHighlight);
	}
	canvas.style.cursor = "default";*/
	divCounter=divCounter+1;
  drag = false;

	addAnnotationZoneElement(element);
}

function mouseMove(e){
	if (drag) {
  	var currentX = e.pageX - rootDivDom.offset().left;
  	var currentY = e.pageY - rootDivDom.offset().top;
   	var divWidth = currentX - startXRel;
    var divHeight = currentY - startYRel;
    var relSaveX=0;
    var relSaveY=0;

    if(currentX - startXRel < 0){
	    if((max_width_rect_abs-min_width_rect_abs)<Math.abs(currentX - startXRel)){
	    	relSaveX = startXRel-(max_width_rect_abs-min_width_rect_abs);
	    	element.offset({left: rootDivDom.offset().left+ relSaveX});
	    	//elementTag.style.left = this.offsetLeft + relSaveX +tagOffsetLeft+ 'px';
	    	divWidth = max_width_rect_abs;
	    }else{
	    	relSaveX =currentX;
				element.offset({left: rootDivDom.offset().left+ relSaveX});
	    	//elementTag.style.left = this.offsetLeft + relSaveX +tagOffsetLeft+ 'px';
	    	divWidth = Math.abs(currentX - startXRel)+ min_width_rect_abs;
	    }
    }else{
    	if((currentX-startXRel)<min_width_rect_abs){
    		relSaveX =startXRel;
				element.offset({left: rootDivDom.offset().left+ relSaveX});
    		//elementTag.style.left =this.offsetLeft+relSaveX +tagOffsetLeft+ 'px';
    		divWidth = min_width_rect_abs;
    	}else{
    		relSaveX=startXRel;
	    	element.offset({left: rootDivDom.offset().left+ relSaveX});
	    	//elementTag.style.left = this.offsetLeft+relSaveX+tagOffsetLeft + 'px';
    		if((currentX-startXRel)>max_width_rect_abs){
    			divWidth= max_width_rect_abs;
    		}else{
    			divWidth = currentX-startXRel;
    		}
    	}

    }
    element.width (Math.abs(divWidth));

    if(currentY - startYRel < 0){
	    if((max_height_rect_abs-min_height_rect_abs)<Math.abs(currentY - startYRel)){
	    	relSaveY = startYRel-(max_height_rect_abs-min_height_rect_abs);
				element.offset({top: rootDivDom.offset().top+ relSaveY});
	    	//elementTag.style.top = this.offsetTop + relSaveY -tagOffsetTop + 'px';
	    	divHeight = max_height_rect_abs;
	    }else{
	    	relSaveY =currentY;
	    	element.offset({top: rootDivDom.offset().top+ relSaveY});
				//elementTag.style.top = this.offsetTop + relSaveY -tagOffsetTop + 'px';

	    	divHeight = Math.abs(currentY - startYRel)+ min_height_rect_abs;
	    }
    }else{
    	if((currentY-startYRel)<min_height_rect_abs){
    		relSaveY =startYRel;
				element.offset({top: startYRel+  rootDivDom.offset().top});
    		//elementTag.style.top =this.offsetTop+ relSaveY -tagOffsetTop + 'px';
    		divHeight = min_height_rect_abs;
    	}else{
    		relSaveY = startYRel;

				element.offset({top: rootDivDom.offset().top+ relSaveY});
	    	//elementTag.style.top = this.offsetTop+relSaveY-tagOffsetTop + 'px';
    		if((currentY-startYRel)>max_height_rect_abs){
    			divHeight= max_height_rect_abs;
    		}else{
    			divHeight = currentY-startYRel;
    		}
    	}

    }
    element.height(Math.abs(divHeight));

    element.attr("data-relwidthheight", Math.abs(divWidth)+";"+Math.abs(divHeight));
    element.attr("data-relstartcoord", relSaveX +";"+relSaveY);
  }

}

function mouseLeave(e){
	if(drag){mouseleftCanvas=true;}
}

function rescalingRects(rectClassName,tagClassName){
	var allElements = $("."+rectClassName);
	var scalingFactor = parseInt(rootDivDom.height())/currentCanvasHeight;
	//console.log("height "+ rootDivDom.height() + " currentCanvasHeight"+ currentCanvasHeight)
	/*var allElementsTag = $("."+tagClassName);
	tagFontSize = parseInt(rootDivDom.height())*tagFontSizeFactor;*/
	tagOffsetTop = tagFontSize+4;
	//console.log("Scaling factor: "+scalingFactor);

	for (var i = 0, len = allElements.length; i < len; i++) {
		var coordAttr=$(allElements[i]).attr("data-relstartcoord").split(";");
		var startXAttr = coordAttr[0]*scalingFactor;
		var startYAttr = coordAttr[1]*scalingFactor;
  	$(allElements[i]).attr("data-relstartcoord",startXAttr+";"+startYAttr);
		$(allElements[i]).css('left',  Math.round(startXAttr));
		$(allElements[i]).css('top',  Math.round(startYAttr));
  	$(allElements[i]).css('height',  Math.round(parseInt($(allElements[i]).css('height'))*scalingFactor));
		$(allElements[i]).css('width',   Math.round(parseInt($(allElements[i]).css('width'))*scalingFactor));
	}
	currentCanvasHeight=parseInt(rootDivDom.height());
}

function alwaysRescaleRects(){
	rescalingRects("slideRect", "slideRectTag");
	currentCanvasHeight=parseInt(rootDivDom.height());

	//tagFontSize = currentCanvasHeight*tagFontSizeFactor;
	//tagOffsetTop = tagFontSize+4;

	min_height_rect_abs=currentCanvasHeight*min_height_rect_rel;
	max_height_rect_abs=currentCanvasHeight*max_height_rect_rel;
	min_width_rect_abs=currentCanvasHeight*min_width_rect_rel;
	max_width_rect_abs=currentCanvasHeight*max_width_rect_rel;
}

function loadRect(relLeft, relTop, relWidth, relHeight, color, tagname, canMove){
	//creating Div with default values
	element = $('<div/>', {
		movable: "",
		"can-move": canMove,
		id: rectPrefix+divCounter,
		position: 'absolute',
		class: 'slideRect ',
		opacity: opacityFactorHighlight
	});
//CHANGE LATER
	element.css({
		position: 'absolute',
		backgroundColor: getCurrentTagColor(),

	});

	//tag
	element.attr("data-tagName","#"+tagname);

//tagspan element
		spanElement = $('<span/>', {
			id: rectSpanPrefix+divCounter
		});
		if(!canMove)
			spanElement.text(tagname);
		else
			spanElement.text("#{{storedAnnZones['"+ rectPrefix+divCounter +"']}}");
		element.append(spanElement);
	//transition //CHECK IF THIS LINES ARE CORRECT
	element.prop("-moz-transition", "opacity 0.1s linear");
	element.prop("-ms-transition", "opacity 0.1s linear");
	element.prop("-o-transition", "opacity 0.1s linear");
	element.prop("transition", "opacity 0.1s linear");

	var currCanWidth = rootDivDom.width();

	var attrRelLeft = relLeft*currCanWidth;
	var currCanHeight =rootDivDom.height();
	var attrRelTop  = relTop* currCanHeight;
	element.attr("data-relstartcoord",(attrRelLeft+";"+attrRelTop));
	element.offset({left: absToViewLeft(attrRelLeft, this)});
	element.offset({top: absToViewLeft(attrRelTop, this)});
	element.css('height',  currCanHeight*relHeight);
	element.css('width',   currCanWidth*relWidth);
	element.css('opacity', opacityFactor)

	element.hover(function(){
		$(this).stop().fadeTo("fast", opacityFactorHighlight);
		$(this).find(".slideRectSpan").stop().fadeTo("fast",1.0); //can be deleted because parent inherit its opacity
	}, function(){
		$(this).stop().fadeTo("fast",opacityFactor);
		$(this).find(".slideRectSpan").stop().fadeTo("fast",opacityFactor);//can be deleted because parent inherit its opacity
	});

	//tagspan element
			spanElement = $('<span/>', {
				id: rectSpanPrefix+divCounter,
				class: 'slideRectSpan'
			});
			spanElement.text("TEXT");
			element.append(spanElement);

	element = angular.element($("#annZoneList")).scope().compileMovableAnnotationZone(element);

	element.appendTo('#annotationZone');
	divCounter=divCounter+1;

	return element;

}

//console.log("test: "+rootDivDom.height());
initRects();

window.onresize = function(){
  		alwaysRescaleRects();
}
<commit_msg>Small fix<commit_after>/*
	drawdiv.js is able to draw as many divs as you want inside an other div.
	If you want to change the rootdiv, just call changeRootDiv(newRootDiv).
*/

//settings
var rootDivId ='annotationZone';
var rootDivDom = $('#annotationZone');
var rectPrefix = "rect-";
var rectSpanPrefix = "rectspan-";
var divCounter = 0;
var drag = false;

var startXRel;
var startYRel;

var opacityFactor ="0.125";
var opacityFactorHighlight ="0.5";

//Random Values
var tagFontSize = 1;
var tagIffsetTop =4;

var currentCanvasHeight=0;
var min_height_rect_rel=0.06;
var max_height_rect_rel=0.55;
var min_width_rect_rel=0.06;
var max_width_rect_rel=0.75;

var min_height_rect_abs=50;
var max_height_rect_abs=300;
var min_width_rect_abs=50;
var max_width_rect_abs=300;

var currentTagName="";
var currentTagColor="#1E90FF";

var bWidth ="3";
var bRadius = "4";

function absToViewTop(relToView,canvas){
	//console.log(rootDivDom.offset().top);
	return rootDivDom.offset().top+parseInt(relToView,10);
}
function absToViewLeft(relToView,canvas){
	//console.log("CHECK: "+ relToView);
	return rootDivDom.offset().left+parseInt(relToView,10);
}

function getCurrentTagName(){
	return currentTagName;
}

function setCurrentTagName(tTagName){
	currentTagName=tTagName;
}
function getCurrentTagColor(){
	return currentTagColor;
}
function setCurrentTagColor(tTagColor){
	currentTagColor=tTagColor;
}

function initRects() {
	//rootDivDom.bind('mousedown', mouseDown);
	//rootDivDom.bind('mouseup', mouseUp);
	//rootDivDom.bind('mousemove', mouseMove);
	//rootDivDom.bind('mouseleave', mouseLeave);
}
function appendClickEventOnRect(){
	$(".slideRect").each(function(){
		$(this).click(function(){
			var text = $(".activeTextArea").val();
			if(text.slice(-1)==" "){
				$(".activeTextArea").val( text+ $(this).attr("data-tagName"));
			}else{
				$(".activeTextArea").val( text+ " "+ $(this).attr("data-tagName"));
			}

		});
	});
}

function mouseDown(e){
	if(e.which!=3){

		if(e.pageX - rootDivDom.offset().left > (min_width_rect_abs/2)){
			if(e.pageX - rootDivDom.offset().left< parseInt(rootDivDom.width())- (min_width_rect_abs/2)){
				startXRel = e.pageX - rootDivDom.offset().left - (min_width_rect_abs/2);
			}else{
				startXRel = parseInt(rootDivDom.width())- min_width_rect_abs;

			}
		}else{
			startXRel = 0;
		}
		if(e.pageY - rootDivDom.offset().top > (min_height_rect_abs/2)){
			if(e.pageY - rootDivDom.offset().top< parseInt(rootDivDom.height())- (min_height_rect_abs/2)){
				startYRel = e.pageY - rootDivDom.offset().top - (min_height_rect_abs/2);
			}else{
				startYRel = parseInt(rootDivDom.height())- min_height_rect_abs;
			}
		}else{
			startYRel = 0;
		}

		//creating Div with default values
		element = $('<div/>', {
			id: rectPrefix+divCounter,
			position: 'absolute',
			class: 'slideRect debug',
			opacity: opacityFactorHighlight
		});
 //CHANGE LATER
		element.css({
			position: 'absolute',
			backgroundColor: getCurrentTagColor(),
			borderRadius: bWidth+"px solid #C1E0FF",
		});

		//tag
		element.attr("data-tagName","#"+getCurrentTagName());

		//setting drawed div on activeRects
		element.className = element.className+ " activeRect tagname-"+element.attr("data-tagName").slice(1);

		//transition //CHECK IF THIS LINES ARE CORRECT
		element.prop("-moz-transition", "opacity 0.1s linear");
		element.prop("-ms-transition", "opacity 0.1s linear");
		element.prop("-o-transition", "opacity 0.1s linear");
		element.prop("transition", "opacity 0.1s linear");

		element.attr("data-relstartcoord",(startXRel+";"+startYRel));

		element.offset({left: absToViewLeft(startXRel, this)});
		element.offset({top: absToViewLeft(startYRel, this)});
		element.width(min_width_rect_abs);
		element.height(min_height_rect_abs);
		element.appendTo('#annotationZone');

		appendClickEventOnRect();
		drag=true;
	}

}

function mouseUp(e){
		element.appendTo('#annotationZone');
	/*elementTag.style.opacity = 0;
	if(animation){
				var tl = new TimelineMax();
				tl.append(TweenMax.fromTo("#"+element.id,.15, {scale:1.02}, {css:{scale:1}, ease:Quad.easeIn}));
				oTransitionRect(element.id,"tagname-"+element.getAttribute("data-tagName").slice(1), opacityFactor, opacityFactorHighlight);
	}
	canvas.style.cursor = "default";*/
	divCounter=divCounter+1;
  drag = false;

	addAnnotationZoneElement(element);
}

function mouseMove(e){
	if (drag) {
  	var currentX = e.pageX - rootDivDom.offset().left;
  	var currentY = e.pageY - rootDivDom.offset().top;
   	var divWidth = currentX - startXRel;
    var divHeight = currentY - startYRel;
    var relSaveX=0;
    var relSaveY=0;

    if(currentX - startXRel < 0){
	    if((max_width_rect_abs-min_width_rect_abs)<Math.abs(currentX - startXRel)){
	    	relSaveX = startXRel-(max_width_rect_abs-min_width_rect_abs);
	    	element.offset({left: rootDivDom.offset().left+ relSaveX});
	    	//elementTag.style.left = this.offsetLeft + relSaveX +tagOffsetLeft+ 'px';
	    	divWidth = max_width_rect_abs;
	    }else{
	    	relSaveX =currentX;
				element.offset({left: rootDivDom.offset().left+ relSaveX});
	    	//elementTag.style.left = this.offsetLeft + relSaveX +tagOffsetLeft+ 'px';
	    	divWidth = Math.abs(currentX - startXRel)+ min_width_rect_abs;
	    }
    }else{
    	if((currentX-startXRel)<min_width_rect_abs){
    		relSaveX =startXRel;
				element.offset({left: rootDivDom.offset().left+ relSaveX});
    		//elementTag.style.left =this.offsetLeft+relSaveX +tagOffsetLeft+ 'px';
    		divWidth = min_width_rect_abs;
    	}else{
    		relSaveX=startXRel;
	    	element.offset({left: rootDivDom.offset().left+ relSaveX});
	    	//elementTag.style.left = this.offsetLeft+relSaveX+tagOffsetLeft + 'px';
    		if((currentX-startXRel)>max_width_rect_abs){
    			divWidth= max_width_rect_abs;
    		}else{
    			divWidth = currentX-startXRel;
    		}
    	}

    }
    element.width (Math.abs(divWidth));

    if(currentY - startYRel < 0){
	    if((max_height_rect_abs-min_height_rect_abs)<Math.abs(currentY - startYRel)){
	    	relSaveY = startYRel-(max_height_rect_abs-min_height_rect_abs);
				element.offset({top: rootDivDom.offset().top+ relSaveY});
	    	//elementTag.style.top = this.offsetTop + relSaveY -tagOffsetTop + 'px';
	    	divHeight = max_height_rect_abs;
	    }else{
	    	relSaveY =currentY;
	    	element.offset({top: rootDivDom.offset().top+ relSaveY});
				//elementTag.style.top = this.offsetTop + relSaveY -tagOffsetTop + 'px';

	    	divHeight = Math.abs(currentY - startYRel)+ min_height_rect_abs;
	    }
    }else{
    	if((currentY-startYRel)<min_height_rect_abs){
    		relSaveY =startYRel;
				element.offset({top: startYRel+  rootDivDom.offset().top});
    		//elementTag.style.top =this.offsetTop+ relSaveY -tagOffsetTop + 'px';
    		divHeight = min_height_rect_abs;
    	}else{
    		relSaveY = startYRel;

				element.offset({top: rootDivDom.offset().top+ relSaveY});
	    	//elementTag.style.top = this.offsetTop+relSaveY-tagOffsetTop + 'px';
    		if((currentY-startYRel)>max_height_rect_abs){
    			divHeight= max_height_rect_abs;
    		}else{
    			divHeight = currentY-startYRel;
    		}
    	}

    }
    element.height(Math.abs(divHeight));

    element.attr("data-relwidthheight", Math.abs(divWidth)+";"+Math.abs(divHeight));
    element.attr("data-relstartcoord", relSaveX +";"+relSaveY);
  }

}

function mouseLeave(e){
	if(drag){mouseleftCanvas=true;}
}

function rescalingRects(rectClassName,tagClassName){
	var allElements = $("."+rectClassName);
	var scalingFactor = parseInt(rootDivDom.height())/currentCanvasHeight;
	//console.log("height "+ rootDivDom.height() + " currentCanvasHeight"+ currentCanvasHeight)
	/*var allElementsTag = $("."+tagClassName);
	tagFontSize = parseInt(rootDivDom.height())*tagFontSizeFactor;*/
	tagOffsetTop = tagFontSize+4;
	//console.log("Scaling factor: "+scalingFactor);

	for (var i = 0, len = allElements.length; i < len; i++) {
		var coordAttr=$(allElements[i]).attr("data-relstartcoord").split(";");
		var startXAttr = coordAttr[0]*scalingFactor;
		var startYAttr = coordAttr[1]*scalingFactor;
  	$(allElements[i]).attr("data-relstartcoord",startXAttr+";"+startYAttr);
		$(allElements[i]).css('left',  Math.round(startXAttr));
		$(allElements[i]).css('top',  Math.round(startYAttr));
  	$(allElements[i]).css('height',  Math.round(parseInt($(allElements[i]).css('height'))*scalingFactor));
		$(allElements[i]).css('width',   Math.round(parseInt($(allElements[i]).css('width'))*scalingFactor));
	}
	currentCanvasHeight=parseInt(rootDivDom.height());
}

function alwaysRescaleRects(){
	rescalingRects("slideRect", "slideRectTag");
	currentCanvasHeight=parseInt(rootDivDom.height());

	//tagFontSize = currentCanvasHeight*tagFontSizeFactor;
	//tagOffsetTop = tagFontSize+4;

	min_height_rect_abs=currentCanvasHeight*min_height_rect_rel;
	max_height_rect_abs=currentCanvasHeight*max_height_rect_rel;
	min_width_rect_abs=currentCanvasHeight*min_width_rect_rel;
	max_width_rect_abs=currentCanvasHeight*max_width_rect_rel;
}

function loadRect(relLeft, relTop, relWidth, relHeight, color, tagname, canMove){
	//creating Div with default values
	element = $('<div/>', {
		movable: "",
		"can-move": canMove,
		id: rectPrefix+divCounter,
		position: 'absolute',
		class: 'slideRect ',
		opacity: opacityFactorHighlight
	});
//CHANGE LATER
	element.css({
		position: 'absolute',
		backgroundColor: getCurrentTagColor(),

	});

	//tag
	element.attr("data-tagName","#"+tagname);

	//transition //CHECK IF THIS LINES ARE CORRECT
	element.prop("-moz-transition", "opacity 0.1s linear");
	element.prop("-ms-transition", "opacity 0.1s linear");
	element.prop("-o-transition", "opacity 0.1s linear");
	element.prop("transition", "opacity 0.1s linear");

	var currCanWidth = rootDivDom.width();

	var attrRelLeft = relLeft*currCanWidth;
	var currCanHeight =rootDivDom.height();
	var attrRelTop  = relTop* currCanHeight;
	element.attr("data-relstartcoord",(attrRelLeft+";"+attrRelTop));
	element.offset({left: absToViewLeft(attrRelLeft, this)});
	element.offset({top: absToViewLeft(attrRelTop, this)});
	element.css('height',  currCanHeight*relHeight);
	element.css('width',   currCanWidth*relWidth);
	element.css('opacity', opacityFactor)

	element.hover(function(){
		$(this).stop().fadeTo("fast", opacityFactorHighlight);
		$(this).find(".slideRectSpan").stop().fadeTo("fast",1.0); //can be deleted because parent inherit its opacity
	}, function(){
		$(this).stop().fadeTo("fast",opacityFactor);
		$(this).find(".slideRectSpan").stop().fadeTo("fast",opacityFactor);//can be deleted because parent inherit its opacity
	});

	//tagspan element
			spanElement = $('<span/>', {
				id: rectSpanPrefix+divCounter,
				class: 'slideRectSpan'
			});
			if(!canMove)
				spanElement.text(tagname);
			else
				spanElement.text("#{{storedAnnZones['"+ rectPrefix+divCounter +"']}}");
			element.append(spanElement);

	element = angular.element($("#annZoneList")).scope().compileMovableAnnotationZone(element);

	element.appendTo('#annotationZone');
	divCounter=divCounter+1;

	return element;

}

//console.log("test: "+rootDivDom.height());
initRects();

window.onresize = function(){
  		alwaysRescaleRects();
}
<|endoftext|>


<commit_before>if (process.env.NODE_ENV != "production") {
	require('dotenv').config();
}

assignments = [require('./assignments/assignment0.js')]

controller = require('botkit').slackbot({
	debug: false,
	storage: require('botkit-storage-redis')({
		url: process.env.REDIS_URL
	})
})

controller.spawn({
	token: process.env.SLACK_BOT_API_TOKEN
}).startRTM(function(err, bot, payload) {
	if (err) {
		console.log(err);
		throw new Error('Could not connect to Slack');
	} else {
		console.log("Connected to Slack");
	}
})

controller.hears(['submit ([0-9]+)(.*)'], ['direct_message'], function(bot, message) {
	assignmentNumber = message.match[1]
	if (assignmentNumber > assignments.length - 1) {
		bot.reply(message, "Sorry! That assignment isn't available yet. See what assignments are available with `assignments`.")
	} else {
		url = message.match[2].replace(/[<>]/g, "")
		bot.startPrivateConversation(message, function(err, convo) {
			if (err) {
				convo.say("Whoa, ran into an issue there. Try again?")
			} else {
				convo.say("Submitting " + url + " for Assignment #" + assignmentNumber + "...")
				assignments[parseInt(assignmentNumber)](url, function(err, scoreObject) {
					if (err) {
						convo.say("Error: " + err)
					} else {
						convo.say("Done processing. Your score is: " + scoreObject.score * 100 + "%")
						for (test of scoreObject.tests) {
							convo.say((test.passed ? ":white_check_mark:" : ":x:") + " " + test.description)
						}

						// write score
						controller.storage.users.get(message.user, function(err, user_data) {
							if (!("id" in user_data)) {
								user_data.id = message.user
							}
							if (!("assignments" in user_data)) {
								user_data.assignments = []
							}
							user_data.assignments[parseInt(assignmentNumber)] = scoreObject
							controller.storage.users.save(user_data, function(err) {
								if (err) {
									console.log(err);
									convo.say("Uh oh, we had a problem saving that grade. Try again?")
								} else {
									convo.say("Assignment grade saved!")
								}
							})
						});
					}
				})
			}
		})
	}
})

controller.hears(["assignments"], ["direct_message"], function(bot, message) {
	availableAssignments = []
	for (var i = 0; i < assignments.length; i++) {
		availableAssignments.push("`" + i + "`")
	}
	bot.reply(message, "Available assignments are: " + availableAssignments.join(" "))
})

controller.hears(["dump grades"], ["direct_message"], function(bot, message) {
	if (message.user == process.env.ADMIN_USER) {
		controller.storage.users.all(function(err, all_user_data) {
			bot.reply(message, "```" + JSON.stringify(all_user_data) + "```")
		});
	} else {
		bot.reply(message, "Insufficient permissions.")
	}
})

controller.hears(["grades", "grade"], ["direct_message"], function(bot, message) {
	bot.startPrivateConversation(message, function(err, convo) {
		convo.say("Looking up grades...")
		controller.storage.users.get(message.user, function(err, user_data) {
			if (!("assignments" in user_data) || (user_data.assignments.length == 0)) {
				convo.say("You haven't submitted any assignments yet.")
			} else {
				userScore = 0
				totalScore = 0
				for (var i = 0; i < user_data.assignments.length; i++) {
					if (user_data.assignments[i]) {
						convo.say("Assignment " + i + ": " + (user_data.assignments[i].score * 100) + "%")
						userScore += user_data.assignments[i].score * 100
					} else {
						convo.say("Assignment " + i + ": 0%")
						userScore += 0
					}
					totalScore += 100
				}
				convo.say("Total: " + ((userScore / totalScore) * 100) + "% _(" + userScore + "/" + totalScore + ")_")
			}
		});
	})
})

controller.hears(["help"], ["direct_message"], function(bot, message) {
	listOfCommands = [
		"submit <<assignmentNumber>> <<URL>>",
		"grades",
		"help"
	]
	for (var i = 0; i < listOfCommands.length; i++) {
		listOfCommands[i] = "`" + listOfCommands[i] + "`"
	}
	bot.reply(message, listOfCommands.join("\n"))
})

controller.hears(['.*'], ['direct_message'], function(bot, message) {
	bot.reply(message, "I'm sorry, I didn't quite understand that. For commands, type `help`")
})
<commit_msg>forgot assignments help<commit_after>if (process.env.NODE_ENV != "production") {
	require('dotenv').config();
}

assignments = [require('./assignments/assignment0.js')]

controller = require('botkit').slackbot({
	debug: false,
	storage: require('botkit-storage-redis')({
		url: process.env.REDIS_URL
	})
})

controller.spawn({
	token: process.env.SLACK_BOT_API_TOKEN
}).startRTM(function(err, bot, payload) {
	if (err) {
		console.log(err);
		throw new Error('Could not connect to Slack');
	} else {
		console.log("Connected to Slack");
	}
})

controller.hears(['submit ([0-9]+)(.*)'], ['direct_message'], function(bot, message) {
	assignmentNumber = message.match[1]
	if (assignmentNumber > assignments.length - 1) {
		bot.reply(message, "Sorry! That assignment isn't available yet. See what assignments are available with `assignments`.")
	} else {
		url = message.match[2].replace(/[<>]/g, "")
		bot.startPrivateConversation(message, function(err, convo) {
			if (err) {
				convo.say("Whoa, ran into an issue there. Try again?")
			} else {
				convo.say("Submitting " + url + " for Assignment #" + assignmentNumber + "...")
				assignments[parseInt(assignmentNumber)](url, function(err, scoreObject) {
					if (err) {
						convo.say("Error: " + err)
					} else {
						convo.say("Done processing. Your score is: " + scoreObject.score * 100 + "%")
						for (test of scoreObject.tests) {
							convo.say((test.passed ? ":white_check_mark:" : ":x:") + " " + test.description)
						}

						// write score
						controller.storage.users.get(message.user, function(err, user_data) {
							if (!("id" in user_data)) {
								user_data.id = message.user
							}
							if (!("assignments" in user_data)) {
								user_data.assignments = []
							}
							user_data.assignments[parseInt(assignmentNumber)] = scoreObject
							controller.storage.users.save(user_data, function(err) {
								if (err) {
									console.log(err);
									convo.say("Uh oh, we had a problem saving that grade. Try again?")
								} else {
									convo.say("Assignment grade saved!")
								}
							})
						});
					}
				})
			}
		})
	}
})

controller.hears(["assignments"], ["direct_message"], function(bot, message) {
	availableAssignments = []
	for (var i = 0; i < assignments.length; i++) {
		availableAssignments.push("`" + i + "`")
	}
	bot.reply(message, "Available assignments are: " + availableAssignments.join(" "))
})

controller.hears(["dump grades"], ["direct_message"], function(bot, message) {
	if (message.user == process.env.ADMIN_USER) {
		controller.storage.users.all(function(err, all_user_data) {
			bot.reply(message, "```" + JSON.stringify(all_user_data) + "```")
		});
	} else {
		bot.reply(message, "Insufficient permissions.")
	}
})

controller.hears(["grades", "grade"], ["direct_message"], function(bot, message) {
	bot.startPrivateConversation(message, function(err, convo) {
		convo.say("Looking up grades...")
		controller.storage.users.get(message.user, function(err, user_data) {
			if (!("assignments" in user_data) || (user_data.assignments.length == 0)) {
				convo.say("You haven't submitted any assignments yet.")
			} else {
				userScore = 0
				totalScore = 0
				for (var i = 0; i < user_data.assignments.length; i++) {
					if (user_data.assignments[i]) {
						convo.say("Assignment " + i + ": " + (user_data.assignments[i].score * 100) + "%")
						userScore += user_data.assignments[i].score * 100
					} else {
						convo.say("Assignment " + i + ": 0%")
						userScore += 0
					}
					totalScore += 100
				}
				convo.say("Total: " + ((userScore / totalScore) * 100) + "% _(" + userScore + "/" + totalScore + ")_")
			}
		});
	})
})

controller.hears(["help"], ["direct_message"], function(bot, message) {
	listOfCommands = [
		"submit <<assignmentNumber>> <<URL>>",
		"assignments",
		"grades",
		"help"
	]
	for (var i = 0; i < listOfCommands.length; i++) {
		listOfCommands[i] = "`" + listOfCommands[i] + "`"
	}
	bot.reply(message, listOfCommands.join("\n"))
})

controller.hears(['.*'], ['direct_message'], function(bot, message) {
	bot.reply(message, "I'm sorry, I didn't quite understand that. For commands, type `help`")
})
<|endoftext|>


<commit_before>/* http://developer.apple.com/safari/library/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/UsingtheJavascriptDatabase/UsingtheJavascriptDatabase.html */

function Migrator(db) {
    var migrations = [];
    var doReload = false;
    this.migration = function(number, func){
        migrations[number] = func;
    };
    var doMigration = function(number){
        if(migrations[number]){
            doReload = true;
            db.changeVersion(db.version, String(number), function(t){
                migrations[number](t);
            }, function(err){
                debug.log('DB changeVersion failed: ' + err.message);
            }, function(){
                debug.log('DB migration to ' + String(number) + ' successfull');
                doMigration(number+1);
            });
        } else {
            // migration done, reload
            if(doReload) {
                debug.log('reloading');
                window.location.reload(true);
            }
        }
    };
    this.doIt = function(){
        var initialVersion = parseInt(db.version) || 0;
        try {
            doMigration(initialVersion+1);
        } catch(e) {
            debug.log(e);
        }
    }
}

RadioDb = function() {

    var that = this;

    var db = null;

    var defaultStations = [
    ['DRS 1',        'http://stream.srg-ssr.ch/drs1/mp3_128.m3u', 'a'],
    ['DRS 2', 'http://stream.srg-ssr.ch/drs2/mp3_128.m3u', 'a'],
    ['DRS 3', 'http://stream.srg-ssr.ch/drs3/mp3_128.m3u', 'a'],
    ['DRS Virus',         'http://zlz-stream12.streamserver.ch/1/drsvirus/mp3_128', 'a'],
    ['Couleur 3',         'http://broadcast.infomaniak.net:80/rsr-couleur3-high.mp3', 'a'],
    ['Radio 1',           'http://stream.radio1.ch:8000/radio1', 'a'],
    ['Energy Zürich',     'http://statslive.infomaniak.ch/playlist/energyzuerich/energyzuerich-high.mp3/playlist.pls', 'a'],
    ['Energy Bern',       'http://statslive.infomaniak.ch/playlist/energybern/energybern-high.mp3/playlist.pls', 'a'],
    ['Radio Swiss Jazz',  'http://www.radioswissjazz.ch/live/mp3.m3u', 'a'],
    ['Radio Swiss Clas…', 'http://www.radioswissclassic.ch/live/mp3.m3u', 'a'],
    ['Rock Nation',       'http://105-stream-02.datacomm.ch:8000/rocknation', 'a'],
    ['RSR La Première',   'http://broadcast.infomaniak.net:80/rsr-la1ere-high.mp3', 'a'],
    ['Option Musique',    'http://broadcast.infomaniak.ch/rsr-optionmusique-high.mp3', 'a'],
    ['Frequence Banane',  'http://www.frequencebanane.ch/fb_128.m3u', 'a'],
    ['Backstageradio',    'http://broadcast.infomaniak.ch/backstageradio-high.mp3.m3u','a'],
    ['Radio 105',         'http://212.40.5.105:7000/listen.pls','a'],
    ['neo1',              'http://stream-02.neo1.ch/neo1.m3u','b'],
    ['Lounge-radio.com',  'http://www.lounge-radio.com/listen128.m3u','b'],
	['Radio Top',         'http://icecast.radiotop.ch/radiotop','b'],
	['MagicRadio.CH',     'http://www.magicradio.ch/iphoneAac.m3u','b'],
	['Radio FM1',         'http://radiofm1.ice.infomaniak.ch/playlists/radiofm1-128.mp3.pls','b'],
    ['Radio Swiss Pop',   'http://www.radioswisspop.ch/live/mp3.m3u','a'],
    ['DRS Musikwelle',     'http://stream.srg-ssr.ch/drsmw/mp3_128.m3u','a']
    ];

    var ERR_NONDB = 0;
    var ERR_OTHER = 1;
    var ERR_VERSION_MISMATCH = 2;
    var ERR_RESULTSIZE_EXCEEDED = 3;
    var ERR_MAXSIZE_EXCEEDED = 4;
    var ERR_LOCK_ERROR = 5; // contention
    var ERR_CONSTRAINT = 6;

    var upgradeSuccess = function() { debug.log('Successfully upgraded db.'); };
    var upgradeError = function(error) { debug.log('Failed upgrading db.'); return true; /* treat all errs as fatal */ };
    /** Return TRUE for fatal error */
    var errorHandler = function(t, error) {
        if(error.code == ERR_VERSION_MISMATCH) {
            // well, we just log&ignore it.. safari doesn't see the changeVersion effect until restart Oo
            debug.log('ERR_VERSION_MISMATCH');
            return false;
        }
        debug.log('Whoops, DB error: ' + error.message + ' (' + error.code + ')');
        return true; // fatal error
    };

    /** This is used as a data handler for a request that should return no data. */
    var nullDataHandler = function(t, results) {
        return false;
    };

    var insertDefaults = function(t) {
        var insertquery = 'INSERT INTO stations(name, stream, logo, listened_at) VALUES(?, ?, ?, NULL);';
        var selectquery = 'SELECT id, name FROM stations';
        var updatequery = 'UPDATE stations SET stream = ?, logo = ? where id = ?';
        var defaultStationsName = [];
        for( var i=0; i < defaultStations.length; ++i ) {
            defaultStationsName[defaultStations[i][0]] = defaultStations[i];
            //first we try to insert, then update, this could be improved
            t.executeSql(insertquery, defaultStations[i], nullDataHandler, errorHandler);
            t.executeSql(selectquery, [] , function(t, results) {
                if (results.rows.length == 0) {
                    //
                } else {

                    for (var j = 0; j < results.rows.length; ++j) {
                        var row = results.rows.item(j);
                        var station = defaultStationsName[row['name']];
                        t.executeSql(updatequery,[station[1],station[2],row['id']], nullDataHandler, function(t,error) {debug.log("ERRROR UPDATE");debug.log(error); return true});

                    }

                }
            },
            errorHandler
            );
        }
    };

    this.init = function() {
        try {
            if(!window.openDatabase) {
                alert('Ihr Browser unterstützt kein Local Storage');
            } else {
                db = openDatabase('radios_db', '1', 'Radios Database', 524288); // 512KiB
                debug.log('Current DB Version: ' + db.version);
                db.transaction(function(t) {
                    t.executeSql('CREATE TABLE IF NOT EXISTS stations (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE ON CONFLICT IGNORE, stream TEXT NOT NULL, logo TEXT NOT NULL, listened_at DATE )',
                    [], insertDefaults, errorHandler);
                });
                /*
                db = openDatabase('radios_db', '', 'Radios Database', 524288); // 512KiB
                debug.log('Current DB Version: ' + db.version);
                var M = new Migrator(db);
                M.migration(1, function(t) {
                    debug.log('ONE');
                    t.executeSql('CREATE TABLE stations(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE ON CONFLICT IGNORE, stream TEXT NOT NULL, logo TEXT NOT NULL, listened_at DATE )',
                    [], insertDefaults, errorHandler);
                });
                M.doIt();
                */
            }
            return db;
        } catch(e) {
            if(e.code == ERR_VERSION_MISMATCH) {
                debug.log('ERR_VERSION_MISMATCH');
            } else {
                alert('Error: ' + e);
            }
        }
    };

    this.updateListenAt = function(id) {
        db.transaction(function(t) {
            t.executeSql('UPDATE stations SET listened_at = datetime("now","localtime") WHERE id = ?', [ id ], nullDataHandler, errorHandler);
        });
    };

    this.getLastListenedStation = function(resultHandler) {
        db.transaction(function(t) {
            t.executeSql("SELECT id, name, stream, logo, listened_at FROM stations ORDER BY listened_at DESC LIMIT 1", [] , function(t, results) {
                resultHandler( results.rows.length == 0 ? null : results.rows.item(0) );
            }, errorHandler);
        });
    };

    var getStation = function(id, resultHandler, doUpdateListen) {
        if( doUpdateListen )
            that.updateListenAt(id);

        db.transaction(function(t) {
            t.executeSql("SELECT id, name, stream, logo, listened_at FROM stations WHERE id = ?", [ id ] , function(t, results) {
                resultHandler( results.rows.length == 0 ? null : results.rows.item(0) );
            }, errorHandler);
        });
    };

    var getStations = function(resultHandler, filter) {
        var where = '';
        if ( filter ) {
            where = " WHERE name LIKE '%" + filter + "%';"; // FIXME EEEEESCAPE!
        }
        db.transaction(function(t) {
            t.executeSql("SELECT id, name, stream, logo, listened_at FROM stations " + where + " ORDER BY logo ASC, name ASC", [ ] , function(t, results) {
                resultHandler(results.rows);
            }, errorHandler);
        });
    };

    this.insertStation = function(station) {
        db.transaction(function(t) {
            t.executeSql('INSERT INTO stations(name, stream, logo, listened_at) VALUES(?, ?, ?, NULL);', [ station.name, station.stream, station.logo ], nullDataHandler, errorHandler);
        });
    };

    this.autoSearch = function() {
        var searchel = document.getElementById('search-field');
        searchel.onkeyup = function(ev) {
            that.populateStations(searchel.value);
        };
    };

    this.populateStations = function(filter) {
        getStations(function(stations) {
            var ul = document.createElement('ul');
            var li, txt;
            var playing = document.createElement('span');
            var playingOn = document.createTextNode('On');
            playing.setAttribute('class', 'playing');
            playing.appendChild(playingOn);
            radio.playing = playing;
            for( var i=0; i<stations.length; ++i ) {
                li = document.createElement('li');
                txt = document.createTextNode(stations.item(i).name);
                li.appendChild(txt);
                li.setAttribute('id', 'station-'+ stations.item(i).id);
                li.onclick = function(ev) {

                    var id = this.getAttribute('id').split('-')[1];
                    getStation(id, function(station) {
                        var el = document.getElementById('station-'+station.id);

                        if (plugins.AudioStream.getStatus() == 'isPlaying' && station.name == radio.station) {
                            stopSound();
                        } else {
                            radio.station = station.name;
                            radio.stream = station.stream;
                            radio.playingEl = el;
                            radio.clear();
                            radio.noTrack(true);
                            playSound(station.stream);

                        }
                        // remove mute
                        document.getElementById("mute").setAttribute('class', '');
                    }, true);

                };
                ul.appendChild(li);
            }
            // remove current nav
            var statel = document.getElementById("scrollStations");
            if( statel.hasChildNodes() ) {
                while( statel.childNodes.length >= 1 )
                    statel.removeChild(statel.firstChild);
            }
            // append updated nav
            statel.appendChild(ul);
        }, filter);

    };
};

<commit_msg>Added Radio Zuerisee<commit_after>/* http://developer.apple.com/safari/library/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/UsingtheJavascriptDatabase/UsingtheJavascriptDatabase.html */

function Migrator(db) {
    var migrations = [];
    var doReload = false;
    this.migration = function(number, func){
        migrations[number] = func;
    };
    var doMigration = function(number){
        if(migrations[number]){
            doReload = true;
            db.changeVersion(db.version, String(number), function(t){
                migrations[number](t);
            }, function(err){
                debug.log('DB changeVersion failed: ' + err.message);
            }, function(){
                debug.log('DB migration to ' + String(number) + ' successfull');
                doMigration(number+1);
            });
        } else {
            // migration done, reload
            if(doReload) {
                debug.log('reloading');
                window.location.reload(true);
            }
        }
    };
    this.doIt = function(){
        var initialVersion = parseInt(db.version) || 0;
        try {
            doMigration(initialVersion+1);
        } catch(e) {
            debug.log(e);
        }
    }
}

RadioDb = function() {

    var that = this;

    var db = null;

    var defaultStations = [
    ['DRS 1',        'http://stream.srg-ssr.ch/drs1/mp3_128.m3u', 'a'],
    ['DRS 2', 'http://stream.srg-ssr.ch/drs2/mp3_128.m3u', 'a'],
    ['DRS 3', 'http://stream.srg-ssr.ch/drs3/mp3_128.m3u', 'a'],
    ['DRS Virus',         'http://zlz-stream12.streamserver.ch/1/drsvirus/mp3_128', 'a'],
    ['Couleur 3',         'http://broadcast.infomaniak.net:80/rsr-couleur3-high.mp3', 'a'],
    ['Radio 1',           'http://stream.radio1.ch:8000/radio1', 'a'],
    ['Energy Zürich',     'http://statslive.infomaniak.ch/playlist/energyzuerich/energyzuerich-high.mp3/playlist.pls', 'a'],
    ['Energy Bern',       'http://statslive.infomaniak.ch/playlist/energybern/energybern-high.mp3/playlist.pls', 'a'],
    ['Radio Swiss Jazz',  'http://www.radioswissjazz.ch/live/mp3.m3u', 'a'],
    ['Radio Swiss Clas…', 'http://www.radioswissclassic.ch/live/mp3.m3u', 'a'],
    ['Rock Nation',       'http://105-stream-02.datacomm.ch:8000/rocknation', 'a'],
    ['RSR La Première',   'http://broadcast.infomaniak.net:80/rsr-la1ere-high.mp3', 'a'],
    ['Option Musique',    'http://broadcast.infomaniak.ch/rsr-optionmusique-high.mp3', 'a'],
    ['Frequence Banane',  'http://www.frequencebanane.ch/fb_128.m3u', 'a'],
    ['Backstageradio',    'http://broadcast.infomaniak.ch/backstageradio-high.mp3.m3u','a'],
    ['Radio 105',         'http://212.40.5.105:7000/listen.pls','a'],
    ['neo1',              'http://stream-02.neo1.ch/neo1.m3u','b'],
    ['Lounge-radio.com',  'http://www.lounge-radio.com/listen128.m3u','b'],
	['Radio Top',         'http://icecast.radiotop.ch/radiotop','b'],
	['MagicRadio.CH',     'http://www.magicradio.ch/iphoneAac.m3u','b'],
	['Radio FM1',         'http://radiofm1.ice.infomaniak.ch/playlists/radiofm1-128.mp3.pls','b'],
    ['Radio Swiss Pop',   'http://www.radioswisspop.ch/live/mp3.m3u','a'],
    ['DRS Musikwelle',    'http://stream.srg-ssr.ch/drsmw/mp3_128.m3u','a'],
	['Radio Zürisee',     'http://mp3.radio.ch/radiozuerisee128k','a']

    ];

    var ERR_NONDB = 0;
    var ERR_OTHER = 1;
    var ERR_VERSION_MISMATCH = 2;
    var ERR_RESULTSIZE_EXCEEDED = 3;
    var ERR_MAXSIZE_EXCEEDED = 4;
    var ERR_LOCK_ERROR = 5; // contention
    var ERR_CONSTRAINT = 6;

    var upgradeSuccess = function() { debug.log('Successfully upgraded db.'); };
    var upgradeError = function(error) { debug.log('Failed upgrading db.'); return true; /* treat all errs as fatal */ };
    /** Return TRUE for fatal error */
    var errorHandler = function(t, error) {
        if(error.code == ERR_VERSION_MISMATCH) {
            // well, we just log&ignore it.. safari doesn't see the changeVersion effect until restart Oo
            debug.log('ERR_VERSION_MISMATCH');
            return false;
        }
        debug.log('Whoops, DB error: ' + error.message + ' (' + error.code + ')');
        return true; // fatal error
    };

    /** This is used as a data handler for a request that should return no data. */
    var nullDataHandler = function(t, results) {
        return false;
    };

    var insertDefaults = function(t) {
        var insertquery = 'INSERT INTO stations(name, stream, logo, listened_at) VALUES(?, ?, ?, NULL);';
        var selectquery = 'SELECT id, name FROM stations';
        var updatequery = 'UPDATE stations SET stream = ?, logo = ? where id = ?';
        var defaultStationsName = [];
        for( var i=0; i < defaultStations.length; ++i ) {
            defaultStationsName[defaultStations[i][0]] = defaultStations[i];
            //first we try to insert, then update, this could be improved
            t.executeSql(insertquery, defaultStations[i], nullDataHandler, errorHandler);
            t.executeSql(selectquery, [] , function(t, results) {
                if (results.rows.length == 0) {
                    //
                } else {

                    for (var j = 0; j < results.rows.length; ++j) {
                        var row = results.rows.item(j);
                        var station = defaultStationsName[row['name']];
                        t.executeSql(updatequery,[station[1],station[2],row['id']], nullDataHandler, function(t,error) {debug.log("ERRROR UPDATE");debug.log(error); return true});

                    }

                }
            },
            errorHandler
            );
        }
    };

    this.init = function() {
        try {
            if(!window.openDatabase) {
                alert('Ihr Browser unterstützt kein Local Storage');
            } else {
                db = openDatabase('radios_db', '1', 'Radios Database', 524288); // 512KiB
                debug.log('Current DB Version: ' + db.version);
                db.transaction(function(t) {
                    t.executeSql('CREATE TABLE IF NOT EXISTS stations (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE ON CONFLICT IGNORE, stream TEXT NOT NULL, logo TEXT NOT NULL, listened_at DATE )',
                    [], insertDefaults, errorHandler);
                });
                /*
                db = openDatabase('radios_db', '', 'Radios Database', 524288); // 512KiB
                debug.log('Current DB Version: ' + db.version);
                var M = new Migrator(db);
                M.migration(1, function(t) {
                    debug.log('ONE');
                    t.executeSql('CREATE TABLE stations(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE ON CONFLICT IGNORE, stream TEXT NOT NULL, logo TEXT NOT NULL, listened_at DATE )',
                    [], insertDefaults, errorHandler);
                });
                M.doIt();
                */
            }
            return db;
        } catch(e) {
            if(e.code == ERR_VERSION_MISMATCH) {
                debug.log('ERR_VERSION_MISMATCH');
            } else {
                alert('Error: ' + e);
            }
        }
    };

    this.updateListenAt = function(id) {
        db.transaction(function(t) {
            t.executeSql('UPDATE stations SET listened_at = datetime("now","localtime") WHERE id = ?', [ id ], nullDataHandler, errorHandler);
        });
    };

    this.getLastListenedStation = function(resultHandler) {
        db.transaction(function(t) {
            t.executeSql("SELECT id, name, stream, logo, listened_at FROM stations ORDER BY listened_at DESC LIMIT 1", [] , function(t, results) {
                resultHandler( results.rows.length == 0 ? null : results.rows.item(0) );
            }, errorHandler);
        });
    };

    var getStation = function(id, resultHandler, doUpdateListen) {
        if( doUpdateListen )
            that.updateListenAt(id);

        db.transaction(function(t) {
            t.executeSql("SELECT id, name, stream, logo, listened_at FROM stations WHERE id = ?", [ id ] , function(t, results) {
                resultHandler( results.rows.length == 0 ? null : results.rows.item(0) );
            }, errorHandler);
        });
    };

    var getStations = function(resultHandler, filter) {
        var where = '';
        if ( filter ) {
            where = " WHERE name LIKE '%" + filter + "%';"; // FIXME EEEEESCAPE!
        }
        db.transaction(function(t) {
            t.executeSql("SELECT id, name, stream, logo, listened_at FROM stations " + where + " ORDER BY logo ASC, name ASC", [ ] , function(t, results) {
                resultHandler(results.rows);
            }, errorHandler);
        });
    };

    this.insertStation = function(station) {
        db.transaction(function(t) {
            t.executeSql('INSERT INTO stations(name, stream, logo, listened_at) VALUES(?, ?, ?, NULL);', [ station.name, station.stream, station.logo ], nullDataHandler, errorHandler);
        });
    };

    this.autoSearch = function() {
        var searchel = document.getElementById('search-field');
        searchel.onkeyup = function(ev) {
            that.populateStations(searchel.value);
        };
    };

    this.populateStations = function(filter) {
        getStations(function(stations) {
            var ul = document.createElement('ul');
            var li, txt;
            var playing = document.createElement('span');
            var playingOn = document.createTextNode('On');
            playing.setAttribute('class', 'playing');
            playing.appendChild(playingOn);
            radio.playing = playing;
            for( var i=0; i<stations.length; ++i ) {
                li = document.createElement('li');
                txt = document.createTextNode(stations.item(i).name);
                li.appendChild(txt);
                li.setAttribute('id', 'station-'+ stations.item(i).id);
                li.onclick = function(ev) {

                    var id = this.getAttribute('id').split('-')[1];
                    getStation(id, function(station) {
                        var el = document.getElementById('station-'+station.id);

                        if (plugins.AudioStream.getStatus() == 'isPlaying' && station.name == radio.station) {
                            stopSound();
                        } else {
                            radio.station = station.name;
                            radio.stream = station.stream;
                            radio.playingEl = el;
                            radio.clear();
                            radio.noTrack(true);
                            playSound(station.stream);

                        }
                        // remove mute
                        document.getElementById("mute").setAttribute('class', '');
                    }, true);

                };
                ul.appendChild(li);
            }
            // remove current nav
            var statel = document.getElementById("scrollStations");
            if( statel.hasChildNodes() ) {
                while( statel.childNodes.length >= 1 )
                    statel.removeChild(statel.firstChild);
            }
            // append updated nav
            statel.appendChild(ul);
        }, filter);

    };
};

<|endoftext|>


<commit_before>var fs               = require('fs')
,   util             = require('util')
,   events           = require('events')
,   moment           = require('moment')
,   Playlist         = require('./api/Playlist')
,   Melted           = require('./api/Melted')
,   Media            = require('./api/Media')
,   ScheduledMedia   = require('./api/ScheduledMedia')
,   mvcp_server      = require('./drivers/mvcp/mvcp-driver')
,   playlists_driver = require('./drivers/playlists/playlists-driver')
,   status_driver    = require('./drivers/status/pubsub')
,   utils            = require('./utils')
,   config           = require('mbc-common').config.Mosto.General
,   _                = require('underscore')
,   hearbeats        = require('./heartbeats')
,   models           = require('./models/Mosto')
;

function mosto(customConfig) {

    /** CONFIGURATION */
    this.config = customConfig || config;
    this.server = undefined;
    this.server_started = false;
    this.pl_driver = undefined;
    this.status_driver = undefined;

    /* MODULES */
    this.heartbeats = undefined;

    events.EventEmitter.call(this);
}

util.inherits(mosto, events.EventEmitter);

mosto.prototype.initDriver = function() {

    console.log("mbc-mosto: [INFO] Initializing playlists driver");

    self.driver.on ("create", function(playlist) {

        self.fetcher.addPlaylist( playlist, self.fetcher );
    } );
    self.driver.on ("update", function(playlist) {
        self.fetcher.updatePlaylist( playlist, self.fetcher);
    } );
    self.driver.on ("delete", function(playlist) {
        self.fetcher.removePlaylist( playlist, self.fetcher);
    } );

    self.driver.start();
};

mosto.prototype.stopDriver = function() {

    console.log("mbc-mosto: [INFO] Stopping playlists driver");

    self.driver.stop();

    self.driver.removeAllListeners("create");
    self.driver.removeAllListeners("update");
    self.driver.removeAllListeners("delete");
};

mosto.prototype.startMvcpServer = function(callback) {
    var result = self.server.initServer();
    result.then(function() {
        console.log("mbc-mosto: [INFO] MVCP server started");
        self.server_started = true;
        if (callback !== undefined) {
            callback();
        }
    }, function(err) {
        var e = new Error("mbc-mosto: [ERROR] Error starting MVCP server: " + err + ".\nRetrying in 2 seconds...");
        console.error(e);
        setTimeout(function() {
            self.startMvcpServer(callback);
        }, 2000);
    });
};

console.log("mbc-mosto: [INFO] Starting mbc-mosto... ") ;
mosto.prototype.initHeartbeats = function() {
    var self = this;

    console.log("mbc-mosto: [INFO] Initializing heartbeats");

    self.heartbeats.on('frameStatus', function(status) {
        self.status_driver.setStatusClip(StatusClip(
            status.media.id,
            status.media.get('playlist_order'),
            status.media.playlist.id,
            status.media.get('fps'),
            status.frame,
            status.media.get('length')
        ));
    });
    self.heartbeats.on('clipStatus', function(media) {
        var melted_medias = self.playlists.get('melted_medias');
        var playlists = self.playlists.get('playlists');
        var status = {
            clip:{
                previous: undefined,
                current: undefined,
                next: undefined
            },
            show: {
                previous: undefined,
                current: undefined,
                next: undefined
            },
            position: 0,
            clips: melted_medias.toJSON(),
            status: none
        };
        /* clips */
        var index = melted_medias.indexOf(media);
        status.clip.current = media.toJSON();
        if( index > 0 )
            status.clip.previous = melted_medias.at(index-1).toJSON();
        if( index < melted_medias.length )
            status.clip.next = melted_medias.at(index+1).toJSON();
        /* shows */
        var playlist = playlists.find(function(pl) {
            return pl.indexOf(media) >= 0;
        });
        index = playlists.indexOf(playlist);
        status.show.current = playlist.toJSON();
        if( index > 0 )
            status.show.previous = playlists.at(index-1).toJSON();
        if( index < playlists.length )
            status.show.next = playlists.at(index+1).toJSON();
        self.status_driver.setStatus(status);
    });
    self.heartbeats.init();
};
mosto.prototype.fetchPlaylists = function(window) {
    self.driver.getPlaylists(window, function(playlists) {
        playlists.forEach(function(playlist) {
            var mostoPlaylist = self.getModelPlaylistFromApiPlaylist(playlist);
            self.playlists.get("playlists").add(mostoPlaylist, {merge: true});
        });
        self.playlists.get("melted_medias").sync();
    });
};

mosto.prototype.getModelPlaylistFromApiPlaylist = function(playlist) {
    //TODO: Remove this function and change driver to send Caspa Models
    var playlistJson   = {};
    playlistJson.name  = playlist.name;
    playlistJson.start = moment(playlist.startDate);
    playlistJson.end   = moment(playlist.endDate);
    playlistJson.id    = playlist.id;

    var start = playlistJson.start;
    var medias = new Mosto.MediaCollection();
    playlist.medias.forEach(function(media) {
        var mediaJson = {};
        mediaJson.playlist_order = media.orig_order;
        mediaJson.name           = media.name;
        mediaJson.type           = media.type;
        mediaJson.file           = media.file;
        //TODO: ASSUMING LENGTH COMES IN SOME KIND OF DATE FORMAT THAT CAN BE USED BY MOMENT
        mediaJson.length         = (moment(media.length) / 1000) * media.fps;
        mediaJson.fps            = media.fps;
        mediaJson.start          = start;
        mediaJson.end            = start + moment(media.length);
        mediaJson.id             = media.id;

        var mostoMedia = new Mosto.Media(mediaJson);
        medias.add(mostoMedia);

        start = start + moment(media.length);
    });

    playlistJson.medias = medias;

    return new Mosto.Playlist(playlistJson);
};

mosto.prototype.init = function( melted, callback) {
    console.log("mbc-mosto: [INFO] Init mbc-mosto... ") ;
    var self = this;
    /*
     * inicializar los drivers
     * inicializar los modelos backbone
     * inicializar los heartbeats
     * linkear los eventos entre pl driver y backbone driver
     * linkear heartbeat con status driver
     */
    function startall() {
        self.server        = new mvcp_server(self.config.mvcp_server);
        self.pl_driver     = new playlists_driver(self.config.playlist_server);
        self.status_driver = new status_driver();
        self.playlists = models.Playlists;

        self.pl_driver.on('create');
        self.pl_driver.on('update');
        self.pl_driver.on('delete');

        self.initDriver();
        self.heartbeats.init();

        self.startMvcpServer( function() {
            self.player.play( self.player );
            if (callback) callback();
        } );
    }

    function check_and_start() {
        Melted.is_running(function(running) {
            if (!running) {
                Melted.start(function(pid) {
                    Melted.setup( undefined, undefined, function(result) {
                        startall();
                    });
                });
            } else {
                startall();
            }
        });
    };

    if (melted!==undefined) {
        Melted = melted;
        check_and_start();
    }
    else
        Melted.take( check_and_start );

}

mosto.prototype.finish = function(callback) {
    console.log("mbc-mosto: [INFO] Finish mbc-mosto... ") ;
    self.stopDriver();
    self.player.stop();
    Melted.stop(function(pid) {
        setTimeout( function() {
            Melted.leave();
            if (callback) callback();
        }, 1000 );
    });
}

}

exports = module.exports = function(customConfig) {
    var mosto_server = new mosto(customConfig);
    return mosto_server;
};
/*

  mosto tiene que:

  * inicializar melted
  * inicializar los drivers
  * inicializar los modelos backbone
  * inicializar los heartbeats
  * linkear los eventos entre pl driver y backbone driver
  * linkear heartbeat con status driver

  */
<commit_msg>Fixed heartbeats var name<commit_after>var fs               = require('fs')
,   util             = require('util')
,   events           = require('events')
,   moment           = require('moment')
,   Playlist         = require('./api/Playlist')
,   Melted           = require('./api/Melted')
,   Media            = require('./api/Media')
,   ScheduledMedia   = require('./api/ScheduledMedia')
,   mvcp_server      = require('./drivers/mvcp/mvcp-driver')
,   playlists_driver = require('./drivers/playlists/playlists-driver')
,   status_driver    = require('./drivers/status/pubsub')
,   utils            = require('./utils')
,   config           = require('mbc-common').config.Mosto.General
,   _                = require('underscore')
,   heartbeats        = require('./heartbeats')
,   models           = require('./models/Mosto')
;

function mosto(customConfig) {

    /** CONFIGURATION */
    this.config = customConfig || config;
    this.server = undefined;
    this.server_started = false;
    this.pl_driver = undefined;
    this.status_driver = undefined;

    /* MODULES */
    this.heartbeats = undefined;

    events.EventEmitter.call(this);
}

util.inherits(mosto, events.EventEmitter);

mosto.prototype.initDriver = function() {

    console.log("mbc-mosto: [INFO] Initializing playlists driver");

    self.driver.on ("create", function(playlist) {

        self.fetcher.addPlaylist( playlist, self.fetcher );
    } );
    self.driver.on ("update", function(playlist) {
        self.fetcher.updatePlaylist( playlist, self.fetcher);
    } );
    self.driver.on ("delete", function(playlist) {
        self.fetcher.removePlaylist( playlist, self.fetcher);
    } );

    self.driver.start();
};

mosto.prototype.stopDriver = function() {

    console.log("mbc-mosto: [INFO] Stopping playlists driver");

    self.driver.stop();

    self.driver.removeAllListeners("create");
    self.driver.removeAllListeners("update");
    self.driver.removeAllListeners("delete");
};

mosto.prototype.startMvcpServer = function(callback) {
    var result = self.server.initServer();
    result.then(function() {
        console.log("mbc-mosto: [INFO] MVCP server started");
        self.server_started = true;
        if (callback !== undefined) {
            callback();
        }
    }, function(err) {
        var e = new Error("mbc-mosto: [ERROR] Error starting MVCP server: " + err + ".\nRetrying in 2 seconds...");
        console.error(e);
        setTimeout(function() {
            self.startMvcpServer(callback);
        }, 2000);
    });
};

console.log("mbc-mosto: [INFO] Starting mbc-mosto... ") ;
mosto.prototype.initHeartbeats = function() {
    var self = this;

    console.log("mbc-mosto: [INFO] Initializing heartbeats");

    self.heartbeats.on('frameStatus', function(status) {
        self.status_driver.setStatusClip(StatusClip(
            status.media.id,
            status.media.get('playlist_order'),
            status.media.playlist.id,
            status.media.get('fps'),
            status.frame,
            status.media.get('length')
        ));
    });
    self.heartbeats.on('clipStatus', function(media) {
        var melted_medias = self.playlists.get('melted_medias');
        var playlists = self.playlists.get('playlists');
        var status = {
            clip:{
                previous: undefined,
                current: undefined,
                next: undefined
            },
            show: {
                previous: undefined,
                current: undefined,
                next: undefined
            },
            position: 0,
            clips: melted_medias.toJSON(),
            status: none
        };
        /* clips */
        var index = melted_medias.indexOf(media);
        status.clip.current = media.toJSON();
        if( index > 0 )
            status.clip.previous = melted_medias.at(index-1).toJSON();
        if( index < melted_medias.length )
            status.clip.next = melted_medias.at(index+1).toJSON();
        /* shows */
        var playlist = playlists.find(function(pl) {
            return pl.indexOf(media) >= 0;
        });
        index = playlists.indexOf(playlist);
        status.show.current = playlist.toJSON();
        if( index > 0 )
            status.show.previous = playlists.at(index-1).toJSON();
        if( index < playlists.length )
            status.show.next = playlists.at(index+1).toJSON();
        self.status_driver.setStatus(status);
    });
    self.heartbeats.init();
};
mosto.prototype.fetchPlaylists = function(window) {
    self.driver.getPlaylists(window, function(playlists) {
        playlists.forEach(function(playlist) {
            var mostoPlaylist = self.getModelPlaylistFromApiPlaylist(playlist);
            self.playlists.get("playlists").add(mostoPlaylist, {merge: true});
        });
        self.playlists.get("melted_medias").sync();
    });
};

mosto.prototype.getModelPlaylistFromApiPlaylist = function(playlist) {
    //TODO: Remove this function and change driver to send Caspa Models
    var playlistJson   = {};
    playlistJson.name  = playlist.name;
    playlistJson.start = moment(playlist.startDate);
    playlistJson.end   = moment(playlist.endDate);
    playlistJson.id    = playlist.id;

    var start = playlistJson.start;
    var medias = new Mosto.MediaCollection();
    playlist.medias.forEach(function(media) {
        var mediaJson = {};
        mediaJson.playlist_order = media.orig_order;
        mediaJson.name           = media.name;
        mediaJson.type           = media.type;
        mediaJson.file           = media.file;
        //TODO: ASSUMING LENGTH COMES IN SOME KIND OF DATE FORMAT THAT CAN BE USED BY MOMENT
        mediaJson.length         = (moment(media.length) / 1000) * media.fps;
        mediaJson.fps            = media.fps;
        mediaJson.start          = start;
        mediaJson.end            = start + moment(media.length);
        mediaJson.id             = media.id;

        var mostoMedia = new Mosto.Media(mediaJson);
        medias.add(mostoMedia);

        start = start + moment(media.length);
    });

    playlistJson.medias = medias;

    return new Mosto.Playlist(playlistJson);
};

mosto.prototype.init = function( melted, callback) {
    console.log("mbc-mosto: [INFO] Init mbc-mosto... ") ;
    var self = this;
    /*
     * inicializar los drivers
     * inicializar los modelos backbone
     * inicializar los heartbeats
     * linkear los eventos entre pl driver y backbone driver
     * linkear heartbeat con status driver
     */
    function startall() {
        self.server        = new mvcp_server(self.config.mvcp_server);
        self.pl_driver     = new playlists_driver(self.config.playlist_server);
        self.status_driver = new status_driver();
        self.playlists = models.Playlists;

        self.pl_driver.on('create');
        self.pl_driver.on('update');
        self.pl_driver.on('delete');

        self.initDriver();
        self.heartbeats.init();

        self.startMvcpServer( function() {
            self.player.play( self.player );
            if (callback) callback();
        } );
    }

    function check_and_start() {
        Melted.is_running(function(running) {
            if (!running) {
                Melted.start(function(pid) {
                    Melted.setup( undefined, undefined, function(result) {
                        startall();
                    });
                });
            } else {
                startall();
            }
        });
    };

    if (melted!==undefined) {
        Melted = melted;
        check_and_start();
    }
    else
        Melted.take( check_and_start );

}

mosto.prototype.finish = function(callback) {
    console.log("mbc-mosto: [INFO] Finish mbc-mosto... ") ;
    self.stopDriver();
    self.player.stop();
    Melted.stop(function(pid) {
        setTimeout( function() {
            Melted.leave();
            if (callback) callback();
        }, 1000 );
    });
}

}

exports = module.exports = function(customConfig) {
    var mosto_server = new mosto(customConfig);
    return mosto_server;
};
/*

  mosto tiene que:

  * inicializar melted
  * inicializar los drivers
  * inicializar los modelos backbone
  * inicializar los heartbeats
  * linkear los eventos entre pl driver y backbone driver
  * linkear heartbeat con status driver

  */
<|endoftext|>