<commit_before>function WualaDisplay(){

}

WualaDisplay.prototype.createNavElement = function(name){
	var element = document.createElement("li");
	if (null == name || undefined == name){
		var a = document.createElement("div")
		var i = document.createElement("span");
		i.className = "fa fa-home";
		//i.style.fontSize = "21px";
		a.appendChild(i);
		element.appendChild(a);
	}else{
		element.innerHTML = name
	}
	return element;
}

WualaDisplay.prototype.GetBrowsingPathElement = function(path, onBrowseChangeCB){
	var nav_bar = document.getElementById("navigation_bar");
	nav_bar.innerHTML = "";
	nav_bar.className = "row hidden-xs hidden-sm";
	var nav = document.createElement("div");
	nav_bar.appendChild(nav);
	nav.className = "large-11 columns";
	nav.id = "breadcrumbs";
	var splitted_path = path.split("/");
	var nav_elements = splitted_path.slice(1, splitted_path.length -1);
	nav.innerHTML = "";
	var nav_ul = document.createElement("ol");
	nav_ul.className = "breadcrumb";
	nav.appendChild(nav_ul);
	var current_nav_element = this.createNavElement();
	current_nav_element.onclick = function(path){
		onBrowseChangeCB(path);
	}.bind(current_nav_element, "/");
	nav_ul.appendChild(current_nav_element);
	for (var i=0; i<nav_elements.length; i++){
		current_nav_element = this.createNavElement(nav_elements[i]);
		current_nav_element.onclick = function(path){
			onBrowseChangeCB(path);
		}.bind(current_nav_element, "/" + nav_elements.slice(0, i+1).join("/"));
		nav_ul.appendChild(current_nav_element);
	}
	if (null != current_nav_element){
		current_nav_element.className += " active";
	}
}

WualaDisplay.prototype.GetFilesListElement = function(path){
	var browse_div = document.createElement("table");
	browse_div.style.tableLayout = "fixed";
	browse_div.className = "table table-striped table-hover";
	browsing.innerHTML = "";
	this.thead = document.createElement("thead");

	var tr = document.createElement("tr");
	this.thead.appendChild(tr);

	//For the mobile
	var th = document.createElement("th");
	th.className = "visible-xs visible-sm browse-plus";
	tr.appendChild(th);
	//File Type
	th = document.createElement("th");
	th.innerHTML = "#";
	th.className = "browse-type";
	tr.appendChild(th);

	//FileName
	th = document.createElement("th");
	th.innerHTML = "Name";
	th.className = "browse-name";
	tr.appendChild(th);

	//Size
	th = document.createElement("th");
	th.innerHTML = "Size";
	th.className = "hidden-xs hidden-sm hide-for-medium-down browse-size";
	tr.appendChild(th);

	//Mdate
	th = document.createElement("th");
	th.innerHTML = "Change";
	th.className = "hidden-xs hidden-sm hide-for-medium-down browse-mdate";
	tr.appendChild(th);

	//kind
	th = document.createElement("th");
	th.innerHTML = "Kind";
	th.className = "hidden-xs hidden-sm hide-for-medium-down browse-kind";
	tr.appendChild(th);

	//Actions
	th = document.createElement("th");
	th.innerHTML = "Actions";
	th.className = "hidden-xs hidden-sm hide-for-medium-down browse-action";
	tr.appendChild(th);

	this.tbody = document.createElement("tbody");
	browse_div.appendChild(this.thead);
	browse_div.appendChild(this.tbody);

	return browse_div;
}

WualaDisplay.prototype.buildButtonDiv = function(element, displayName, 	onBrowseCB, onDownloadCB, onDeleteCB, onShareCB){
	var buttonDiv = document.createElement("div");
	buttonDiv.className = "actions";
	if (null != onDeleteCB && undefined != onDeleteCB)
	{
		var deleteButton = document.createElement("div");
		deleteButton.className = "btn btn-default";
		var i =document.createElement("span");
		i.className = "fa fa-trash-o";
		deleteButton.appendChild(i);
		deleteButton.onclick = function(path, event){
			onDeleteCB(event);
		}.bind(element, displayName);
		buttonDiv.appendChild(deleteButton);
	}

	if (null != onDownloadCB && undefined != onDownloadCB){
		var downloadButton = document.createElement("div");
		downloadButton.className = "btn btn-default";
		var i = document.createElement("span");
		i.className = "fa fa-download";
		downloadButton.appendChild(i);
		downloadButton.onclick = function(path, event){
			onDownloadCB(event);
		}.bind(element, displayName);
		downloadButton.appendChild(i);
		buttonDiv.appendChild(downloadButton);
	}

	if (null != onShareCB && undefined != onShareCB){
		var shareButton = document.createElement("span");
		shareButton.className = "btn btn-default";
		var i = document.createElement("span");
		i.className = "fa fa-share";
		shareButton.appendChild(i);
		shareButton.onclick = function(path, event){
			event.stopPropagation();
			onShareCB(event);
		}.bind(element, displayName);
		buttonDiv.appendChild(shareButton);
	}
	return buttonDiv;
}

WualaDisplay.prototype.AddElement = function(list, element, displayName, onBrowseCB, onDownloadCB, onDeleteCB, onShareCB){
	var name = displayName;
	if (null == element){
		element = {
			size: "-",
			kind: "-",
			mDate: "-"
		}
	}
	var tr = document.createElement("tr");
	tr.className = "w-open-path pointer ";
	//TODO TO REMOVE AFTER REWRITING IT
	a = tr;

	//Mobile
	var td = document.createElement("td");
	td.className = "	visible-xs";

	var buttonPlus = document.createElement("div");
	buttonPlus.className = "btn btn-default";
	var iButtonPlus = document.createElement("span");
	iButtonPlus.className = "fa fa-plus-square";
	buttonPlus.appendChild(iButtonPlus);
	buttonPlus.onclick = function(event){
		if (mobtr.className == "hide"){
			mobtr.className = "visible-xs visible-sm";
			iButtonPlus.className = "fa fa-minus-sign";
		}else{
			mobtr.className = "hide";
			iButtonPlus.className = "fa fa-plus-sign";
		}
		event.stopPropagation();
	}
	td.appendChild(buttonPlus)
	tr.appendChild(td);

	td=document.createElement("td");
	var img = document.createElement("span");
	img.className = "fa fa-file";
	td.appendChild(img);
	tr.appendChild(td);

	if (onBrowseCB){
		tr.className = "browseable";
		img.className = "fa fa-folder-open";
		tr.onclick = function(path, event){
			onBrowseCB(event);
		}.bind(a, name);

	}

	td = document.createElement("td");
	td.innerHTML = name;
	td.className = "browse-name";
	tr.appendChild(td);

	//Size
	th = document.createElement("td");
	th.innerHTML =  bytesToSize(element.size);

	th.className = "hidden-xs hidden-sm";
	tr.appendChild(th);

	//Mdate
	th = document.createElement("td");

    if ("-" == element.mDate){
      element.mDateStr = "";
    }else{
      var temp = new Date(element.mDate * 1000)
      element.mDateStr = temp.toDateString();
    }
	th.innerHTML = element.mDateStr;
	th.className = "hidden-xs hidden-sm";
	tr.appendChild(th);

	//kind
	th = document.createElement("td");
	th.innerHTML = element.kind;
	th.className = "hidden-xs hidden-sm";
	tr.appendChild(th);

	td = document.createElement("td");
	td.className = "hidden-xs hidden-sm";
	tr.appendChild(td);

	var buttonDiv = this.buildButtonDiv(element, displayName, onBrowseCB, onDownloadCB, onDeleteCB, onShareCB);
	td.appendChild(buttonDiv);
	this.tbody.appendChild(a);
	//TODO make another one for the phones :)
	var mobtr = document.createElement("tr");
	mobtr.className = "hide";
	mobtr.style.display = "table-row";
	td = document.createElement("td");
	td.colSpan = "3";
	mobtr.style.textAlign = "center";
	mobtr.appendChild(td);

	if (null != onDownloadCB && undefined != onDownloadCB){
		var div = document.createElement("div");
		var strong = document.createElement("strong");
		strong.innerHTML = "Size";
		div.appendChild(strong);
		div.innerHTML += ": " + bytesToSize(element.size);
		td.appendChild(div);
		div = document.createElement("div");
		strong = document.createElement("strong");
		strong.innerHTML = "Change";
		div.appendChild(strong);
		div.innerHTML += ": " + element.mDateStr;
		td.appendChild(div);
		div = document.createElement("div");
		strong = document.createElement("strong");
		strong.innerHTML = "Kind";
		div.appendChild(strong);
		div.innerHTML += ": -";
		td.appendChild(div);
	}
	var actiondiv = this.buildButtonDiv(element, displayName, onBrowseCB, onDownloadCB, onDeleteCB);
	td.appendChild(actiondiv)
	mobtr.appendChild(td);
	//

    //
    //
Size : 6.3 MB

    //
Change : 1 years ago

    //
Kind :  ftf

    //

    //
    //
    //

    //
    //

    this.tbody.appendChild(mobtr);
    //Just for the strip display we'll add a new line
    this.tbody.appendChild(document.createElement("tr"));
    return tr;
}

WualaDisplay.prototype.AddEmptyList = function(list){
	var tr = document.createElement("tr");
	tr.innerHTML = "No files nor folder";
	this.tbody.appendChild(tr);
}

WualaDisplay.prototype.GetListDisplayComponent = function(list){
	return list;
}

WualaDisplay.prototype.GetDeletePopup = function(path, onOkClickCB, onCancelClickCB){

};

WualaDisplay.prototype.GetDownloadPopup = function(path, onDownloadClickCB, onCancelClickCB){

}<commit_msg>Fix issue with medium screens + allow the sharelink on small/medium screens<commit_after>function WualaDisplay(){

}

WualaDisplay.prototype.createNavElement = function(name){
	var element = document.createElement("li");
	if (null == name || undefined == name){
		var a = document.createElement("div")
		var i = document.createElement("span");
		i.className = "fa fa-home";
		//i.style.fontSize = "21px";
		a.appendChild(i);
		element.appendChild(a);
	}else{
		element.innerHTML = name
	}
	return element;
}

WualaDisplay.prototype.GetBrowsingPathElement = function(path, onBrowseChangeCB){
	var nav_bar = document.getElementById("navigation_bar");
	nav_bar.innerHTML = "";
	nav_bar.className = "row hidden-xs hidden-sm";
	var nav = document.createElement("div");
	nav_bar.appendChild(nav);
	nav.className = "large-11 columns";
	nav.id = "breadcrumbs";
	var splitted_path = path.split("/");
	var nav_elements = splitted_path.slice(1, splitted_path.length -1);
	nav.innerHTML = "";
	var nav_ul = document.createElement("ol");
	nav_ul.className = "breadcrumb";
	nav.appendChild(nav_ul);
	var current_nav_element = this.createNavElement();
	current_nav_element.onclick = function(path){
		onBrowseChangeCB(path);
	}.bind(current_nav_element, "/");
	nav_ul.appendChild(current_nav_element);
	for (var i=0; i<nav_elements.length; i++){
		current_nav_element = this.createNavElement(nav_elements[i]);
		current_nav_element.onclick = function(path){
			onBrowseChangeCB(path);
		}.bind(current_nav_element, "/" + nav_elements.slice(0, i+1).join("/"));
		nav_ul.appendChild(current_nav_element);
	}
	if (null != current_nav_element){
		current_nav_element.className += " active";
	}
}

WualaDisplay.prototype.GetFilesListElement = function(path){
	var browse_div = document.createElement("table");
	browse_div.style.tableLayout = "fixed";
	browse_div.className = "table table-striped table-hover";
	browsing.innerHTML = "";
	this.thead = document.createElement("thead");

	var tr = document.createElement("tr");
	this.thead.appendChild(tr);

	//For the mobile
	var th = document.createElement("th");
	th.className = "visible-xs visible-sm browse-plus";
	tr.appendChild(th);
	//File Type
	th = document.createElement("th");
	th.innerHTML = "#";
	th.className = "browse-type";
	tr.appendChild(th);

	//FileName
	th = document.createElement("th");
	th.innerHTML = "Name";
	th.className = "browse-name";
	tr.appendChild(th);

	//Size
	th = document.createElement("th");
	th.innerHTML = "Size";
	th.className = "hidden-xs hidden-sm hide-for-medium-down browse-size";
	tr.appendChild(th);

	//Mdate
	th = document.createElement("th");
	th.innerHTML = "Change";
	th.className = "hidden-xs hidden-sm hide-for-medium-down browse-mdate";
	tr.appendChild(th);

	//kind
	th = document.createElement("th");
	th.innerHTML = "Kind";
	th.className = "hidden-xs hidden-sm hide-for-medium-down browse-kind";
	tr.appendChild(th);

	//Actions
	th = document.createElement("th");
	th.innerHTML = "Actions";
	th.className = "hidden-xs hidden-sm hide-for-medium-down browse-action";
	tr.appendChild(th);

	this.tbody = document.createElement("tbody");
	browse_div.appendChild(this.thead);
	browse_div.appendChild(this.tbody);

	return browse_div;
}

WualaDisplay.prototype.buildButtonDiv = function(element, displayName, 	onBrowseCB, onDownloadCB, onDeleteCB, onShareCB){
	var buttonDiv = document.createElement("div");
	buttonDiv.className = "actions";
	if (null != onDeleteCB && undefined != onDeleteCB)
	{
		var deleteButton = document.createElement("div");
		deleteButton.className = "btn btn-default";
		var i =document.createElement("span");
		i.className = "fa fa-trash-o";
		deleteButton.appendChild(i);
		deleteButton.onclick = function(path, event){
			onDeleteCB(event);
		}.bind(element, displayName);
		buttonDiv.appendChild(deleteButton);
	}

	if (null != onDownloadCB && undefined != onDownloadCB){
		var downloadButton = document.createElement("div");
		downloadButton.className = "btn btn-default";
		var i = document.createElement("span");
		i.className = "fa fa-download";
		downloadButton.appendChild(i);
		downloadButton.onclick = function(path, event){
			onDownloadCB(event);
		}.bind(element, displayName);
		downloadButton.appendChild(i);
		buttonDiv.appendChild(downloadButton);
	}

	if (null != onShareCB && undefined != onShareCB){
		var shareButton = document.createElement("span");
		shareButton.className = "btn btn-default";
		var i = document.createElement("span");
		i.className = "fa fa-share";
		shareButton.appendChild(i);
		shareButton.onclick = function(path, event){
			event.stopPropagation();
			onShareCB(event);
		}.bind(element, displayName);
		buttonDiv.appendChild(shareButton);
	}
	return buttonDiv;
}

WualaDisplay.prototype.AddElement = function(list, element, displayName, onBrowseCB, onDownloadCB, onDeleteCB, onShareCB){
	var name = displayName;
	if (null == element){
		element = {
			size: "-",
			kind: "-",
			mDate: "-"
		}
	}
	var tr = document.createElement("tr");
	tr.className = "w-open-path pointer ";
	//TODO TO REMOVE AFTER REWRITING IT
	a = tr;

	//Mobile
	var td = document.createElement("td");
	td.className = "visible-xs visible-sm";

	var buttonPlus = document.createElement("div");
	buttonPlus.className = "btn btn-default";
	var iButtonPlus = document.createElement("span");
	iButtonPlus.className = "fa fa-plus-square";
	buttonPlus.appendChild(iButtonPlus);
	buttonPlus.onclick = function(event){
		if (mobtr.className == "hide"){
			mobtr.className = "visible-xs visible-sm";
			iButtonPlus.className = "fa fa-minus-square";
		}else{
			mobtr.className = "hide";
			iButtonPlus.className = "fa fa-plus-square";
		}
		event.stopPropagation();
	}
	td.appendChild(buttonPlus)
	tr.appendChild(td);

	td=document.createElement("td");
	var img = document.createElement("span");
	img.className = "fa fa-file";
	td.appendChild(img);
	tr.appendChild(td);

	if (onBrowseCB){
		tr.className = "browseable";
		img.className = "fa fa-folder-open";
		tr.onclick = function(path, event){
			onBrowseCB(event);
		}.bind(a, name);

	}

	td = document.createElement("td");
	td.innerHTML = name;
	td.className = "browse-name";
	tr.appendChild(td);

	//Size
	th = document.createElement("td");
	th.innerHTML =  bytesToSize(element.size);

	th.className = "hidden-xs hidden-sm";
	tr.appendChild(th);

	//Mdate
	th = document.createElement("td");

    if ("-" == element.mDate){
      element.mDateStr = "";
    }else{
      var temp = new Date(element.mDate * 1000)
      element.mDateStr = temp.toDateString();
    }
	th.innerHTML = element.mDateStr;
	th.className = "hidden-xs hidden-sm";
	tr.appendChild(th);

	//kind
	th = document.createElement("td");
	th.innerHTML = element.kind;
	th.className = "hidden-xs hidden-sm";
	tr.appendChild(th);

	td = document.createElement("td");
	td.className = "hidden-xs hidden-sm";
	tr.appendChild(td);

	var buttonDiv = this.buildButtonDiv(element, displayName, onBrowseCB, onDownloadCB, onDeleteCB, onShareCB);
	td.appendChild(buttonDiv);
	this.tbody.appendChild(a);
	//TODO make another one for the phones :)
	var mobtr = document.createElement("tr");
	mobtr.className = "hide";
	mobtr.style.display = "table-row";
	td = document.createElement("td");
	td.colSpan = "3";
	mobtr.style.textAlign = "center";
	mobtr.appendChild(td);

	if (null != onDownloadCB && undefined != onDownloadCB){
		var div = document.createElement("div");
		var strong = document.createElement("strong");
		strong.innerHTML = "Size";
		div.appendChild(strong);
		div.innerHTML += ": " + bytesToSize(element.size);
		td.appendChild(div);
		div = document.createElement("div");
		strong = document.createElement("strong");
		strong.innerHTML = "Change";
		div.appendChild(strong);
		div.innerHTML += ": " + element.mDateStr;
		td.appendChild(div);
		div = document.createElement("div");
		strong = document.createElement("strong");
		strong.innerHTML = "Kind";
		div.appendChild(strong);
		div.innerHTML += ": -";
		td.appendChild(div);
	}
	var actiondiv = this.buildButtonDiv(element, displayName, onBrowseCB, onDownloadCB, onDeleteCB, onShareCB);
	td.appendChild(actiondiv)
	mobtr.appendChild(td);
	//

    //
    //
Size : 6.3 MB

    //
Change : 1 years ago

    //
Kind :  ftf

    //

    //
    //
    //

    //
    //

    this.tbody.appendChild(mobtr);
    //Just for the strip display we'll add a new line
    this.tbody.appendChild(document.createElement("tr"));
    return tr;
}

WualaDisplay.prototype.AddEmptyList = function(list){
	var tr = document.createElement("tr");
	tr.innerHTML = "No files nor folder";
	this.tbody.appendChild(tr);
}

WualaDisplay.prototype.GetListDisplayComponent = function(list){
	return list;
}

WualaDisplay.prototype.GetDeletePopup = function(path, onOkClickCB, onCancelClickCB){

};

WualaDisplay.prototype.GetDownloadPopup = function(path, onDownloadClickCB, onCancelClickCB){

}<|endoftext|>


<commit_before>// Copyright (c) 2014 Walter Bender
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the The GNU Affero General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// You should have received a copy of the GNU Affero General Public
// License along with this library; if not, write to the Free Software
// Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA

// The trashcan is an area at the bottom of the screen where stacks of
// blocks can be dragged. Once in the trash area, they are marked as
// trash and hidden. There is a menu button that can be used to
// restore trash.
require(['activity/utils']);

var TRASHWIDTH = 120;
var TRASHHEIGHT = 120;

function Trashcan (canvas, stage, size, refreshCanvas) {
    this.canvas = canvas;
    this.stage = stage;
    this.refreshCanvas = refreshCanvas;
    this.size = size;
    this.isVisible = false;

    this.iconsize = 55;  // default value
    this.container = new createjs.Container();

    this._borderHighlightBitmap = null;
    this.__isHighlightInitialized = false;
    this._inAnimation = false;
    this._animationInterval = null;
    this._highlightPower = 255;
    this._animationLevel = 0;
    this.animationTime = 500;

    this._makeBorderHighlight = function(isRed = false) {
        var img = new Image();
        var trash = this;

        img.onload = function () {
            trash._borderHighlightBitmap = new createjs.Bitmap(img);
            trash._borderHighlightBitmap.scaleX = size / trash.iconsize;
            trash._borderHighlightBitmap.scaleY = size / trash.iconsize;
            if (!trash._isHighlightInitialized) {
                trash.container.visible = false;
                trash._isHighlightInitialized = true;
            } else {
               trash.container.removeChildAt(trash.container.children.length-1);
            }
            trash.container.addChild(trash._borderHighlightBitmap);
            trash._borderHighlightBitmap.visible = true;
        };

        var highlightString = 'rgb(' + this._highlightPower + ',' + this._highlightPower + ',' + this._highlightPower + ')';
        if (isRed) {
            highlightString = 'rgb(255, 0, 0)'; // when trash is activated, highlight should be red (warn)
        }
        img.src = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(BORDER.replace('stroke_color', highlightString))));
    };

    this._makeBorder = function() {
        var img = new Image();
        var trash = this;

        img.onload = function () {
            border = new createjs.Bitmap(img);
            bitmap.scaleX = trash.size / trash.iconsize;
            bitmap.scaleY = trash.size / trash.iconsize;
            trash.container.addChild(border);
            trash._makeBorderHighlight();
        };

        img.src = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(BORDER.replace('stroke_color', '#e0e0e0'))));
    };

    this._makeTrash = function() {
        var img = new Image();
        var trash = this;

        img.onload = function () {
            bitmap = new createjs.Bitmap(img);
            trash.container.addChild(bitmap);
            trash.iconsize = bitmap.getBounds().width;
            bitmap.scaleX = trash.size / trash.iconsize;
            bitmap.scaleY = trash.size / trash.iconsize;
            bitmap.x = ((TRASHWIDTH - size) / 2) * bitmap.scaleX;
            bitmap.y = ((TRASHHEIGHT - size) / 2) * bitmap.scaleY;
            trash._makeBorder();
        };

        img.src = 'images/trash.svg';
    };

    this.resizeEvent = function(scale) {
        this.container.x = (this.canvas.width * 1 / scale / 2) - ((TRASHWIDTH / 2) * (this.size / this.iconsize));
        this.container.y = (this.canvas.height * 1 / scale) - (TRASHHEIGHT * (this.size / this.iconsize));
    };

    this.stage.addChild(this.container);
    this.stage.setChildIndex(this.container, 0);
    this.resizeEvent(1);
    this._makeTrash();

    this.hide = function() {
        createjs.Tween.get(this.container).to({alpha: 0}, 200).set({visible: false});
    };

    this.show = function() {
        createjs.Tween.get(this.container).to({alpha: 0.0, visible: true}).to({alpha: 1.0}, 200);
    };

    this.startHighlightAnimation = function() {
        if(this._inAnimation)
            return;
        this._inAnimation = true;
        var that = this;
        this._animationInterval = setInterval(function() {
            that._animationLevel += 20;
            if(that._animationLevel >= that.animationTime) {
                that.isVisible = true;
                that._makeBorderHighlight(true); // make it red
                that.refreshCanvas();
                clearInterval(that._animationInterval); // autostop animation
                return;
            }
            that._highlightPower = parseInt(255 - (255 * (that._animationLevel / that.animationTime)), 10);
            that._makeBorderHighlight();
            that.refreshCanvas();
        }, 20);
        this._switchHighlightVisibility(true);
    }

    this.stopHighlightAnimation = function() {
        if(!this._inAnimation)
            return;
        clearInterval(this._animationInterval);
        this._inAnimation = false;
        this.isVisible = false;
        this._animationLevel = 0;
        this._highlightPower = 255;
        this._makeBorderHighlight();
        this._switchHighlightVisibility(false);
    }

    this._switchHighlightVisibility = function(bool) {
        last(this.container.children).visible = bool;
        this.container.children[1].visible = !bool;
        this.container.visible = true;
        this.refreshCanvas();
    }

    this.overTrashcan = function(x, y) {
        var tx = this.container.x;
        var ty = this.container.y;

        if (x < tx) {
            return false;
        } else if (x > tx + (TRASHWIDTH * this.size / this.iconsize)) {
            return false;
        }

        if (y < ty) {
            return false;
        }

        return true;
    };
};
<commit_msg>Changed animation time; minor bugs fixed<commit_after>// Copyright (c) 2014 Walter Bender
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the The GNU Affero General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// You should have received a copy of the GNU Affero General Public
// License along with this library; if not, write to the Free Software
// Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA

// The trashcan is an area at the bottom of the screen where stacks of
// blocks can be dragged. Once in the trash area, they are marked as
// trash and hidden. There is a menu button that can be used to
// restore trash.
require(['activity/utils']);

var TRASHWIDTH = 120;
var TRASHHEIGHT = 120;

function Trashcan (canvas, stage, size, refreshCanvas) {
    this.canvas = canvas;
    this.stage = stage;
    this.refreshCanvas = refreshCanvas;
    this.size = size;
    this.isVisible = false;

    this.iconsize = 55;  // default value
    this.container = new createjs.Container();

    this._borderHighlightBitmap = null;
    this._isHighlightInitialized = false;
    this._inAnimation = false;
    this._animationInterval = null;
    this._highlightPower = 255;
    this._animationLevel = 0;
    this.animationTime = 1000;

    this._makeBorderHighlight = function(isRed = false) {
        var img = new Image();
        var trash = this;

        img.onload = function () {
            trash._borderHighlightBitmap = new createjs.Bitmap(img);
            trash._borderHighlightBitmap.scaleX = size / trash.iconsize;
            trash._borderHighlightBitmap.scaleY = size / trash.iconsize;
            if (!trash._isHighlightInitialized) {
                trash.container.visible = false;
                trash._isHighlightInitialized = true;
            } else {
               trash.container.removeChildAt(trash.container.children.length-1);
            }
            trash.container.addChild(trash._borderHighlightBitmap);
            trash._borderHighlightBitmap.visible = true;
        };

        var highlightString = 'rgb(' + this._highlightPower + ',' + this._highlightPower + ',' + this._highlightPower + ')';
        if (isRed) {
            highlightString = 'rgb(255, 0, 0)'; // when trash is activated, highlight should be red (warn)
        }
        img.src = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(BORDER.replace('stroke_color', highlightString))));
    };

    this._makeBorder = function() {
        var img = new Image();
        var trash = this;

        img.onload = function () {
            border = new createjs.Bitmap(img);
            bitmap.scaleX = trash.size / trash.iconsize;
            bitmap.scaleY = trash.size / trash.iconsize;
            trash.container.addChild(border);
            trash._makeBorderHighlight();
        };

        img.src = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(BORDER.replace('stroke_color', '#e0e0e0'))));
    };

    this._makeTrash = function() {
        var img = new Image();
        var trash = this;

        img.onload = function () {
            bitmap = new createjs.Bitmap(img);
            trash.container.addChild(bitmap);
            trash.iconsize = bitmap.getBounds().width;
            bitmap.scaleX = trash.size / trash.iconsize;
            bitmap.scaleY = trash.size / trash.iconsize;
            bitmap.x = ((TRASHWIDTH - size) / 2) * bitmap.scaleX;
            bitmap.y = ((TRASHHEIGHT - size) / 2) * bitmap.scaleY;
            trash._makeBorder();
        };

        img.src = 'images/trash.svg';
    };

    this.resizeEvent = function(scale) {
        this.container.x = (this.canvas.width * 1 / scale / 2) - ((TRASHWIDTH / 2) * (this.size / this.iconsize));
        this.container.y = (this.canvas.height * 1 / scale) - (TRASHHEIGHT * (this.size / this.iconsize));
    };

    this.stage.addChild(this.container);
    this.stage.setChildIndex(this.container, 0);
    this.resizeEvent(1);
    this._makeTrash();

    this.hide = function() {
        createjs.Tween.get(this.container).to({alpha: 0}, 200).set({visible: false});
    };

    this.show = function() {
        this.stopHighlightAnimation();
        createjs.Tween.get(this.container).to({alpha: 0.0, visible: true}).to({alpha: 1.0}, 200);
    };

    this.startHighlightAnimation = function() {
        if(this._inAnimation)
            return;
        this._inAnimation = true;
        var that = this;
        this._animationInterval = setInterval(function() {
            that._animationLevel += 20;
            if(that._animationLevel >= that.animationTime) {
                that.isVisible = true;
                that._makeBorderHighlight(true); // make it red
                that.refreshCanvas();
                clearInterval(that._animationInterval); // autostop animation
                return;
            }
            that._highlightPower = parseInt(255 - (255 * (that._animationLevel / that.animationTime)), 10);
            that._makeBorderHighlight();
            that.refreshCanvas();
        }, 20);
        this._switchHighlightVisibility(true);
    };

    this.stopHighlightAnimation = function() {
        if(!this._inAnimation)
            return;
        clearInterval(this._animationInterval);
        this._inAnimation = false;
        this.isVisible = false;
        this._animationLevel = 0;
        this._highlightPower = 255;
        this._makeBorderHighlight();
        this._switchHighlightVisibility(false);
    };

    this._switchHighlightVisibility = function(bool) {
        last(this.container.children).visible = bool;
        this.container.children[1].visible = !bool;
        this.container.visible = true;
        this.refreshCanvas();
    };

    this.overTrashcan = function(x, y) {
        var tx = this.container.x;
        var ty = this.container.y;

        if (x < tx) {
            return false;
        } else if (x > tx + (TRASHWIDTH * this.size / this.iconsize)) {
            return false;
        }

        if (y < ty) {
            return false;
        }

        return true;
    };
};
<|endoftext|>


<commit_before>// Copyright 2018-2020, University of Colorado Boulder

/**
 * These are the units that can be associated with Property instances.
 *
 * When adding units to this file, please add abbreviation, preferably SI abbreviations.
 * See https://github.com/phetsims/phet-io/issues/530
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */

import axon from './axon.js';

const units = {
  values: [
    '%', // percent
    'A', // amperes
    'AMU', // atomic mass unit
    'atm', // atmospheres
    'cm', // centimeters
    'cm^2', // centimeters squared
    'C', // coulombs
    '\u00B0', // °, degrees (angle)
    '\u00B0C', // °C, degrees Celsius
    'F', // farad
    'g', // grams
    'Hz', // hertz
    'J', // Joules
    'K', // Kelvin
    'kg', // kilograms
    'kg/m^3', // kg/cubic meter
    'kPa', // kilopascals
    'L',
    'L/s',
    'm', // meters
    'm/s', // meters/second
    'm/s/s', // meters/second/second
    'm/s^2', // meters/seconds squared
    'mA', // milliampere
    'mm', //millimeters
    'mol',
    'mol/L',
    'N', // Newtons
    'N/m', // Newtons/meter
    'nm', // nanometers
    'nm/ps', // nanometers/picosecond
    '(N\u00b7s)/m', // (N·s)/n, Newton-seconds/meter
    '\u2126', // Ω, ohms - don't use the one in MathSymbols to prevent a dependency on scenery-phet
    '\u2126\u00b7cm', // Ω·cm, ohm-centimeters
    'particles/ps', // particles/picosecond
    'pm', // picometers
    'pm/ps', // picometers/picosecond
    'pm/s', // picometers/second
    'pm/s^2', // picometers/second-squared
    'pm^3', // picometers cubed
    'ps', // picoseconds
    'radians', // radians - note this has the same abbreviation as the radiation term "rad" so we use the full term
    'radians/s', // radians/second
    's', // seconds
    'V', // volts
    'view-coordinates/s'
  ],

  isValidUnits: function( unit ) {
    return _.includes( units.values, unit );
  }
};

axon.register( 'units', units );

export default units;<commit_msg>revise N⋅s/m, https://github.com/phetsims/phet-io/issues/530<commit_after>// Copyright 2018-2020, University of Colorado Boulder

/**
 * These are the units that can be associated with Property instances.
 *
 * When adding units to this file, please add abbreviation, preferably SI abbreviations.
 * See https://github.com/phetsims/phet-io/issues/530
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */

import axon from './axon.js';

const units = {
  values: [
    '%', // percent
    'A', // amperes
    'AMU', // atomic mass unit
    'atm', // atmospheres
    'cm', // centimeters
    'cm^2', // centimeters squared
    'C', // coulombs
    '\u00B0', // °, degrees (angle)
    '\u00B0C', // °C, degrees Celsius
    'F', // farad
    'g', // grams
    'Hz', // hertz
    'J', // Joules
    'K', // Kelvin
    'kg', // kilograms
    'kg/m^3', // kg/cubic meter
    'kPa', // kilopascals
    'L',
    'L/s',
    'm', // meters
    'm/s', // meters/second
    'm/s/s', // meters/second/second
    'm/s^2', // meters/seconds squared
    'mA', // milliampere
    'mm', //millimeters
    'mol',
    'mol/L',
    'N', // Newtons
    'N/m', // Newtons/meter
    'nm', // nanometers
    'nm/ps', // nanometers/picosecond
    'N\u00b7s/m', // (N·s)/n, Newton-seconds/meter
    '\u2126', // Ω, ohms - don't use the one in MathSymbols to prevent a dependency on scenery-phet
    '\u2126\u00b7cm', // Ω·cm, ohm-centimeters
    'particles/ps', // particles/picosecond
    'pm', // picometers
    'pm/ps', // picometers/picosecond
    'pm/s', // picometers/second
    'pm/s^2', // picometers/second-squared
    'pm^3', // picometers cubed
    'ps', // picoseconds
    'radians', // radians - note this has the same abbreviation as the radiation term "rad" so we use the full term
    'radians/s', // radians/second
    's', // seconds
    'V', // volts
    'view-coordinates/s'
  ],

  isValidUnits: function( unit ) {
    return _.includes( units.values, unit );
  }
};

axon.register( 'units', units );

export default units;<|endoftext|>


<commit_before>// Copyright 2011 Joshua Wang, MIT License

/**
 * @fileoverview
 *   - numberUtils
 *   - localStorageUtils
 *   - debugUtils
 * @author sharkman.jw@gmail.com (Joshua Wang)
 */

/**
 * numberUtils singleton
 */
var numberUtils = (function() {
  epsilon = 0.000001; // good enough for this app

  return {
    zeroTolerance: epsilon,

    /**
     * Format number with comma(s)
     * @param {number} value: input number
     * @param {number} decimals: number of decimals
     * @return {string} formatted string
     */
    formatWithComma: function(value, decimals) {
      if (!decimals && decimals != 0)
        decimals = 2;
      else if (decimals < 0)
        decimals = 0;

      var neg = false;
      if (value < 0) {
        neg = true;
        value = -value;
      }

      var s = value.toFixed(decimals);
      if (value < 1000)
        return neg ? ('-' + s) : s;

      var x = s.split('.');
      var x1 = x[0]; // part before decimal point
      var x2 = x.length > 1 ? ('.' + x[1]) : ''; // part after decimal point

      var parts = [];
      var n = x1.length % 3;
      if (n > 0) {
        parts.push(x1.substr(0, n));
      }
      while (n < x1.length) {
        parts.push(x1.substr(n, 3));
        n += 3;
      }

      return neg ? ('-' + parts.join(',') + x2) : (parts.join(',') + x2);
    },

    /**
     * Parse number string with comma(s) to float number
     * @param {string} s
     * @return {number} parsed result
     */
    parseNumberWithComma: function(s) {
      if (s)
        return parseFloat(s.replace(/,/g, ''));
      return Number.NaN;
    },

    /**
     * Compare number
     * @param {number} val1
     * @param {number} val2
     * @return {number} compare result
     */
    compare: function(val1, val2) {
      if (Math.abs(val1 - val2) < epsilon)
        return 0;
      else if (val1 > val2)
        return 1;
      return -1;
    }
  };
})();

/**
 * localStorageUtils singleton: wrapper of local storage.
 */
var localStorageUtils = (function() {
  /**
   * Retrieve a str from local storage.
   * @param {string} key
   * @param {string} defaultVal: if no valid value is retrieved, use this
   */
  var _retrieveStr = function(key, defaultVal) {
    var val = localStorage.getItem(key);
    if (val == 'null' || val == 'undefined')
      return null;
    return (val || val == '') ? val : (defaultVal ? defaultVal : null);
  };

  /**
   * Save a str to local storage.
   * @param {string} key
   * @param {any} val: value to store in string format
   */
  var _save = function(key, val) {
    localStorage.setItem(key, val);
  };

  return {
    save: _save,
    saveStr: _save,
    getStr: _retrieveStr,
    saveNumber: _save,

    /**
     * Retrieve a number from local storage.
     * @param {string} key
     * @param {num} defaultVal: default value to use if no valid one is retrieved
     */
    getNumber: function(key, defaultVal) {
      var val = _retrieveStr(key, null);
      return val ? parseFloat(val) : defaultVal;
    },

    /**
     * Retrieve an integer from local storage.
     * @param {string} key
     * @param {number} defaultVal: default value to use if no valid one is
     *                             retrieved.
     */
    getInt: function(key, defaultVal) {
      var val = _retrieveStr(key, null);
      return val ? parseInt(val) : defaultVal;
    },

    /**
     * Save an object to local storage.
     * @param {string} key
     * @param {obj} obj: object to save
     */
    saveObj: function(key, obj) {
      localStorage.setItem(key, JSON.stringify(obj));
    },

    /**
     * Retrieve an object from local storage.
     * @param {string} key
     * @param {obj} defaultVal: default obj to use if no valid one is retrieved
     * @param {obj} classPrototype: prototype to assign to the retrieved obj
     */
    getObj: function(key, defaultVal, classPrototype) {
      var val = _retrieveStr(key, null);
      if (val) {
        var obj = JSON.parse(val);
        if (classPrototype) {
          obj.__proto__ = classPrototype;
        }
        return obj;
      }
      return defaultVal;
    },

    /**
     * Clear all local storage items
     */
    clearAll: function() {
      for (each in localStorage)
        localStorage.removeItem(each);
    }

    /**
     * Clear all stock data
     */
    // TODO
  };
})();

/**
 * debugUtils singleton
 */
var debugUtils = (function() {
  var _config = { enable: true };

  return {
    enable: function(enableIt) {
      _config.enable = enableIt;
    },

    /**
     * Print text to log
     * @param {string} text
     */
    log: function(text) {
      if (!_config.enable)
        return;
      console.log(text);
    },

    /**
     * Print text to log
     * @param {string} text
     */
    logObj: function(obj) {
      if (!_config.enable)
        return;
      console.log(JSON.stringify(obj));
    }
  };
})();

<commit_msg>added localStorageUtils.clearByPattern<commit_after>// Copyright 2011 Joshua Wang, MIT License

/**
 * @fileoverview
 *   - numberUtils
 *   - localStorageUtils
 *   - debugUtils
 * @author sharkman.jw@gmail.com (Joshua Wang)
 */

/**
 * numberUtils singleton
 */
var numberUtils = (function() {
  epsilon = 0.000001; // good enough for this app

  return {
    zeroTolerance: epsilon,

    /**
     * Format number with comma(s)
     * @param {number} value: input number
     * @param {number} decimals: number of decimals
     * @return {string} formatted string
     */
    formatWithComma: function(value, decimals) {
      if (!decimals && decimals != 0)
        decimals = 2;
      else if (decimals < 0)
        decimals = 0;

      var neg = false;
      if (value < 0) {
        neg = true;
        value = -value;
      }

      var s = value.toFixed(decimals);
      if (value < 1000)
        return neg ? ('-' + s) : s;

      var x = s.split('.');
      var x1 = x[0]; // part before decimal point
      var x2 = x.length > 1 ? ('.' + x[1]) : ''; // part after decimal point

      var parts = [];
      var n = x1.length % 3;
      if (n > 0) {
        parts.push(x1.substr(0, n));
      }
      while (n < x1.length) {
        parts.push(x1.substr(n, 3));
        n += 3;
      }

      return neg ? ('-' + parts.join(',') + x2) : (parts.join(',') + x2);
    },

    /**
     * Parse number string with comma(s) to float number
     * @param {string} s
     * @return {number} parsed result
     */
    parseNumberWithComma: function(s) {
      if (s)
        return parseFloat(s.replace(/,/g, ''));
      return Number.NaN;
    },

    /**
     * Compare number
     * @param {number} val1
     * @param {number} val2
     * @return {number} compare result
     */
    compare: function(val1, val2) {
      if (Math.abs(val1 - val2) < epsilon)
        return 0;
      else if (val1 > val2)
        return 1;
      return -1;
    }
  };
})();

/**
 * localStorageUtils singleton: wrapper of local storage.
 */
var localStorageUtils = (function() {
  /**
   * Retrieve a str from local storage.
   * @param {string} key
   * @param {string} defaultVal: if no valid value is retrieved, use this
   */
  var _retrieveStr = function(key, defaultVal) {
    var val = localStorage.getItem(key);
    if (val == 'null' || val == 'undefined')
      return null;
    return (val || val == '') ? val : (defaultVal ? defaultVal : null);
  };

  /**
   * Save a str to local storage.
   * @param {string} key
   * @param {any} val: value to store in string format
   */
  var _save = function(key, val) {
    localStorage.setItem(key, val);
  };

  return {
    save: _save,
    saveStr: _save,
    getStr: _retrieveStr,
    saveNumber: _save,

    /**
     * Retrieve a number from local storage.
     * @param {string} key
     * @param {num} defaultVal: default value to use if no valid one is retrieved
     */
    getNumber: function(key, defaultVal) {
      var val = _retrieveStr(key, null);
      return val ? parseFloat(val) : defaultVal;
    },

    /**
     * Retrieve an integer from local storage.
     * @param {string} key
     * @param {number} defaultVal: default value to use if no valid one is
     *                             retrieved.
     */
    getInt: function(key, defaultVal) {
      var val = _retrieveStr(key, null);
      return val ? parseInt(val) : defaultVal;
    },

    /**
     * Save an object to local storage.
     * @param {string} key
     * @param {obj} obj: object to save
     */
    saveObj: function(key, obj) {
      localStorage.setItem(key, JSON.stringify(obj));
    },

    /**
     * Retrieve an object from local storage.
     * @param {string} key
     * @param {obj} defaultVal: default obj to use if no valid one is retrieved
     * @param {obj} classPrototype: prototype to assign to the retrieved obj
     */
    getObj: function(key, defaultVal, classPrototype) {
      var val = _retrieveStr(key, null);
      if (val) {
        var obj = JSON.parse(val);
        if (classPrototype) {
          obj.__proto__ = classPrototype;
        }
        return obj;
      }
      return defaultVal;
    },

    /**
     * Clear local storage items by key pattern.
     * @param {regex} local storage key regex pattern, of those items to be
     *                removed
     * @return {number} number of items removed
     */
    clearByPattern: function(pattern) {
      var n = 0;
      var matchedResults = null;
      for (each in localStorage) {
        matchedResults = each.match(pattern);
        if (matchedResults) {
          localStorage.removeItem(each);
          n ++;
        }
      }
      return n;
    },

    /**
     * Clear all local storage data
     * @return {number} number of items removed
     */
    clearAll: function() {
      var n = 0;
      for (each in localStorage) {
        localStorage.removeItem(each);
        n ++;
      }
      return n;
    }
  };
})();

/**
 * debugUtils singleton
 */
var debugUtils = (function() {
  var _config = { enable: true };

  return {
    enable: function(enableIt) {
      _config.enable = enableIt;
    },

    /**
     * Print text to log
     * @param {string} text
     */
    log: function(text) {
      if (!_config.enable)
        return;
      console.log(text);
    },

    /**
     * Print text to log
     * @param {string} text
     */
    logObj: function(obj) {
      if (!_config.enable)
        return;
      console.log(JSON.stringify(obj));
    }
  };
})();

<|endoftext|>


<commit_before>(function($, undefined) {
    $.KBWidget({
        name: 'kbaseNarrativeSidePanel',
        parent: 'kbaseWidget',
        options: {
            loadingImage: "static/kbase/images/ajax-loader.gif",
            autorender: true,
        },
        $dataWidget: null,
        $methodsWidget: null,
        $narrativesWidget: null,
        $jobsWidget: null,
        $overlay: null,

        /**
         * Does the initial panel layout - tabs and spots for each widget
         * It then instantiates them, but not until told to render (unless autorender = true)
         */
        init: function(options) {
            this._super(options);

            var analysisWidgets = this.buildPanelSet([
                {
                    name : 'kbaseNarrativeDataPanel',
                    params : {}
                },
                {
                    name : 'kbaseNarrativeMethodPanel',
                    params : { autopopulate: false }
                }
            ]);
            this.$dataWidget = analysisWidgets['kbaseNarrativeDataPanel'];
            this.$methodsWidget = analysisWidgets['kbaseNarrativeMethodPanel'];
            var $analysisPanel = analysisWidgets['panelSet'];

            var manageWidgets = this.buildPanelSet([
                {
                    name : 'kbaseNarrativeAppsPanel',
                    params : { autopopulate: true }
                },
                {
                    name : 'kbaseNarrativeJobsPanel',
                    params : { autopopulate: false }
                }
            ]);

            this.$narrativesWidget = manageWidgets['kbaseNarrativeAppsPanel'];
            this.$jobsWidget = manageWidgets['kbaseNarrativeJobsPanel'];
            var $managePanel = manageWidgets['panelSet'];

            var $tabs = this.buildTabs([
                {
                    tabName : 'Analyze',
                    content : $analysisPanel
                },
                {
                    tabName : 'Manage',
                    content: $managePanel
                }
            ]);

            this.$elem.addClass('kb-side-panel');
            this.$elem.append($tabs.header).append($tabs.body);

            $(document).on('toggleSidePanelOverlay.Narrative', $.proxy(function(event) {
                this.toggleOverlay();
            }, this));

            if (this.autorender) {
                this.render();
            }
            else {

            }
            // add the stuff to the tabs

            return this;
        },

        buildTabs: function(tabs) {
            var $header = $('
');
            var $body = $('
');

            for (var i=0; i<tabs.length; i++) {
                var tab = tabs[i];
                $header.append($('
')
                               .addClass('kb-side-header')
                               .append(tab.tabName));
                $body.append($('
')
                             .addClass('kb-side-tab')
                             .append(tab.content));
            }

            $header.find('div').click(function(event) {
                event.preventDefault();
                event.stopPropagation();
                var $headerDiv = $(event.currentTarget);

                if (!$headerDiv.hasClass('active')) {
                    var idx = $headerDiv.index();
                    $header.find('div').removeClass('active');
                    $headerDiv.addClass('active');
                    $body.find('div.kb-side-tab').removeClass('active');
                    $body.find('div:nth-child(' + (idx+1) + ').kb-side-tab').addClass('active');
                }
            });

            $header.find('div:first-child').addClass('active');
            $body.find('div:first-child.kb-side-tab').addClass('active');

            return {
                header: $header,
                body: $body
            };
        },

        initOverlay: function() {
            var $overlayHeader = $('
')
                                 .addClass('kb-side-overlay-header')
                                 .append('Header!')
                                 .append($('
')
                                        .addClass('pull-right')
                                        .append($('')
                                                .addClass('kb-side-overlay-close glyphicon glyphicon-remove')
                                        .click($.proxy(function(event) {
                                           this.toggleOverlay();
                                        }, this))));

            var $overlayBody = $('
empty
');

            this.$overlay = $('
')
                            .addClass('kb-side-overlay-container')
                            .append($overlayHeader)
                            .append($overlayBody);
            $('body').append(this.$overlay);
            this.$overlay.hide();

            this.$narrativeDimmer = $('
')
                                    .addClass('kb-overlay-dimmer');
            $('body').append(this.$narrativeDimmer);
            this.$narrativeDimmer.hide();
            this.updateOverlayPosition();
        },

        updateOverlayPosition: function() {
            this.$overlay.position({my: 'left top', at: 'right top', of: this.$elem});
            this.$narrativeDimmer.position({my: 'left top', at: 'right top', of: this.$elem});
        },

        toggleOverlay: function() {
            if (this.$overlay.is(':visible'))
                this.hideOverlay();
            else
                this.showOverlay();
        },

        showOverlay: function() {
            if (this.$overlay) {
                this.$narrativeDimmer.show();
                this.$elem.find('.kb-side-header').addClass('overlay-active');
                this.$overlay.show('slide', 'fast', $.proxy(function() {
                }, this));
            }
        },

        hideOverlay: function() {
            if (this.$overlay) {
                this.$narrativeDimmer.hide();
                this.$elem.find('.kb-side-header').removeClass('overlay-active');
                this.$overlay.hide('slide', 'fast', $.proxy(function() {
                }, this));
            }
        },

        /**
         * Builds the general structure for a panel set.
         * These are intended to start with 2 panels, but we can move from there if needed.
         *
         * (I'll jsdoc this up in a bit)
         * widgets = [
         *     {
         *         name: kbaseNarrativeDataPanel (for instance)
         *         params: {}
         *     }
         * ]
         * @param {object} widgets
         *
         */
        buildPanelSet: function(widgets) {
            var $panelSet = $('
')
                            .addClass('kb-narr-side-panel-set');
            if (!widgets || Object.prototype.toString.call(widgets) !== '[object Array]' || widgets.length === 0)
                return $panelSet;

            var height = 100 / widgets.length;
            var minHeight = 200;

            var retObj = {};
            for (var i=0; i<widgets.length; i++) {
                var widgetInfo = widgets[i];
                var $widgetDiv = $('
')
                                 .css({'height' : height + '%', 'border-bottom' : '5px solid #e0e0e0'});

                retObj[widgetInfo.name] = $widgetDiv[widgetInfo.name](widgetInfo.params);
                $panelSet.append($widgetDiv);
            }
            retObj['panelSet'] = $panelSet;
            return retObj;
        },

        render: function() {
            this.initOverlay();

            this.$methodsWidget.refreshFromService();
            setTimeout($.proxy(function() { this.$jobsWidget.refresh(); }, this), 750);

        }
    })
})( jQuery );<commit_msg>Removed (commented out for now) App panel from the 'Manage' tab in the sidebar.<commit_after>(function($, undefined) {
    $.KBWidget({
        name: 'kbaseNarrativeSidePanel',
        parent: 'kbaseWidget',
        options: {
            loadingImage: "static/kbase/images/ajax-loader.gif",
            autorender: true,
        },
        $dataWidget: null,
        $methodsWidget: null,
        $narrativesWidget: null,
        $jobsWidget: null,
        $overlay: null,

        /**
         * Does the initial panel layout - tabs and spots for each widget
         * It then instantiates them, but not until told to render (unless autorender = true)
         */
        init: function(options) {
            this._super(options);

            var analysisWidgets = this.buildPanelSet([
                {
                    name : 'kbaseNarrativeDataPanel',
                    params : {}
                },
                {
                    name : 'kbaseNarrativeMethodPanel',
                    params : { autopopulate: false }
                }
            ]);
            this.$dataWidget = analysisWidgets['kbaseNarrativeDataPanel'];
            this.$methodsWidget = analysisWidgets['kbaseNarrativeMethodPanel'];
            var $analysisPanel = analysisWidgets['panelSet'];

            var manageWidgets = this.buildPanelSet([
                // {
                //     name : 'kbaseNarrativeAppsPanel',
                //     params : { autopopulate: true }
                // },
                {
                    name : 'kbaseNarrativeJobsPanel',
                    params : { autopopulate: false }
                }
            ]);

            this.$narrativesWidget = manageWidgets['kbaseNarrativeAppsPanel'];
            this.$jobsWidget = manageWidgets['kbaseNarrativeJobsPanel'];
            var $managePanel = manageWidgets['panelSet'];

            var $tabs = this.buildTabs([
                {
                    tabName : 'Analyze',
                    content : $analysisPanel
                },
                {
                    tabName : 'Manage',
                    content: $managePanel
                }
            ]);

            this.$elem.addClass('kb-side-panel');
            this.$elem.append($tabs.header).append($tabs.body);

            $(document).on('toggleSidePanelOverlay.Narrative', $.proxy(function(event) {
                this.toggleOverlay();
            }, this));

            if (this.autorender) {
                this.render();
            }
            else {

            }
            // add the stuff to the tabs

            return this;
        },

        buildTabs: function(tabs) {
            var $header = $('
');
            var $body = $('
');

            for (var i=0; i<tabs.length; i++) {
                var tab = tabs[i];
                $header.append($('
')
                               .addClass('kb-side-header')
                               .append(tab.tabName));
                $body.append($('
')
                             .addClass('kb-side-tab')
                             .append(tab.content));
            }

            $header.find('div').click(function(event) {
                event.preventDefault();
                event.stopPropagation();
                var $headerDiv = $(event.currentTarget);

                if (!$headerDiv.hasClass('active')) {
                    var idx = $headerDiv.index();
                    $header.find('div').removeClass('active');
                    $headerDiv.addClass('active');
                    $body.find('div.kb-side-tab').removeClass('active');
                    $body.find('div:nth-child(' + (idx+1) + ').kb-side-tab').addClass('active');
                }
            });

            $header.find('div:first-child').addClass('active');
            $body.find('div:first-child.kb-side-tab').addClass('active');

            return {
                header: $header,
                body: $body
            };
        },

        initOverlay: function() {
            var $overlayHeader = $('
')
                                 .addClass('kb-side-overlay-header')
                                 .append('Header!')
                                 .append($('
')
                                        .addClass('pull-right')
                                        .append($('')
                                                .addClass('kb-side-overlay-close glyphicon glyphicon-remove')
                                        .click($.proxy(function(event) {
                                           this.toggleOverlay();
                                        }, this))));

            var $overlayBody = $('
empty
');

            this.$overlay = $('
')
                            .addClass('kb-side-overlay-container')
                            .append($overlayHeader)
                            .append($overlayBody);
            $('body').append(this.$overlay);
            this.$overlay.hide();

            this.$narrativeDimmer = $('
')
                                    .addClass('kb-overlay-dimmer');
            $('body').append(this.$narrativeDimmer);
            this.$narrativeDimmer.hide();
            this.updateOverlayPosition();
        },

        updateOverlayPosition: function() {
            this.$overlay.position({my: 'left top', at: 'right top', of: this.$elem});
            this.$narrativeDimmer.position({my: 'left top', at: 'right top', of: this.$elem});
        },

        toggleOverlay: function() {
            if (this.$overlay.is(':visible'))
                this.hideOverlay();
            else
                this.showOverlay();
        },

        showOverlay: function() {
            if (this.$overlay) {
                this.$narrativeDimmer.show();
                this.$elem.find('.kb-side-header').addClass('overlay-active');
                this.$overlay.show('slide', 'fast', $.proxy(function() {
                }, this));
            }
        },

        hideOverlay: function() {
            if (this.$overlay) {
                this.$narrativeDimmer.hide();
                this.$elem.find('.kb-side-header').removeClass('overlay-active');
                this.$overlay.hide('slide', 'fast', $.proxy(function() {
                }, this));
            }
        },

        /**
         * Builds the general structure for a panel set.
         * These are intended to start with 2 panels, but we can move from there if needed.
         *
         * (I'll jsdoc this up in a bit)
         * widgets = [
         *     {
         *         name: kbaseNarrativeDataPanel (for instance)
         *         params: {}
         *     }
         * ]
         * @param {object} widgets
         *
         */
        buildPanelSet: function(widgets) {
            var $panelSet = $('
')
                            .addClass('kb-narr-side-panel-set');
            if (!widgets || Object.prototype.toString.call(widgets) !== '[object Array]' || widgets.length === 0)
                return $panelSet;

            var height = 100 / widgets.length;
            var minHeight = 200;

            var retObj = {};
            for (var i=0; i<widgets.length; i++) {
                var widgetInfo = widgets[i];
                var $widgetDiv = $('
')
                                 .css({'height' : height + '%', 'border-bottom' : '5px solid #e0e0e0'});

                retObj[widgetInfo.name] = $widgetDiv[widgetInfo.name](widgetInfo.params);
                $panelSet.append($widgetDiv);
            }
            retObj['panelSet'] = $panelSet;
            return retObj;
        },

        render: function() {
            this.initOverlay();

            this.$methodsWidget.refreshFromService();
            setTimeout($.proxy(function() { this.$jobsWidget.refresh(); }, this), 750);

        }
    })
})( jQuery );<|endoftext|>


<commit_before>//main functions
var helper = require('./lib/Shared');
var Wall = require('./lib/Wall');

//libs
var ioc = require('socket.io-client');
var socket = ioc.connect('http://localhost:3000');

//animations
var ScrollText = require('./animations/ScrollText');
var ScoreBoard = require('./animations/ScoreBoard');
var Ola = require('./animations/Ola');
var Music = require('./animations/Music');
var Idle = require('./animations/Idle');

//walls with motors
var roof = new Wall(374, 11, 'top', 0, socket),
    leftWall = new Wall(170, 34, 'left', 4, socket),
    frontWall = new Wall(55, 11, 'front', 0, socket),
    rightWall = new Wall(170, 34, 'right', 0, socket);
roof.init();
leftWall.init();
frontWall.init();
rightWall.init();

var Redis = require('./lib/redis'),
    r = new Redis(),
    lastAck = Date.now(),
    healthStatus = { healthy: true, lastAck: 0 };
var emitHealthStatus = function(healthy) {
    if(healthy !== undefined) {
        healthStatus = { healthy, lastAck };
    }
    socket.emit('ackHealth', healthStatus);
}
r.ackCallback = function() {
    lastAck = Date.now();
}
var enginesWatchDog = function() {
    var diff = Date.now() - lastAck;
    if(diff >= 2000 && healthStatus.healthy) {
        emitHealthStatus(false);
    } else if(diff <= 2000 && !healthStatus.healthStatus) {
        emitHealthStatus(true);
    }
}

setInterval(enginesWatchDog, 1000);

//all animations
var currentAnimations = [];

//mapped motors to send to Redis
var FACE_BITMAP = {
    map: [
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,0  -> 44,0
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,1  -> 44,1
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,2  -> 44,2
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,3  -> 44,3
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,4  -> 44,4
    ]
};
var TOP_BITMAP = {
    map: [
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,0  -> 10,0
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,1  -> 10,1
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,2  -> 10,2
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,3  -> 10,3
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,4  -> 10,4
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,5  -> 10,5
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,6  -> 10,6
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,7  -> 10,7
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,8  -> 10,8
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,9  -> 10,9
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,10 -> 10,10
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,11 -> 10,11
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,12 -> 10,12
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,13 -> 10,13
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,14 -> 10,14
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,15 -> 10,15
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14] //line 0,16 -> 10,16
    ]
};

(function UpdateBackend() {
    roof.motors.forEach((motor) => {
        TOP_BITMAP.map[motor.y][motor.x] = motor.command;
    });
    rightWall.motors.forEach((motor) => {
        FACE_BITMAP.map[motor.y][motor.x+28] = motor.command;
    });
    frontWall.motors.forEach((motor) => {
        FACE_BITMAP.map[motor.y][motor.x+17] = motor.command;
    });
    leftWall.motors.forEach((motor) => {
        FACE_BITMAP.map[motor.y][motor.x] = motor.command;
    });
    r.send('FACE_BITMAP', FACE_BITMAP);
    r.send('TOP_BITMAP', TOP_BITMAP);
    setTimeout(UpdateBackend, roof.motors[0].getFPS());
}).call(this);

//init socket
socket.on('connect', () => {
        helper.logger.debug('[Processor] Connected to port 3000');
        emitHealthStatus();
    })
    .on('exec', (command) => {
        helper.logger.debug(`[Processor] Received Command ${command.animation}`);
        var animation = '';
        if (command.animation == 'ScrollText') {
            animation = new ScrollText(command.message, 13, [rightWall, frontWall, leftWall, roof], command.continuous, command.loop);
            animation.init();
        } else if (command.animation == 'ScoreBoard') {
            animation = new ScoreBoard({
                country1: command.country1,
                score1: command.score1,
                country2: command.country2,
                score2: command.score2
            }, [rightWall, frontWall, leftWall, roof], command.loop);
            animation.init();
        } else if (command.animation == 'Ola') {
            animation = new Ola(command.type, 13, [rightWall, frontWall, leftWall, roof], command.loop);
            animation.init();
        } else if (command.animation == 'Music') {
            animation = new Music(command.type, 13, [rightWall, frontWall, leftWall, roof]);
            animation.init();
        } else if (command.animation == 'Idle') {
            animation = new Idle(command.type, 18, [rightWall, frontWall, leftWall, roof], command.loop);
            idle.init();
        } else if (command.animation == 'BasicAngle') {
            [rightWall, frontWall, leftWall, roof].forEach((wall) => {
                wall.motors.forEach((motor) => {
                    motor.sendCommand(command.angle);
                });
            });
        } else {
            if (command >= 0xFB && command <= 0xFF) {
                [rightWall, frontWall, leftWall, roof].forEach((wall) => {
                    wall.motors.forEach((motor) => {
                        motor.sendCommand(command);
                    })
                    wall.locked = false;
                });
            }
        }
        if (animation && animation.name) {
            currentAnimations.push(animation);
        }
    })
    .on('freeze', () => {
        var noop = () => {};
        currentAnimations.forEach((animation) => {
            Object.keys(animation).forEach((key) => animation[key] = noop);
            animation = null;
        });
        currentAnimations = [];
    })
    .on('disconnect', () => {
        helper.logger.debug('[Processor] Disconnected from port 3000');
    });
<commit_msg>Fix Processor health status emissor rate<commit_after>//main functions
var helper = require('./lib/Shared');
var Wall = require('./lib/Wall');

//libs
var ioc = require('socket.io-client');
var socket = ioc.connect('http://localhost:3000');

//animations
var ScrollText = require('./animations/ScrollText');
var ScoreBoard = require('./animations/ScoreBoard');
var Ola = require('./animations/Ola');
var Music = require('./animations/Music');
var Idle = require('./animations/Idle');

//walls with motors
var roof = new Wall(374, 11, 'top', 0, socket),
    leftWall = new Wall(170, 34, 'left', 4, socket),
    frontWall = new Wall(55, 11, 'front', 0, socket),
    rightWall = new Wall(170, 34, 'right', 0, socket);
roof.init();
leftWall.init();
frontWall.init();
rightWall.init();

var Redis = require('./lib/redis'),
    r = new Redis(),
    lastAck = Date.now(),
    healthStatus = { healthy: true, lastAck: 0 };
var emitHealthStatus = function(healthy) {
    if(healthy !== undefined) {
        healthStatus = { healthy, lastAck };
    }
    socket.emit('ackHealth', healthStatus);
}
r.ackCallback = function() {
    lastAck = Date.now();
}
var enginesWatchDog = function() {
    var diff = Date.now() - lastAck;
    if(diff >= 2000 && healthStatus.healthy) {
        emitHealthStatus(false);
    } else if(diff <= 2000 && !healthStatus.healthy) {
        emitHealthStatus(true);
    }
}

setInterval(enginesWatchDog, 1000);

//all animations
var currentAnimations = [];

//mapped motors to send to Redis
var FACE_BITMAP = {
    map: [
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,0  -> 44,0
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,1  -> 44,1
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,2  -> 44,2
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,3  -> 44,3
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,4  -> 44,4
    ]
};
var TOP_BITMAP = {
    map: [
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,0  -> 10,0
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,1  -> 10,1
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,2  -> 10,2
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,3  -> 10,3
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,4  -> 10,4
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,5  -> 10,5
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,6  -> 10,6
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,7  -> 10,7
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,8  -> 10,8
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,9  -> 10,9
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,10 -> 10,10
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,11 -> 10,11
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,12 -> 10,12
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,13 -> 10,13
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,14 -> 10,14
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14], //line 0,15 -> 10,15
        [0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14] //line 0,16 -> 10,16
    ]
};

(function UpdateBackend() {
    roof.motors.forEach((motor) => {
        TOP_BITMAP.map[motor.y][motor.x] = motor.command;
    });
    rightWall.motors.forEach((motor) => {
        FACE_BITMAP.map[motor.y][motor.x+28] = motor.command;
    });
    frontWall.motors.forEach((motor) => {
        FACE_BITMAP.map[motor.y][motor.x+17] = motor.command;
    });
    leftWall.motors.forEach((motor) => {
        FACE_BITMAP.map[motor.y][motor.x] = motor.command;
    });
    r.send('FACE_BITMAP', FACE_BITMAP);
    r.send('TOP_BITMAP', TOP_BITMAP);
    setTimeout(UpdateBackend, roof.motors[0].getFPS());
}).call(this);

//init socket
socket.on('connect', () => {
        helper.logger.debug('[Processor] Connected to port 3000');
        emitHealthStatus();
    })
    .on('exec', (command) => {
        helper.logger.debug(`[Processor] Received Command ${command.animation}`);
        var animation = '';
        if (command.animation == 'ScrollText') {
            animation = new ScrollText(command.message, 13, [rightWall, frontWall, leftWall, roof], command.continuous, command.loop);
            animation.init();
        } else if (command.animation == 'ScoreBoard') {
            animation = new ScoreBoard({
                country1: command.country1,
                score1: command.score1,
                country2: command.country2,
                score2: command.score2
            }, [rightWall, frontWall, leftWall, roof], command.loop);
            animation.init();
        } else if (command.animation == 'Ola') {
            animation = new Ola(command.type, 13, [rightWall, frontWall, leftWall, roof], command.loop);
            animation.init();
        } else if (command.animation == 'Music') {
            animation = new Music(command.type, 13, [rightWall, frontWall, leftWall, roof]);
            animation.init();
        } else if (command.animation == 'Idle') {
            animation = new Idle(command.type, 18, [rightWall, frontWall, leftWall, roof], command.loop);
            idle.init();
        } else if (command.animation == 'BasicAngle') {
            [rightWall, frontWall, leftWall, roof].forEach((wall) => {
                wall.motors.forEach((motor) => {
                    motor.sendCommand(command.angle);
                });
            });
        } else {
            if (command >= 0xFB && command <= 0xFF) {
                [rightWall, frontWall, leftWall, roof].forEach((wall) => {
                    wall.motors.forEach((motor) => {
                        motor.sendCommand(command);
                    })
                    wall.locked = false;
                });
            }
        }
        if (animation && animation.name) {
            currentAnimations.push(animation);
        }
    })
    .on('freeze', () => {
        var noop = () => {};
        currentAnimations.forEach((animation) => {
            Object.keys(animation).forEach((key) => animation[key] = noop);
            animation = null;
        });
        currentAnimations = [];
    })
    .on('disconnect', () => {
        helper.logger.debug('[Processor] Disconnected from port 3000');
    });
<|endoftext|>


<commit_before>/*!
 * Waves v0.7.5
 * http://fian.my.id/Waves
 *
 * Copyright 2014-2016 Alfiana E. Sibuea and other contributors
 * Released under the MIT license
 * https://github.com/fians/Waves/blob/master/LICENSE
 */

;(function(window, factory) {
    'use strict';

    // AMD. Register as an anonymous module.  Wrap in function so we have access
    // to root via `this`.
    if (typeof define === 'function' && define.amd) {
        define([], function() {
            return factory.apply(window);
        });
    }

    // Node. Does not work with strict CommonJS, but only CommonJS-like
    // environments that support module.exports, like Node.
    else if (typeof exports === 'object') {
        module.exports = factory.call(window);
    }

    // Browser globals.
    else {
        window.Waves = factory.call(window);
    }
})(typeof global === 'object' ? global : this, function() {
    'use strict';

    var Waves            = Waves || {};
    var $$               = document.querySelectorAll.bind(document);
    var toString         = Object.prototype.toString;
    var isTouchAvailable = 'ontouchstart' in window;

    // Find exact position of element
    function isWindow(obj) {
        return obj !== null && obj === obj.window;
    }

    function getWindow(elem) {
        return isWindow(elem) ? elem : elem.nodeType === 9 && elem.defaultView;
    }

    function isObject(value) {
        var type = typeof value;
        return type === 'function' || type === 'object' && !!value;
    }

    function isDOMNode(obj) {
        return isObject(obj) && obj.nodeType > 0;
    }

    function getWavesElements(nodes) {
        var stringRepr = toString.call(nodes);

        if (stringRepr === '[object String]') {
            return $$(nodes);
        } else if (isObject(nodes) && /^\[object (Array|HTMLCollection|NodeList|Object)\]$/.test(stringRepr) && nodes.hasOwnProperty('length')) {
            return nodes;
        } else if (isDOMNode(nodes)) {
            return [nodes];
        }

        return [];
    }

    function offset(elem) {
        var docElem, win,
            box = { top: 0, left: 0 },
            doc = elem && elem.ownerDocument;

        docElem = doc.documentElement;

        if (typeof elem.getBoundingClientRect !== typeof undefined) {
            box = elem.getBoundingClientRect();
        }
        win = getWindow(doc);
        return {
            top: box.top + win.pageYOffset - docElem.clientTop,
            left: box.left + win.pageXOffset - docElem.clientLeft
        };
    }

    function convertStyle(styleObj) {
        var style = '';

        for (var prop in styleObj) {
            if (styleObj.hasOwnProperty(prop)) {
                style += (prop + ':' + styleObj[prop] + ';');
            }
        }

        return style;
    }

    var Effect = {

        // Effect duration
        duration: 750,

        // Effect delay (check for scroll before showing effect)
        delay: 200,

        show: function(e, element, velocity) {

            // Disable right click
            if (e.button === 2) {
                return false;
            }

            element = element || this;

            // Create ripple
            var ripple = document.createElement('div');
            ripple.className = 'waves-ripple waves-rippling';
            element.appendChild(ripple);

            // Get click coordinate and element width
            var pos       = offset(element);
            var relativeY = 0;
            var relativeX = 0;
            // Support for touch devices
            if('touches' in e && e.touches.length) {
                relativeY   = (e.touches[0].pageY - pos.top);
                relativeX   = (e.touches[0].pageX - pos.left);
            }
            //Normal case
            else {
                relativeY   = (e.pageY - pos.top);
                relativeX   = (e.pageX - pos.left);
            }
            // Support for synthetic events
            relativeX = relativeX >= 0 ? relativeX : 0;
            relativeY = relativeY >= 0 ? relativeY : 0;

            var scale     = 'scale(' + ((element.clientWidth / 100) * 3) + ')';
            var translate = 'translate(0,0)';

            if (velocity) {
                translate = 'translate(' + (velocity.x) + 'px, ' + (velocity.y) + 'px)';
            }

            // Attach data to element
            ripple.setAttribute('data-hold', Date.now());
            ripple.setAttribute('data-x', relativeX);
            ripple.setAttribute('data-y', relativeY);
            ripple.setAttribute('data-scale', scale);
            ripple.setAttribute('data-translate', translate);

            // Set ripple position
            var rippleStyle = {
                top: relativeY + 'px',
                left: relativeX + 'px'
            };

            ripple.classList.add('waves-notransition');
            ripple.setAttribute('style', convertStyle(rippleStyle));
            ripple.classList.remove('waves-notransition');

            // Scale the ripple
            rippleStyle['-webkit-transform'] = scale + ' ' + translate;
            rippleStyle['-moz-transform'] = scale + ' ' + translate;
            rippleStyle['-ms-transform'] = scale + ' ' + translate;
            rippleStyle['-o-transform'] = scale + ' ' + translate;
            rippleStyle.transform = scale + ' ' + translate;
            rippleStyle.opacity = '1';

            var duration = e.type === 'mousemove' ? 2500 : Effect.duration;
            rippleStyle['-webkit-transition-duration'] = duration + 'ms';
            rippleStyle['-moz-transition-duration']    = duration + 'ms';
            rippleStyle['-o-transition-duration']      = duration + 'ms';
            rippleStyle['transition-duration']         = duration + 'ms';

            ripple.setAttribute('style', convertStyle(rippleStyle));
        },

        hide: function(e, element) {
            element = element || this;

            var ripples = element.getElementsByClassName('waves-rippling');

            for (var i = 0, len = ripples.length; i < len; i++) {
                removeRipple(e, element, ripples[i]);
            }

            if (isTouchAvailable) {
                element.removeEventListener('touchend', Effect.hide);
                element.removeEventListener('touchcancel', Effect.hide);
            }

            element.removeEventListener('mouseup', Effect.hide);
            element.removeEventListener('mouseleave', Effect.hide);
        }
    };

    /**
     * Collection of wrapper for HTML element that only have single tag
     * like <input> and <img>
     */
    var TagWrapper = {

        // Wrap <input> tag so it can perform the effect
        input: function(element) {

            var parent = element.parentNode;

            // If input already have parent just pass through
            if (parent.tagName.toLowerCase() === 'i' && parent.classList.contains('waves-effect')) {
                return;
            }

            // Put element class and style to the specified parent
            var wrapper       = document.createElement('i');
            wrapper.className = element.className + ' waves-input-wrapper';
            element.className = 'waves-button-input';

            // Put element as child
            parent.replaceChild(wrapper, element);
            wrapper.appendChild(element);

            // Apply element color and background color to wrapper
            var elementStyle    = window.getComputedStyle(element, null);
            var color           = elementStyle.color;
            var backgroundColor = elementStyle.backgroundColor;

            wrapper.setAttribute('style', 'color:' + color + ';background:' + backgroundColor);
            element.setAttribute('style', 'background-color:rgba(0,0,0,0);');

        },

        // Wrap <img> tag so it can perform the effect
        img: function(element) {

            var parent = element.parentNode;

            // If input already have parent just pass through
            if (parent.tagName.toLowerCase() === 'i' && parent.classList.contains('waves-effect')) {
                return;
            }

            // Put element as child
            var wrapper  = document.createElement('i');
            parent.replaceChild(wrapper, element);
            wrapper.appendChild(element);

        }
    };

    /**
     * Hide the effect and remove the ripple. Must be
     * a separate function to pass the JSLint...
     */
    function removeRipple(e, el, ripple) {

        // Check if the ripple still exist
        if (!ripple) {
            return;
        }

        ripple.classList.remove('waves-rippling');

        var relativeX = ripple.getAttribute('data-x');
        var relativeY = ripple.getAttribute('data-y');
        var scale     = ripple.getAttribute('data-scale');
        var translate = ripple.getAttribute('data-translate');

        // Get delay beetween mousedown and mouse leave
        var diff = Date.now() - Number(ripple.getAttribute('data-hold'));
        var delay = 350 - diff;

        if (delay < 0) {
            delay = 0;
        }

        if (e.type === 'mousemove') {
            delay = 150;
        }

        // Fade out ripple after delay
        var duration = e.type === 'mousemove' ? 2500 : Effect.duration;

        setTimeout(function() {

            var style = {
                top: relativeY + 'px',
                left: relativeX + 'px',
                opacity: '0',

                // Duration
                '-webkit-transition-duration': duration + 'ms',
                '-moz-transition-duration': duration + 'ms',
                '-o-transition-duration': duration + 'ms',
                'transition-duration': duration + 'ms',
                '-webkit-transform': scale + ' ' + translate,
                '-moz-transform': scale + ' ' + translate,
                '-ms-transform': scale + ' ' + translate,
                '-o-transform': scale + ' ' + translate,
                'transform': scale + ' ' + translate
            };

            ripple.setAttribute('style', convertStyle(style));

            setTimeout(function() {
                try {
                    el.removeChild(ripple);
                } catch (e) {
                    return false;
                }
            }, duration);

        }, delay);
    }

    /**
     * Disable mousedown event for 500ms during and after touch
     */
    var TouchHandler = {

        /* uses an integer rather than bool so there's no issues with
         * needing to clear timeouts if another touch event occurred
         * within the 500ms. Cannot mouseup between touchstart and
         * touchend, nor in the 500ms after touchend. */
        touches: 0,

        allowEvent: function(e) {

            var allow = true;

            if (/^(mousedown|mousemove)$/.test(e.type) && TouchHandler.touches) {
                allow = false;
            }

            return allow;
        },
        registerEvent: function(e) {
            var eType = e.type;

            if (eType === 'touchstart') {

                TouchHandler.touches += 1; // push

            } else if (/^(touchend|touchcancel)$/.test(eType)) {

                setTimeout(function() {
                    if (TouchHandler.touches) {
                        TouchHandler.touches -= 1; // pop after 500ms
                    }
                }, 500);

            }
        }
    };

    /**
     * Delegated click handler for .waves-effect element.
     * returns null when .waves-effect element not in "click tree"
     */
    function getWavesEffectElement(e) {

        if (TouchHandler.allowEvent(e) === false) {
            return null;
        }

        var element = null;
        var target = e.target || e.srcElement;

        while (target.parentElement) {
            if ( (!(target instanceof SVGElement)) && target.classList.contains('waves-effect')) {
                element = target;
                break;
            }
            target = target.parentElement;
        }

        return element;
    }

    /**
     * Bubble the click and show effect if .waves-effect elem was found
     */
    function showEffect(e) {

        // Disable effect if element has "disabled" property on it
        // In some cases, the event is not triggered by the current element
        // if (e.target.getAttribute('disabled') !== null) {
        //     return;
        // }

        var element = getWavesEffectElement(e);

        if (element !== null) {

            // Make it sure the element has either disabled property, disabled attribute or 'disabled' class
            if (element.disabled || element.getAttribute('disabled') || element.classList.contains('disabled')) {
                return;
            }

            TouchHandler.registerEvent(e);

            if (e.type === 'touchstart' && Effect.delay) {

                var hidden = false;

                var timer = setTimeout(function () {
                    timer = null;
                    Effect.show(e, element);
                }, Effect.delay);

                var hideEffect = function(hideEvent) {

                    // if touch hasn't moved, and effect not yet started: start effect now
                    if (timer) {
                        clearTimeout(timer);
                        timer = null;
                        Effect.show(e, element);
                    }
                    if (!hidden) {
                        hidden = true;
                        Effect.hide(hideEvent, element);
                    }

                    removeListeners();
                };

                var touchMove = function(moveEvent) {
                    if (timer) {
                        clearTimeout(timer);
                        timer = null;
                    }
                    hideEffect(moveEvent);

                    removeListeners();
                };

                element.addEventListener('touchmove', touchMove, false);
                element.addEventListener('touchend', hideEffect, false);
                element.addEventListener('touchcancel', hideEffect, false);

                var removeListeners = function() {
                    element.removeEventListener('touchmove', touchMove);
                    element.removeEventListener('touchend', hideEffect);
                    element.removeEventListener('touchcancel', hideEffect);
                };
            } else {

                Effect.show(e, element);

                if (isTouchAvailable) {
                    element.addEventListener('touchend', Effect.hide, false);
                    element.addEventListener('touchcancel', Effect.hide, false);
                }

                element.addEventListener('mouseup', Effect.hide, false);
                element.addEventListener('mouseleave', Effect.hide, false);
            }
        }
    }

    Waves.init = function(options) {
        var body = document.body;

        options = options || {};

        if ('duration' in options) {
            Effect.duration = options.duration;
        }

        if ('delay' in options) {
            Effect.delay = options.delay;
        }

        if (isTouchAvailable) {
            body.addEventListener('touchstart', showEffect, false);
            body.addEventListener('touchcancel', TouchHandler.registerEvent, false);
            body.addEventListener('touchend', TouchHandler.registerEvent, false);
        }

        body.addEventListener('mousedown', showEffect, false);
    };

    /**
     * Attach Waves to dynamically loaded inputs, or add .waves-effect and other
     * waves classes to a set of elements. Set drag to true if the ripple mouseover
     * or skimming effect should be applied to the elements.
     */
    Waves.attach = function(elements, classes) {

        elements = getWavesElements(elements);

        if (toString.call(classes) === '[object Array]') {
            classes = classes.join(' ');
        }

        classes = classes ? ' ' + classes : '';

        var element, tagName;

        for (var i = 0, len = elements.length; i < len; i++) {

            element = elements[i];
            tagName = element.tagName.toLowerCase();

            if (['input', 'img'].indexOf(tagName) !== -1) {
                TagWrapper[tagName](element);
                element = element.parentElement;
            }

            if (element.className.indexOf('waves-effect') === -1) {
                element.className += ' waves-effect' + classes;
            }
        }
    };

    /**
     * Cause a ripple to appear in an element via code.
     */
    Waves.ripple = function(elements, options) {
        elements = getWavesElements(elements);
        var elementsLen = elements.length;

        options          = options || {};
        options.wait     = options.wait || 0;
        options.position = options.position || null; // default = centre of element

        if (elementsLen) {
            var element, pos, off, centre = {}, i = 0;
            var mousedown = {
                type: 'mousedown',
                button: 1
            };
            var hideRipple = function(mouseup, element) {
                return function() {
                    Effect.hide(mouseup, element);
                };
            };

            for (; i < elementsLen; i++) {
                element = elements[i];
                pos = options.position || {
                    x: element.clientWidth / 2,
                    y: element.clientHeight / 2
                };

                off      = offset(element);
                centre.x = off.left + pos.x;
                centre.y = off.top + pos.y;

                mousedown.pageX = centre.x;
                mousedown.pageY = centre.y;

                Effect.show(mousedown, element);

                if (options.wait >= 0 && options.wait !== null) {
                    var mouseup = {
                        type: 'mouseup',
                        button: 1
                    };

                    setTimeout(hideRipple(mouseup, element), options.wait);
                }
            }
        }
    };

    /**
     * Remove all ripples from an element.
     */
    Waves.calm = function(elements) {
        elements = getWavesElements(elements);
        var mouseup = {
            type: 'mouseup',
            button: 1
        };

        for (var i = 0, len = elements.length; i < len; i++) {
            Effect.hide(mouseup, elements[i]);
        }
    };

    /**
     * Deprecated API fallback
     */
    Waves.displayEffect = function(options) {
        console.error('Waves.displayEffect() has been deprecated and will be removed in future version. Please use Waves.init() to initialize Waves effect');
        Waves.init(options);
    };

    return Waves;
});
<commit_msg>Delete waves.js<commit_after><|endoftext|>