<commit_before>/**
 * mySlider (http://github.com/stefanotorresi/myslider)
 *
 * Copyright (c) 2013 Stefano Torresi (http://stefanotorresi.it)
 * See the file LICENSE.txt for copying permission.
 * ************************************************
 */

(function($){

    var Slideshow = function (container, options) {
        this.$container = $(container);
        this.options = options;
        this.$slides = this.$container.children(options.slideSelector);
        this.$current = this.$slides.first();

        if (options.autoStart) {
            this.play();
        }

        if (options.pauseOnHover) {
            this.$container.on('mouseenter', $.proxy(this.pause, this) );
            this.$container.on('mouseleave', $.proxy(this.play, this) );
        }

        if (options.controls) {

            this.$buttons = $('
prevnext
');

            this.$container.append(this.$buttons);

            this.$buttons.children('.prev').click($.proxy(function(e){
                this.prev();
                return false;
            }, this));

            this.$buttons.children('.next').click($.proxy(function(e){
                this.next();
                return false;
            }, this));

            if(options.fadeControls) {
                this.$container.on('mouseenter', $.proxy(function() {
                    if (this.csstransitions) {
                        this.$buttons.css('opacity', 1);
                    } else {
                        this.$buttons.fadeIn('fast');
                    }
                }, this));

                this.$container.on('mouseleave', $.proxy(function() {
                    if (this.csstransitions) {
                        this.$buttons.css('opacity', 0);
                    } else {
                        this.$buttons.fadeOut('fast');
                    }
                }, this));

                if (this.csstransitions) {
                    this.$buttons.css({
                        'transition' : 'opacity 200ms',
                        '-moz-transition': 'opacity 200ms',
                        '-webkit-transition': 'opacity 200ms'
                    });
                }
            } else {
                this.$buttons.show();
            }
        }

        if (options.pager) {

            this.$pager = $('

');

            this.$container.append(this.$pager);

            this.$slides.each($.proxy(function(index, element){
                var $link = $('');
                $link.data('slideIndex', index);

                if (index == 0) {
                    $link.addClass('active');
                }

                $link.click($.proxy(function(e){
                    var index = $(e.target).data('slideIndex');
                    this.slideTo(this.$slides.eq(index));

                    return false;
                }, this));

                this.$pager.append($link);
            }, this));

        }

        if (this.csstransitions) {
            this.$slides.css('transition', 'opacity '+options.speed+'ms');
            this.$slides.css('-moz-transition', 'opacity '+options.speed+'ms');
            this.$slides.css('-webkit-transition', 'opacity '+options.speed+'ms');
        }
    }

    Slideshow.prototype = {

        csstransitions : typeof Modernizr !== 'undefined' && Modernizr.csstransitions,
        cycling :    false,

        play : function () {
            this.cycling = true;

            this.interval = setInterval($.proxy(function() {
                this.next();
            }, this), this.options.interval );

            return this;
        },

        pause : function() {
            clearInterval(this.interval);
            this.cycling = false;

            return this;
        },

        slideTo : function($slide) {
            clearInterval(this.interval);

            var $siblings = $slide.siblings(this.options.slideSelector);

            $siblings.removeClass('active');
            $slide.addClass('active');
            this.$current = $slide;

            if (this.csstransitions) {
                $slide.one("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", $.proxy(function(event) {
                    this.cycling && this.play();
                }, this));
                $siblings.css('opacity', 0);
                $slide.css('opacity', 1);
            } else {
                $slide.stop(true).fadeTo(this.options.speed, 1, $.proxy(function(){
                    this.cycling && this.play();
                }, this));
                $siblings.stop(true).fadeTo(this.options.speed, 0);
            }

            if (this.options.pager) {
                var index = this.$slides.index($slide);
                var $pagerLink = this.$pager.children().eq(index);
                $pagerLink.addClass('active');
                $pagerLink.siblings().removeClass('active');
            }

            return this;
        },

        next : function () {
            var $next;

            if (this.$current.next(this.options.slideSelector).length) {
                $next = this.$current.next();
            } else {
                $next = this.$slides.first();
            }

            return this.slideTo($next);
        },

        prev : function () {
            var $prev;

            if (this.$current.prev(this.options.slideSelector).length) {
                $prev = this.$current.prev();
            } else {
                $prev = this.$slides.last();
            }

            return this.slideTo($prev);
        }

    }

    $.fn.mySlider = function (options) {

        options = $.extend({
            interval :          5000,
            speed :             1000,
            slideSelector :     '.slide',
            autoStart :         true,
            controls:           true,
            fadeControls:       true,
            pauseOnHover:       false,
            pager:              true
        }, options);

        this.each(function(){
            var slideshow = new Slideshow(this, options);
            $(this).data('slideshow', slideshow);
            console.log(slideshow.csstransitions);
        });

        return this;

    }

})(jQuery)<commit_msg>fix interval not clearing when using css3 transitions<commit_after>/**
 * mySlider (http://github.com/stefanotorresi/myslider)
 *
 * Copyright (c) 2013 Stefano Torresi (http://stefanotorresi.it)
 * See the file LICENSE.txt for copying permission.
 * ************************************************
 */

(function($){

    var Slideshow = function (container, options) {
        this.$container = $(container);
        this.options = options;
        this.$slides = this.$container.children(options.slideSelector);
        this.$current = this.$slides.first();

        if (options.autoStart) {
            this.play();
        }

        if (options.pauseOnHover) {
            this.$container.on('mouseenter', $.proxy(this.pause, this) );
            this.$container.on('mouseleave', $.proxy(this.play, this) );
        }

        if (options.controls) {

            this.$buttons = $('
prevnext
');

            this.$container.append(this.$buttons);

            this.$buttons.children('.prev').click($.proxy(function(e){
                this.prev();
                return false;
            }, this));

            this.$buttons.children('.next').click($.proxy(function(e){
                this.next();
                return false;
            }, this));

            if(options.fadeControls) {
                this.$container.on('mouseenter', $.proxy(function() {
                    if (this.csstransitions) {
                        this.$buttons.css('opacity', 1);
                    } else {
                        this.$buttons.fadeIn('fast');
                    }
                }, this));

                this.$container.on('mouseleave', $.proxy(function() {
                    if (this.csstransitions) {
                        this.$buttons.css('opacity', 0);
                    } else {
                        this.$buttons.fadeOut('fast');
                    }
                }, this));

                if (this.csstransitions) {
                    this.$buttons.css({
                        'transition' : 'opacity 200ms',
                        '-moz-transition': 'opacity 200ms',
                        '-webkit-transition': 'opacity 200ms'
                    });
                }
            } else {
                this.$buttons.show();
            }
        }

        if (options.pager) {

            this.$pager = $('

');

            this.$container.append(this.$pager);

            this.$slides.each($.proxy(function(index, element){
                var $link = $('');
                $link.data('slideIndex', index);

                if (index == 0) {
                    $link.addClass('active');
                }

                $link.click($.proxy(function(e){
                    var index = $(e.target).data('slideIndex');
                    this.slideTo(this.$slides.eq(index));

                    return false;
                }, this));

                this.$pager.append($link);
            }, this));

        }

        if (this.csstransitions) {
            this.$slides.css('transition', 'opacity '+options.speed+'ms');
            this.$slides.css('-moz-transition', 'opacity '+options.speed+'ms');
            this.$slides.css('-webkit-transition', 'opacity '+options.speed+'ms');
        }
    }

    Slideshow.prototype = {

        csstransitions : typeof Modernizr !== 'undefined' && Modernizr.csstransitions,
        cycling :    false,

        play : function () {
            clearInterval(this.interval);

            this.cycling = true;

            this.interval = setInterval($.proxy(function() {
                this.next();
            }, this), this.options.interval );

            return this;
        },

        pause : function() {
            clearInterval(this.interval);
            this.cycling = false;

            return this;
        },

        slideTo : function($slide) {
            clearInterval(this.interval);

            var $siblings = $slide.siblings(this.options.slideSelector);

            $siblings.removeClass('active');
            $slide.addClass('active');
            this.$current = $slide;

            if (this.csstransitions) {
                $slide.one("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", $.proxy(function(event) {
                    this.cycling && this.play();
                }, this));
                $siblings.css('opacity', 0);
                $slide.css('opacity', 1);
            } else {
                $slide.stop(true).fadeTo(this.options.speed, 1, $.proxy(function(){
                    this.cycling && this.play();
                }, this));
                $siblings.stop(true).fadeTo(this.options.speed, 0);
            }

            if (this.options.pager) {
                var index = this.$slides.index($slide);
                var $pagerLink = this.$pager.children().eq(index);
                $pagerLink.addClass('active');
                $pagerLink.siblings().removeClass('active');
            }

            return this;
        },

        next : function () {
            var $next;

            if (this.$current.next(this.options.slideSelector).length) {
                $next = this.$current.next();
            } else {
                $next = this.$slides.first();
            }

            return this.slideTo($next);
        },

        prev : function () {
            var $prev;

            if (this.$current.prev(this.options.slideSelector).length) {
                $prev = this.$current.prev();
            } else {
                $prev = this.$slides.last();
            }

            return this.slideTo($prev);
        }

    }

    $.fn.mySlider = function (options) {

        options = $.extend({
            interval :          5000,
            speed :             1000,
            slideSelector :     '.slide',
            autoStart :         true,
            controls:           true,
            fadeControls:       true,
            pauseOnHover:       false,
            pager:              true
        }, options);

        this.each(function(){
            var slideshow = new Slideshow(this, options);
            $(this).data('slideshow', slideshow);
        });

        return this;

    }

})(jQuery)<|endoftext|>


<commit_before>$(function() {
	var socket = io();
	var commands = [
		"/close",
		"/connect",
		"/deop",
		"/devoice",
		"/disconnect",
		"/invite",
		"/join",
		"/kick",
		"/leave",
		"/mode",
		"/msg",
		"/nick",
		"/notice",
		"/op",
		"/part",
		"/query",
		"/quit",
		"/raw",
		"/say",
		"/send",
		"/server",
		"/slap",
		"/topic",
		"/voice",
		"/whois"
	];

	var sidebar = $("#sidebar");
	var chat = $("#chat");

	try {
		var pop = new Audio();
		pop.src = "/audio/pop.ogg";
	} catch(e) {
		var pop = {
			play: $.noop
		};
	}

	$("#play").on("click", function() { pop.play(); });
	$("#footer .icon").tooltip();

	var favico = new Favico({
		animation: "none"
	});

	function render(name, data) {
		return Handlebars.templates[name](data);
	}

	Handlebars.registerHelper(
		"partial", function(id) {
			return new Handlebars.SafeString(render(id, this));
		}
	);

	socket.on("error", function(e) {
		console.log(e);
	});

	socket.on("auth", function(data) {
		var body = $("body");
		var login = $("#sign-in");
		if (body.hasClass("signed-out")) {
			var error = login.find(".error");
			error.show().closest("form").one("submit", function() {
				error.hide();
			});
		}
		body.addClass("signed-out");
		login.find("input[name='user']").val($.cookie("user") || "");
		sidebar.find(".sign-in")
			.click()
			.end()
			.find(".networks")
			.html("")
			.next()
			.show();
	});

	socket.on("init", function(data) {
		if (data.networks.length === 0) {
			$("#footer").find(".connect").trigger("click");
			return;
		}

		sidebar.find(".networks").html(
			render("network", {
				networks: data.networks
			})
		);

		var channels = $.map(data.networks, function(n) {
			return n.channels;
		});
		chat.html(
			render("chat", {
				channels: channels
			})
		);

		sidebar.find(".empty").hide();
		$("body").removeClass("signed-out");

		var id = $.cookie("target");
		var target = sidebar.find("[data-target='" + id + "']").trigger("click");
		if (target.length === 0) {
			var first = sidebar.find(".chan")
				.eq(0)
				.trigger("click");
			if (first.length === 0) {
				$("#footer").find(".connect").trigger("click");
			}
		}
	});

	socket.on("join", function(data) {
		var id = data.network;
		var network = sidebar.find("#network-" + id);
		network.append(
			render("chan", {
				channels: [data.chan]
			})
		);
		chat.append(
			render("chat", {
				channels: [data.chan]
			})
		);

		sidebar.find(".chan")
			.sort(function(a, b) { return $(a).data("id") - $(b).data("id") })
			.last()
			.trigger("click");
	});

	socket.on("msg", function(data) {
		var target = data.chan;
		if (data.msg.type == "error") {
			target = chat.find(".active").data("id");
		}
		target = "#chan-" + target;
		chat.find(target)
			.find(".messages")
			.append(render("msg", {messages: [data.msg]}))
			.trigger("msg", [
				target,
				data.msg
			]);
	});

	socket.on("more", function(data) {
		var target = data.chan;
		var chan = chat
			.find("#chan-" + target)
			.find(".messages")
			.prepend(render("msg", {messages: data.messages}))
			.end();
		if (data.messages.length != 100) {
			var more = chan
				.find(".show-more")
				.remove();
		}
	});

	socket.on("network", function(data) {
		sidebar.find(".empty").hide();
		sidebar.find(".networks").append(
			render("network", {
				networks: [data.network]
			})
		);
		chat.append(
			render("chat", {
				channels: data.network.channels
			})
		);
		sidebar.find(".chan")
			.last()
			.trigger("click");
		$("#connect")
			.find(".btn")
			.prop("disabled", false)
			.end()
			.find("input")
			.each(function() {
				var self = $(this);
				self.val(self.data("default"));
			});
	});

	socket.on("nick", function(data) {
		console.log(data);
	});

	socket.on("part", function(data) {
		var id = data.chan;
		sidebar.find("[data-target=#chan-" + id + "]")
			.remove()
			.end()
			.find(".chan")
			.eq(0)
			.trigger("click");
	});

	socket.on("quit", function(data) {
		var id = data.network;
		sidebar.find("#network-" + id)
			.remove()
			.end();
		var chan = sidebar.find(".chan")
			.eq(0)
			.trigger("click");
		if (chan.length === 0) {
			sidebar.find(".empty").show();
		}
	});

	socket.on("users", function(data) {
		chat.find("#chan-" + data.chan)
			.find(".users")
			.html(render("user", data));
	});

	$("#connect")
		.find("input")
		.each(function() {
			var self = $(this);
			self.data("default", self.val());
		});

	$.cookie.json = true;

	var settings = $("#settings");
	var options = $.extend({notification: true}, $.cookie("settings"));

	for (var i in options) {
		if (options[i]) {
			settings.find("input[name=" + i + "]").prop("checked", true);
		}
	}

	settings.on("change", "input", function() {
		var self = $(this);
		options[self.attr("name")] = self.prop("checked");
		$.cookie("settings", options);
	}).find("input")
		.eq(0)
		.trigger("change");

	var viewport = $("#viewport");

	viewport.on("click", ".lt, .rt", function(e) {
		var self = $(this);
		viewport.toggleClass(self.attr("class"));
		if (viewport.is(".lt, .rt")) {
			e.stopPropagation();
			chat.find(".chat").one("click", function() {
				viewport.removeClass("lt rt");
			});
		}
	});

	var input = $("#input")
		.history()
		.tab(complete, {hint: false});

	var form = $("#form").on("submit", function(e) {
		e.preventDefault();
		var text = input.val();
		input.val("");
		socket.emit("input", {
			target: chat.data("id"),
			text: text
		});
	});

	var top = 1;
	sidebar.on("click", "button", function() {
		var self = $(this);
		var target = self.data("target");
		if (!target) {
			return;
		}

		if (self.hasClass("chan")) {
			$.cookie("target", target);
		}
		chat.data(
			"id",
			self.data("id")
		);

		sidebar.find(".active").removeClass("active");
		self.addClass("active")
			.find(".badge")
			.removeClass("highlight")
			.empty();

		if (sidebar.find(".highlight").length == 0) {
			favico.badge("");
		}

		viewport.removeClass();

		$("#windows .active").removeClass("active");
		var chan = $(target)
			.addClass("active")
			.trigger("show")
			.css("z-index", top++)
			.find(".chat")
			.sticky()
			.end();

		if (screen.width > 768 && chan.hasClass("chan")) {
			input.focus();
		}
	});

	sidebar.on("click", "#sign-out", function() {
		location.reload();
	});

	sidebar.on("click", ".close", function() {
		var cmd = "/close";
		var chan = $(this).closest(".chan");
		if (chan.hasClass("lobby")) {
			cmd = "/quit";
			var server = chan
				.clone()
				.remove("span")
				.text()
				.trim();
			if (!confirm("Disconnect from " + server + "?")) {
				return false;
			}
		}
		socket.emit("input", {
			target: chan.data("id"),
			text: cmd
		});
		chan.css({
			transition: "none",
			opacity: .4
		});
		return false;
	});

	chat.on("input", ".search", function() {
		var value = $(this).val().toLowerCase();
		var names = $(this).closest(".users").find(".names");
		names.find("button").each(function() {
			var btn = $(this);
			var name = btn.text().toLowerCase().replace(/[+%@~]/, "");
			if (name.indexOf(value) === 0) {
				btn.show();
			} else {
				btn.hide();
			}
		});
	});

	chat.on("click", ".user", function() {
		var user = $(this).html().trim().replace(/[+%@~]/, "");
		if (user.indexOf("#") !== -1) {
			return;
		}
		var text = "/whois " + user;
		socket.emit("input", {
			target: chat.data("id"),
			text: text
		});
	});

	chat.on("msg", ".messages", function(e, target, msg) {
		var btn = sidebar.find(".chan[data-target=" + target + "]:not(.active)");
		var query = btn.hasClass("query");
		var type = msg.type;
		var highlight = type.contains("highlight");
		if (highlight || query) {
			pop.play();
			if (document.hidden || !$(target).hasClass("active")) {
				favico.badge("!");
			}
		}

		if (btn.length === 0) {
			return;
		}

		var ignore = [
			"join",
			"part",
			"quit",
			"nick"
		];
		if ($.inArray(type, ignore) !== -1){
			return;
		}

		var badge = btn.find(".badge");
		if (badge.length !== 0) {
			var i = (parseInt(badge.html()) || 0) + 1;
			badge.html(i);
			if (highlight || query) {
				badge.addClass("highlight");
			}
		}
	});

	chat.on("click", ".show-more", function() {
		var self = $(this);
		var id = self.data("id");
		var count = self.next(".messages").children().length;
		socket.emit("more", {
			target: id,
			count: count
		});
	});

	var windows = $("#windows");
	var forms = $("#sign-in, #connect");

	windows.on("show", "#sign-in", function() {
		var self = $(this);
		var inputs = self.find("input");
		inputs.each(function() {
			var self = $(this);
			if (self.val() === "") {
				self.focus();
				return false;
			}
		})
	});

	windows.on("click", ".input", function() {
		$(this).select();
	});

	forms.on("submit", "form", function(e) {
		e.preventDefault()
		var event = "auth";
		var form = $(this);
		if (form.closest(".window").attr("id") == "connect") {
			event = "conn";
			form.find(".btn")
				.attr("disabled", true)
				.end();
		}
		var values = {};
		$.each(form.serializeArray(), function(i, obj) {
			if (obj.value !== "") {
				values[obj.name] = obj.value;
			}
		});
		if (values.user) {
			$.cookie("user", values.user);
		}
		socket.emit(
			event, values
		);
	});

	Mousetrap.bind([
		"command+up",
		"command+down",
		"ctrl+up",
		"ctrl+down"
	], function(e, keys) {
		var channels = sidebar.find(".chan");
		var index = channels.index(channels.filter(".active"));

		var direction = keys.split("+").pop();
		switch (direction) {
		case "up":
			var i = Math.max(0, index - 1);
			channels.eq(i).click();
			break;

		case "down":
			var i = Math.min(channels.length, index + 1);
			channels.eq(i).click();
			break;
		}
	});

	function complete(word) {
		var words = commands.slice();
		var users = chat.find(".active")
			.find(".names")
			.children()
			.each(function() {
				words.push($(this).text().replace(/[+%@~]/, ""));
			});
		var channels = sidebar.find(".channel")
			.each(function() {
				var chan = $(this).clone().remove("span").text().trim();
				words.push(chan);
			});
		return $.grep(
			words,
			function(w) {
				return !w.toLowerCase().indexOf(word.toLowerCase());
			}
		);
	}

	document.addEventListener(
		"visibilitychange",
		function() {
			if (sidebar.find(".highlight").length == 0) {
				favico.badge("");
			}
		}
	);
});
<commit_msg>Minor fix<commit_after>$(function() {
	var socket = io();
	var commands = [
		"/close",
		"/connect",
		"/deop",
		"/devoice",
		"/disconnect",
		"/invite",
		"/join",
		"/kick",
		"/leave",
		"/mode",
		"/msg",
		"/nick",
		"/notice",
		"/op",
		"/part",
		"/query",
		"/quit",
		"/raw",
		"/say",
		"/send",
		"/server",
		"/slap",
		"/topic",
		"/voice",
		"/whois"
	];

	var sidebar = $("#sidebar");
	var chat = $("#chat");

	try {
		var pop = new Audio();
		pop.src = "/audio/pop.ogg";
	} catch(e) {
		var pop = {
			play: $.noop
		};
	}

	$("#play").on("click", function() { pop.play(); });
	$("#footer .icon").tooltip();

	var favico = new Favico({
		animation: "none"
	});

	function render(name, data) {
		return Handlebars.templates[name](data);
	}

	Handlebars.registerHelper(
		"partial", function(id) {
			return new Handlebars.SafeString(render(id, this));
		}
	);

	socket.on("error", function(e) {
		console.log(e);
	});

	socket.on("auth", function(data) {
		var body = $("body");
		var login = $("#sign-in");
		if (body.hasClass("signed-out")) {
			var error = login.find(".error");
			error.show().closest("form").one("submit", function() {
				error.hide();
			});
		}
		body.addClass("signed-out");
		var input = login.find("input[name='user']");
		if (input.val() === "") {
			input.val($.cookie("user") || "");
		}
		sidebar.find(".sign-in")
			.click()
			.end()
			.find(".networks")
			.html("")
			.next()
			.show();
	});

	socket.on("init", function(data) {
		if (data.networks.length === 0) {
			$("#footer").find(".connect").trigger("click");
			return;
		}

		sidebar.find(".networks").html(
			render("network", {
				networks: data.networks
			})
		);

		var channels = $.map(data.networks, function(n) {
			return n.channels;
		});
		chat.html(
			render("chat", {
				channels: channels
			})
		);

		sidebar.find(".empty").hide();
		$("body").removeClass("signed-out");

		var id = $.cookie("target");
		var target = sidebar.find("[data-target='" + id + "']").trigger("click");
		if (target.length === 0) {
			var first = sidebar.find(".chan")
				.eq(0)
				.trigger("click");
			if (first.length === 0) {
				$("#footer").find(".connect").trigger("click");
			}
		}
	});

	socket.on("join", function(data) {
		var id = data.network;
		var network = sidebar.find("#network-" + id);
		network.append(
			render("chan", {
				channels: [data.chan]
			})
		);
		chat.append(
			render("chat", {
				channels: [data.chan]
			})
		);

		sidebar.find(".chan")
			.sort(function(a, b) { return $(a).data("id") - $(b).data("id") })
			.last()
			.trigger("click");
	});

	socket.on("msg", function(data) {
		var target = data.chan;
		if (data.msg.type == "error") {
			target = chat.find(".active").data("id");
		}
		target = "#chan-" + target;
		chat.find(target)
			.find(".messages")
			.append(render("msg", {messages: [data.msg]}))
			.trigger("msg", [
				target,
				data.msg
			]);
	});

	socket.on("more", function(data) {
		var target = data.chan;
		var chan = chat
			.find("#chan-" + target)
			.find(".messages")
			.prepend(render("msg", {messages: data.messages}))
			.end();
		if (data.messages.length != 100) {
			var more = chan
				.find(".show-more")
				.remove();
		}
	});

	socket.on("network", function(data) {
		sidebar.find(".empty").hide();
		sidebar.find(".networks").append(
			render("network", {
				networks: [data.network]
			})
		);
		chat.append(
			render("chat", {
				channels: data.network.channels
			})
		);
		sidebar.find(".chan")
			.last()
			.trigger("click");
		$("#connect")
			.find(".btn")
			.prop("disabled", false)
			.end()
			.find("input")
			.each(function() {
				var self = $(this);
				self.val(self.data("default"));
			});
	});

	socket.on("nick", function(data) {
		console.log(data);
	});

	socket.on("part", function(data) {
		var id = data.chan;
		sidebar.find("[data-target=#chan-" + id + "]")
			.remove()
			.end()
			.find(".chan")
			.eq(0)
			.trigger("click");
	});

	socket.on("quit", function(data) {
		var id = data.network;
		sidebar.find("#network-" + id)
			.remove()
			.end();
		var chan = sidebar.find(".chan")
			.eq(0)
			.trigger("click");
		if (chan.length === 0) {
			sidebar.find(".empty").show();
		}
	});

	socket.on("users", function(data) {
		chat.find("#chan-" + data.chan)
			.find(".users")
			.html(render("user", data));
	});

	$("#connect")
		.find("input")
		.each(function() {
			var self = $(this);
			self.data("default", self.val());
		});

	$.cookie.json = true;

	var settings = $("#settings");
	var options = $.extend({notification: true}, $.cookie("settings"));

	for (var i in options) {
		if (options[i]) {
			settings.find("input[name=" + i + "]").prop("checked", true);
		}
	}

	settings.on("change", "input", function() {
		var self = $(this);
		options[self.attr("name")] = self.prop("checked");
		$.cookie("settings", options);
	}).find("input")
		.eq(0)
		.trigger("change");

	var viewport = $("#viewport");

	viewport.on("click", ".lt, .rt", function(e) {
		var self = $(this);
		viewport.toggleClass(self.attr("class"));
		if (viewport.is(".lt, .rt")) {
			e.stopPropagation();
			chat.find(".chat").one("click", function() {
				viewport.removeClass("lt rt");
			});
		}
	});

	var input = $("#input")
		.history()
		.tab(complete, {hint: false});

	var form = $("#form").on("submit", function(e) {
		e.preventDefault();
		var text = input.val();
		input.val("");
		socket.emit("input", {
			target: chat.data("id"),
			text: text
		});
	});

	var top = 1;
	sidebar.on("click", "button", function() {
		var self = $(this);
		var target = self.data("target");
		if (!target) {
			return;
		}

		if (self.hasClass("chan")) {
			$.cookie("target", target);
		}
		chat.data(
			"id",
			self.data("id")
		);

		sidebar.find(".active").removeClass("active");
		self.addClass("active")
			.find(".badge")
			.removeClass("highlight")
			.empty();

		if (sidebar.find(".highlight").length == 0) {
			favico.badge("");
		}

		viewport.removeClass();

		$("#windows .active").removeClass("active");
		var chan = $(target)
			.addClass("active")
			.trigger("show")
			.css("z-index", top++)
			.find(".chat")
			.sticky()
			.end();

		if (screen.width > 768 && chan.hasClass("chan")) {
			input.focus();
		}
	});

	sidebar.on("click", "#sign-out", function() {
		location.reload();
	});

	sidebar.on("click", ".close", function() {
		var cmd = "/close";
		var chan = $(this).closest(".chan");
		if (chan.hasClass("lobby")) {
			cmd = "/quit";
			var server = chan
				.clone()
				.remove("span")
				.text()
				.trim();
			if (!confirm("Disconnect from " + server + "?")) {
				return false;
			}
		}
		socket.emit("input", {
			target: chan.data("id"),
			text: cmd
		});
		chan.css({
			transition: "none",
			opacity: .4
		});
		return false;
	});

	chat.on("input", ".search", function() {
		var value = $(this).val().toLowerCase();
		var names = $(this).closest(".users").find(".names");
		names.find("button").each(function() {
			var btn = $(this);
			var name = btn.text().toLowerCase().replace(/[+%@~]/, "");
			if (name.indexOf(value) === 0) {
				btn.show();
			} else {
				btn.hide();
			}
		});
	});

	chat.on("click", ".user", function() {
		var user = $(this).html().trim().replace(/[+%@~]/, "");
		if (user.indexOf("#") !== -1) {
			return;
		}
		var text = "/whois " + user;
		socket.emit("input", {
			target: chat.data("id"),
			text: text
		});
	});

	chat.on("msg", ".messages", function(e, target, msg) {
		var btn = sidebar.find(".chan[data-target=" + target + "]:not(.active)");
		var query = btn.hasClass("query");
		var type = msg.type;
		var highlight = type.contains("highlight");
		if (highlight || query) {
			pop.play();
			if (document.hidden || !$(target).hasClass("active")) {
				favico.badge("!");
			}
		}

		if (btn.length === 0) {
			return;
		}

		var ignore = [
			"join",
			"part",
			"quit",
			"nick"
		];
		if ($.inArray(type, ignore) !== -1){
			return;
		}

		var badge = btn.find(".badge");
		if (badge.length !== 0) {
			var i = (parseInt(badge.html()) || 0) + 1;
			badge.html(i);
			if (highlight || query) {
				badge.addClass("highlight");
			}
		}
	});

	chat.on("click", ".show-more", function() {
		var self = $(this);
		var id = self.data("id");
		var count = self.next(".messages").children().length;
		socket.emit("more", {
			target: id,
			count: count
		});
	});

	var windows = $("#windows");
	var forms = $("#sign-in, #connect");

	windows.on("show", "#sign-in", function() {
		var self = $(this);
		var inputs = self.find("input");
		inputs.each(function() {
			var self = $(this);
			if (self.val() === "") {
				self.focus();
				return false;
			}
		})
	});

	windows.on("click", ".input", function() {
		$(this).select();
	});

	forms.on("submit", "form", function(e) {
		e.preventDefault()
		var event = "auth";
		var form = $(this);
		if (form.closest(".window").attr("id") == "connect") {
			event = "conn";
			form.find(".btn")
				.attr("disabled", true)
				.end();
		}
		var values = {};
		$.each(form.serializeArray(), function(i, obj) {
			if (obj.value !== "") {
				values[obj.name] = obj.value;
			}
		});
		if (values.user) {
			$.cookie("user", values.user);
		}
		socket.emit(
			event, values
		);
	});

	Mousetrap.bind([
		"command+up",
		"command+down",
		"ctrl+up",
		"ctrl+down"
	], function(e, keys) {
		var channels = sidebar.find(".chan");
		var index = channels.index(channels.filter(".active"));

		var direction = keys.split("+").pop();
		switch (direction) {
		case "up":
			var i = Math.max(0, index - 1);
			channels.eq(i).click();
			break;

		case "down":
			var i = Math.min(channels.length, index + 1);
			channels.eq(i).click();
			break;
		}
	});

	function complete(word) {
		var words = commands.slice();
		var users = chat.find(".active")
			.find(".names")
			.children()
			.each(function() {
				words.push($(this).text().replace(/[+%@~]/, ""));
			});
		var channels = sidebar.find(".channel")
			.each(function() {
				var chan = $(this).clone().remove("span").text().trim();
				words.push(chan);
			});
		return $.grep(
			words,
			function(w) {
				return !w.toLowerCase().indexOf(word.toLowerCase());
			}
		);
	}

	document.addEventListener(
		"visibilitychange",
		function() {
			if (sidebar.find(".highlight").length == 0) {
				favico.badge("");
			}
		}
	);
});
<|endoftext|>


<commit_before>/* canvas erstellen */
var canvas = document.getElementById("myCanvas");
var ctx=canvas.getContext("2d");

/* Andere globale Variablen */
var consoleLog = document.getElementById("consoleLog");
var webSocket;
var stellwertHeizung = 100;

//var rangeslider = document.getElementByID("rangevalue");

/* Handler fuer Mouse-click im canvas-Bereich */
function on_canvas_click(ev) {
  // ... x,y sind die absoluten Koordinaten innerhalb des Canvas, scrollOffset bercksichtigen
  var x = ev.clientX - canvas.offsetLeft + document.body.scrollLeft + document.documentElement.scrollLeft;
  var y = ev.clientY - canvas.offsetTop + document.body.scrollTop + document.documentElement.scrollTop;
  var kl = document.getElementById("s_kronleuchter");
  var lp = document.getElementById("s_lampe");
  var tv = document.getElementById("label_tv");
  var hz = document.getElementById("s_heizung");

  var message = "Mouse-Position: x=" + x + "y=" + y;
  logToConsole("Mouse-Position: x=" + x + "y=" + y);

  ctx.font="14px Arial";
  ctx.clearRect(0,300,400,50);  /* alten Text loeschen */
  ctx.fillStyle = "#000000";
  ctx.fillText(message,10,315);  /* neuen Text schreiben */
  message = "Kronleuchter: " +kronleuchter.value + " Lampe : " + lampe.value + " Heizung Soll: " +heizung.value +" Ist: " + heizung_ist.value;
  ctx.fillText(message, 10, 330);

  /* wenn auf Kronleuchter gedrckt */
  if(x > 196 && x < (196 + 22) && y > 156 && y < (156 + 22)){

		if(kl.value < 1){
			kl.value = 100;
		}
		else{
			kl.value = 0;
		}
		kl.onchange();

        logToConsole('Kronleuchter: ' + kronleuchter.value+'');
	}

	/* wenn auf Lampe gedrckt */
  if(x > 248 && x < (248 + 21) && y > 196 && y < (196 + 17)){

		if(lp.value < 1){
			lp.value = 100;
		}
		else{
			lp.value = 0;
		}
		lp.onchange();

        logToConsole('Lampe: ' + lampe.value+'');
	}

		/* wenn auf TV gedrckt */
  if(x > 164 && x < (163 + 23) && y > 227 && y < (227 + 14)){
        if(tv.value == "OFF"){
            tv.value = "ON";
            tvbild.src = "../bilder/TV_on.png";
        }
        else{
            tv.value = "OFF";
        }

        tv_change(tv.value);

		logToConsole('TV: ' + tv.value+'');

        sendTvPair(tv.value);
	}
}

function tv_change(value){

    /* Bild zeichnen */
    var tvbild = new Image();

    if(value == "OFF"){
        tvbild.src = "../bilder/TV_on.png";
    }
    else{
        tvbild.src = "../bilder/TV_off.png";
    }

    tvbild.onload = function() {
        ctx.drawImage(tvbild, 163, 227, 23, 14);
    };
}

/* Handler fr Stnderlampe, GUI aktualisieren und Kommunikation zum Huesli */
 function lamp_change(slideAmount){

	/* Bild zeichnen */
	var img_lampe_on = new Image();
	var img_lampe = new Image();

	/* altes Bild loeschen */
	img_lampe.src = "../bilder/Lampe_off.png";
	img_lampe.onload = function() {
		ctx.drawImage(img_lampe, 248, 195, 21, 17);
	};
	img_lampe_on.src = "../bilder/Lampe_on.png";
	img_lampe_on.onload = function() {
		/* Transparenz setzen */
		ctx.globalAlpha = slideAmount/100.0;
		ctx.drawImage(img_lampe_on, 248, 195, 21, 17);
		ctx.globalAlpha = 1.0;
	};
	/* Hier Wert an BeagleBone senden */
    sendLampPair(slideAmount);
 }

 /* Handler fr Kronleuchter, GUI aktualisieren und Kommunikation zum Huesli */
 function kron_change(slideAmount){

	/* Bild zeichnen */
	var img_lampe_on = new Image();
	var img_lampe = new Image();

	/* altes Bild loeschen */
	img_lampe.src = "../bilder/Kronleuchter_off.png";
	img_lampe.onload = function() {
		ctx.drawImage(img_lampe, 196, 156, 22, 22);
	};
	img_lampe_on.src = "../bilder/Kronleuchter_on.png";
	img_lampe_on.onload = function() {
		/* Transparenz setzen */
		ctx.globalAlpha = slideAmount/100.0;
		ctx.drawImage(img_lampe_on, 196, 156, 22, 22);
		ctx.globalAlpha = 1.0;
	};
	/* Hier Wert an BeagleBone senden */
	sendLeuchterPair(slideAmount);
 }

 function heizung_soll_change(slideAmount){
	/* Hier Wert an BeagleBone senden */
	sendHeizungPair(slideAmount);
 }

/* Handler fure Mouse-click registrieren */
canvas.addEventListener('click', on_canvas_click, false);

/* Bild zeichnen */
var cat = new Image();
cat.src = "../bilder/haus.gif";
cat.onload = function() {
  ctx.drawImage(cat, 0, 0, 400, 300);
};

/* zu Teszwecken hier heizung setzen */
heating(stellwertHeizung);

/* Illustrates the Heating control value */
 function heating(stellwert){

	/* Bild rechts zeichnen */
	var img_heating_on = new Image();
	var img_heating = new Image();

	/* altes Bild loeschen */
	img_heating.src = "../bilder/Heizung_off.png";
	img_heating.onload = function() {
		ctx.drawImage(img_heating, 278, 236, 9, 30);
	};
	img_heating_on.src = "../bilder/Heizung_on.png";
	img_heating_on.onload = function() {
		/* Transparenz setzen */
		ctx.globalAlpha = stellwert/100.0;
		ctx.drawImage(img_heating_on, 278, 236, 9, 30);
		ctx.globalAlpha = 1.0;
	};

	/* Bild links zeichnen */
	var img_heating_on_left = new Image();
	var img_heating_left = new Image();
	/* altes Bild loeschen */
	img_heating_left.src = "../bilder/Heizung_off_left.png";
	img_heating_left.onload = function() {
		ctx.drawImage(img_heating_left, 132, 237, 9, 30);
	};
	img_heating_on_left.src = "../bilder/Heizung_on_left.png";
	img_heating_on_left.onload = function() {
		/* Transparenz setzen */
		ctx.globalAlpha = stellwert/100.0;
		ctx.drawImage(img_heating_on_left, 132, 237, 9, 30);
		ctx.globalAlpha = 1.0;
	};

 }

/* Log Console */
function logToConsole(message)
{
    var pre = document.createElement("p");
    pre.style.wordWrap = "break-word";
    pre.innerHTML = message;
    consoleLog.appendChild(pre);

    while (consoleLog.childNodes.length > 50)
    {
      consoleLog.removeChild(consoleLog.firstChild);
    }

    consoleLog.scrollTop = consoleLog.scrollHeight;
}

function ClearLogPressed()
{
    while (consoleLog.childNodes.length > 0)
    {
        consoleLog.removeChild(consoleLog.lastChild);
    }
}

/* Websocket Management */
initSocket();

function initSocket(){
    webSocket = new WebSocket("ws://echo.websocket.org");

    webSocket.onopen = function (evt){ logToConsole("CONNECTED: " + evt.data); };
    webSocket.onerror = function (evt){ logToConsole('ERROR: ' + evt.data); };
    webSocket.onmessage = function (evt){ onMessage(evt); };
    webSocket.onclose = function (evt){ logToConsole("DISCONNECTED: " + evt.data); };
}

function onMessage(evt)
{
    logToConsole('RESPONSE: ' + evt.data+'');

    /* Es knnten mehrere Pairs in einer JSON Message sein, also damit rechnen */
    var jsonObject = JSON.parse(evt.data) ;
    /*for(var key in jsonObject){
        ...
    }*/
    if(jsonObject.TV){
        tv.value = jsonObject.TV;
        tv_change(jsonObject.TV);
    }
    if(jsonObject.Lampe){
        lp.value = jsonObject.Lampe;
        lamp_change(jsonObject.Lamp);
    }
    if(jsonObject.Leuchter){
        kl.value = jsonObject.Leuchter;
        kron_change(jsonObject.Leuchter);
    }
    if(jsonObject.TempSoll){
        hz.value = jsonObject.TempSoll;
        heizung_soll_change(jsonObject.TempSoll);
    }
    if(jsonObject.TempIst){
        hz.value = jsonObject.TempSoll;
        heizung_soll_change(jsonObject.TempSoll);
    }
    if(jsonObject.Heizung){
        stellwertHeizung = jsonObject.TempSoll;
        heating(jsonObject.TempSoll);
    }
}

function sendTvPair(val){
    var sendObj = { TV: val };
    webSocket.send(JSON.stringify(sendObj));
    logToConsole("SENT: " + JSON.stringify(sendObj));
}

function sendLampPair(val){
    var sendObj = { Lampe: val };
    webSocket.send(JSON.stringify(sendObj));
    logToConsole("SENT: " + JSON.stringify(sendObj));
}

function sendLeuchterPair(val){
    var sendObj = { Leuchter: val };
    webSocket.send(JSON.stringify(sendObj));
    logToConsole("SENT: " + JSON.stringify(sendObj));
}

function sendHeizungPair(val){
    var sendObj = { TempSoll: val };
    webSocket.send(JSON.stringify(sendObj));
    logToConsole("SENT: " + JSON.stringify(sendObj));
}
<commit_msg>fixed error with non visible tv variable -> now lp, kl, tv and hz are globally defined<commit_after>/* canvas erstellen */
var canvas = document.getElementById("myCanvas");
var ctx=canvas.getContext("2d");

/* Andere globale Variablen */
var consoleLog = document.getElementById("consoleLog");
var webSocket;
var stellwertHeizung = 100;
var kl = document.getElementById("s_kronleuchter");
var lp = document.getElementById("s_lampe");
var tv = document.getElementById("label_tv");
var hz = document.getElementById("s_heizung");

//var rangeslider = document.getElementByID("rangevalue");

/* Handler fuer Mouse-click im canvas-Bereich */
function on_canvas_click(ev) {
  // ... x,y sind die absoluten Koordinaten innerhalb des Canvas, scrollOffset bercksichtigen
  var x = ev.clientX - canvas.offsetLeft + document.body.scrollLeft + document.documentElement.scrollLeft;
  var y = ev.clientY - canvas.offsetTop + document.body.scrollTop + document.documentElement.scrollTop;

  var message = "Mouse-Position: x=" + x + "y=" + y;
  logToConsole("Mouse-Position: x=" + x + "y=" + y);

  ctx.font="14px Arial";
  ctx.clearRect(0,300,400,50);  /* alten Text loeschen */
  ctx.fillStyle = "#000000";
  ctx.fillText(message,10,315);  /* neuen Text schreiben */
  message = "Kronleuchter: " +kronleuchter.value + " Lampe : " + lampe.value + " Heizung Soll: " +heizung.value +" Ist: " + heizung_ist.value;
  ctx.fillText(message, 10, 330);

  /* wenn auf Kronleuchter gedrckt */
  if(x > 196 && x < (196 + 22) && y > 156 && y < (156 + 22)){

		if(kl.value < 1){
			kl.value = 100;
		}
		else{
			kl.value = 0;
		}
		kl.onchange();

        logToConsole('Kronleuchter: ' + kronleuchter.value+'');
	}

	/* wenn auf Lampe gedrckt */
  if(x > 248 && x < (248 + 21) && y > 196 && y < (196 + 17)){

		if(lp.value < 1){
			lp.value = 100;
		}
		else{
			lp.value = 0;
		}
		lp.onchange();

        logToConsole('Lampe: ' + lampe.value+'');
	}

		/* wenn auf TV gedrckt */
  if(x > 164 && x < (163 + 23) && y > 227 && y < (227 + 14)){
        if(tv.value == "OFF"){
            tv.value = "ON";
        }
        else{
            tv.value = "OFF";
        }
        tv_change(tv.value);

		logToConsole('TV: ' + tv.value+'');
	}
}

function tv_change(value){
    /* Bild zeichnen */
    var tvbild = new Image();

    if(value == "OFF"){
        tvbild.src = "../bilder/TV_off.png";
    }
    else{
        tvbild.src = "../bilder/TV_on.png";
    }

    tvbild.onload = function() {
        ctx.drawImage(tvbild, 163, 227, 23, 14);
    };
    /* Hier Wert an BeagleBone senden */
    sendTvPair(value);
}

/* Handler fr Stnderlampe, GUI aktualisieren und Kommunikation zum Huesli */
 function lamp_change(slideAmount){
	/* Bild zeichnen */
	var img_lampe_on = new Image();
	var img_lampe = new Image();

	/* altes Bild loeschen */
	img_lampe.src = "../bilder/Lampe_off.png";
	img_lampe.onload = function() {
		ctx.drawImage(img_lampe, 248, 195, 21, 17);
	};
	img_lampe_on.src = "../bilder/Lampe_on.png";
	img_lampe_on.onload = function() {
		/* Transparenz setzen */
		ctx.globalAlpha = slideAmount/100.0;
		ctx.drawImage(img_lampe_on, 248, 195, 21, 17);
		ctx.globalAlpha = 1.0;
	};
	/* Hier Wert an BeagleBone senden */
    sendLampPair(slideAmount);
 }

 /* Handler fr Kronleuchter, GUI aktualisieren und Kommunikation zum Huesli */
 function kron_change(slideAmount){
	/* Bild zeichnen */
	var img_lampe_on = new Image();
	var img_lampe = new Image();

	/* altes Bild loeschen */
	img_lampe.src = "../bilder/Kronleuchter_off.png";
	img_lampe.onload = function() {
		ctx.drawImage(img_lampe, 196, 156, 22, 22);
	};
	img_lampe_on.src = "../bilder/Kronleuchter_on.png";
	img_lampe_on.onload = function() {
		/* Transparenz setzen */
		ctx.globalAlpha = slideAmount/100.0;
		ctx.drawImage(img_lampe_on, 196, 156, 22, 22);
		ctx.globalAlpha = 1.0;
	};
	/* Hier Wert an BeagleBone senden */
	sendLeuchterPair(slideAmount);
    sendTvPair("OFF");
 }

 function heizung_soll_change(slideAmount){
	/* Hier Wert an BeagleBone senden */
	sendHeizungPair(slideAmount);
 }

/* zu Teszwecken hier heizung setzen */
heating(stellwertHeizung);

/* Illustrates the Heating control value */
 function heating(stellwert){
	/* Bild rechts zeichnen */
	var img_heating_on = new Image();
	var img_heating = new Image();

	/* altes Bild loeschen */
	img_heating.src = "../bilder/Heizung_off.png";
	img_heating.onload = function() {
		ctx.drawImage(img_heating, 278, 236, 9, 30);
	};
	img_heating_on.src = "../bilder/Heizung_on.png";
	img_heating_on.onload = function() {
		/* Transparenz setzen */
		ctx.globalAlpha = stellwert/100.0;
		ctx.drawImage(img_heating_on, 278, 236, 9, 30);
		ctx.globalAlpha = 1.0;
	};

	/* Bild links zeichnen */
	var img_heating_on_left = new Image();
	var img_heating_left = new Image();
	/* altes Bild loeschen */
	img_heating_left.src = "../bilder/Heizung_off_left.png";
	img_heating_left.onload = function() {
		ctx.drawImage(img_heating_left, 132, 237, 9, 30);
	};
	img_heating_on_left.src = "../bilder/Heizung_on_left.png";
	img_heating_on_left.onload = function() {
		/* Transparenz setzen */
		ctx.globalAlpha = stellwert/100.0;
		ctx.drawImage(img_heating_on_left, 132, 237, 9, 30);
		ctx.globalAlpha = 1.0;
	};

 }

 /* Handler fure Mouse-click registrieren */
canvas.addEventListener('click', on_canvas_click, false);

/* Abschliessend Bild zeichnen */
var cat = new Image();
cat.src = "../bilder/haus.gif";
cat.onload = function() {
  ctx.drawImage(cat, 0, 0, 400, 300);
};

/* Log Console */
function logToConsole(message)
{
    var pre = document.createElement("p");
    pre.style.wordWrap = "break-word";
    pre.innerHTML = message;
    consoleLog.appendChild(pre);

    while (consoleLog.childNodes.length > 50)
    {
      consoleLog.removeChild(consoleLog.firstChild);
    }

    consoleLog.scrollTop = consoleLog.scrollHeight;
}

function ClearLogPressed()
{
    while (consoleLog.childNodes.length > 0)
    {
        consoleLog.removeChild(consoleLog.lastChild);
    }
}

/* Websocket Management */
initSocket();

function initSocket(){
    webSocket = new WebSocket("ws://echo.websocket.org");

    webSocket.onopen = function (evt){ logToConsole("CONNECTED: " + evt.data); };
    webSocket.onerror = function (evt){ logToConsole('ERROR: ' + evt.data); };
    webSocket.onmessage = function (evt){ onMessage(evt); };
    webSocket.onclose = function (evt){ logToConsole("DISCONNECTED: " + evt.data); };
}

function onMessage(evt)
{
    logToConsole('RESPONSE: ' + evt.data+'');

    /* Es knnten mehrere Pairs in einer JSON Message sein, also damit rechnen */
    var jsonObject = JSON.parse(evt.data);
    /*for(var key in jsonObject){
        ...
    }*/
    if(jsonObject.TV){
        tv.value = jsonObject.TV;
        tv_change(tv.value);
    }
    if(jsonObject.Lampe){
        lp.value = jsonObject.Lampe;
        lamp_change(jsonObject.Lamp);
    }
    if(jsonObject.Leuchter){
        kl.value = jsonObject.Leuchter;
        kron_change(jsonObject.Leuchter);
    }
    if(jsonObject.TempSoll){
        hz.value = jsonObject.TempSoll;
        heizung_soll_change(jsonObject.TempSoll);
    }
    if(jsonObject.TempIst){
        hz.value = jsonObject.TempSoll;
        heizung_soll_change(jsonObject.TempSoll);
    }
    if(jsonObject.Heizung){
        stellwertHeizung = jsonObject.TempSoll;
        heating(jsonObject.TempSoll);
    }
}

function sendTvPair(val){
    var sendObj = { TV: val };
    webSocket.send(JSON.stringify(sendObj));
    logToConsole("SENT: " + JSON.stringify(sendObj));
}

function sendLampPair(val){
    var sendObj = { Lampe: val };
    webSocket.send(JSON.stringify(sendObj));
    logToConsole("SENT: " + JSON.stringify(sendObj));
}

function sendLeuchterPair(val){
    var sendObj = { Leuchter: val };
    webSocket.send(JSON.stringify(sendObj));
    logToConsole("SENT: " + JSON.stringify(sendObj));
}

function sendHeizungPair(val){
    var sendObj = { TempSoll: val };
    webSocket.send(JSON.stringify(sendObj));
    logToConsole("SENT: " + JSON.stringify(sendObj));
}
<|endoftext|>


<commit_before>import Component from '@ember/component';
import layout from './template';
import { inject as service } from '@ember/service';
import { get, computed } from '@ember/object';

const FEATURE_HEADERS = [
  {
    translationKey: 'featureFlags.table.state',
    name:           'state',
    sort:           ['state'],
    width:          '100px',
  },
  {
    translationKey: 'featureFlags.table.restart',
    name:           'restart',
    sort:           ['status.dynamic'],
    width:          '90px',
  },
  {
    translationKey: 'featureFlags.table.name',
    name:           'name',
    sort:           ['name'],
    searchField:    'name',
    width:          '300px',
  },
  {
    translationKey: 'featureFlags.table.description',
    name:           'description',
    sort:           ['description'],
    searchField:    'description',
  },
];

export default Component.extend({
  intl:     service(),
  settings: service(),

  layout,

  bulkActions:         false,
  descending:          false,
  featuresHeaders:     FEATURE_HEADERS,
  model:               null,
  searchText:          '',
  sortBy:              'name',
  stickyHeader:        false,

  filteredFeatures: computed('model.[]', function() {
    return get(this, 'model').filter((feature) => feature.name !== 'dashboard');
  }),
});
<commit_msg>Hide fleet feature flag<commit_after>import Component from '@ember/component';
import layout from './template';
import { inject as service } from '@ember/service';
import { get, computed } from '@ember/object';

const FEATURE_HEADERS = [
  {
    translationKey: 'featureFlags.table.state',
    name:           'state',
    sort:           ['state'],
    width:          '100px',
  },
  {
    translationKey: 'featureFlags.table.restart',
    name:           'restart',
    sort:           ['status.dynamic'],
    width:          '90px',
  },
  {
    translationKey: 'featureFlags.table.name',
    name:           'name',
    sort:           ['name'],
    searchField:    'name',
    width:          '300px',
  },
  {
    translationKey: 'featureFlags.table.description',
    name:           'description',
    sort:           ['description'],
    searchField:    'description',
  },
];

export default Component.extend({
  intl:     service(),
  settings: service(),

  layout,

  bulkActions:         false,
  descending:          false,
  featuresHeaders:     FEATURE_HEADERS,
  model:               null,
  searchText:          '',
  sortBy:              'name',
  stickyHeader:        false,

  filteredFeatures: computed('model.[]', function() {
    return get(this, 'model').filter((feature) => !['dashboard', 'fleet'].includes(feature.name));
  }),
});
<|endoftext|>


<commit_before>apos.define('apostrophe-doc-type-manager-chooser', {
  extend: 'apostrophe-context',
  beforeConstruct: function(self, options) {
    self.manager = options.manager;
    self.field = options.field;
    self.$el = options.$el;
    self.$el.data('aposChooser', self);
    if (self.field.type === 'joinByOne') {
      self.limit = 1;
    } else {
      self.limit = (self.field.hints && self.field.hints.limit) || self.field.limit;
    }
    self.choices = [];
  },
  afterConstruct: function(self, callback) {
    self.removed = self.options.removed;
    self.enableInlineSchema();

    return async.series([
      self.load
    ], function(err) {
      if (err) {
        return callback(err);
      }
      self.enableLinks();
      self.enableAutocomplete();
      return callback(null);
    });
  },
  construct: function(self, options) {
    self.load = function(callback) {
      var args = {};
      // browse button can be shut off, for instance if we're already appearing in
      // a manage modal in response to a browse button
      if (options.browse !== false) {
        args.browse = true;
      }
      if (options.autocomplete !== false) {
        args.autocomplete = true;
      }
      if (self.removed) {
        args.removed = true;
      }
      return self.html('chooser', args, function(html) {
        self.$el.html(html);
        self.$choices = self.$el.find('[data-choices]:first');
        self.set([]);
        return callback(null);
      }, function(err) {
        return callback(err);
      });
    };
    self.set = function(choices) {
      self.choices = choices;
      return self.refresh();
    };
    self.get = function(callback) {
      if (!self.refreshing) {
        return async.eachSeries(self.choices, function(choice, callback) {
          var $relationship = self.$choices.find('[data-relationship-inline="' + choice.value + '"]');
          return apos.schemas.convert($relationship, self.inlineSchema, choice, callback);
        }, function(err) {
          if (err) {
            return callback(err);
          }
          return callback(null, self.choices);
        });
      }
      setTimeout(function() {
        return self.get(callback);
      }, 50);
    };
    self.getFinal = function(callback) {
      return self.finalize(function(err) {
        if (err) {
          return callback(err);
        }
        return self.get(callback);
      });
    };
    self.finalize = function(callback) {
      // A hook to implement things like minimums, autocropping, etc.
      return setImmediate(callback);
    };
    self.add = function(_id) {
      var existing = _.find(self.choices, { value: _id });
      if (existing) {
        if (existing.__removed) {
          delete existing.__removed;
        }
      } else {
        if ((!self.limit) || (self.choices.length < self.limit)) {
          self.choices.push({ value: _id });
        }
      }
      self.refresh();
      return true;
    };
    self.remove = function(_id) {
      if (self.removed) {
        // We are striking things through, not forgetting about them
        var removed = _.find(self.choices, { value: _id });
        if (removed) {
          removed.__removed = !removed.__removed;
        }
      } else {
        self.choices = _.filter(self.choices, function(choice) {
          return choice.value !== _id;
        });
      }
      self.refresh();
      return true;
    }
    self.refreshing = 0;
    self.last = [];
    self.refresh = function() {
      if (self.refreshing) {
        self.refreshing++;
        return;
      }
      self.refreshing++;
      self.$choices.html('');
      return self.api('chooser-choices', { choices: self.choices, field: self.field, validate: true }, function(result) {
        // If we're not going to make another API call in a moment and blow this one out anyway,
        // display and accept the validated results. If we are, don't do that, because it's a waste
        // of time and because accepting the validated results would sabotage the *next* refresh. -Tom

        if (self.refreshing > 1) {
          // We're superfluous, the last guy matters
          self.decrementRefreshing();
          return;
        }

        if (result.status !== 'ok') {
          self.decrementRefreshing();
          return;
        }

        self.choices = result.choices;
        var $currentInlineRelationships = self.$choices.find('[data-relationship-inline]');
        self.$choices.html(result.html);
        return async.eachSeries(self.choices || [], function(choice, callback) {
          var $current = $currentInlineRelationships.find('[data-relationship-inline="' + choice.value + '"]');
          var $new = self.$choices.find('[data-relationship-inline="' + choice.value + '"]');
          if ($current.length) {
            // Don't blow out the relationship forms for items already among the choices as that would
            // lose work in progress when we're just adding another choice
            $new.replaceWith($current);
            return setImmediate(callback);
          }
          return apos.schemas.populate(self.$choices.find('[data-relationship-inline="' + choice.value + '"]'), self.inlineSchema, choice, callback);
        }, function(err) {
          if (err) {
            // Ouch
            alert('Unable to populate form correctly, try again later');
            self.decrementRefreshing();
            return;
          }
          var compare = JSON.stringify(self.choices);
          if (self.last !== compare) {
            self.last = compare;
            self.onChange();
          }
          self.decrementRefreshing();
        });

      }, function(err) {
        self.decrementRefreshing();
      });
    };

    self.decrementRefreshing = function() {
      self.refreshing--;
      // If one or more additional refreshes have been requested, carrying out
      // one more is sufficient
      if (self.refreshing > 0) {
        self.refreshing = 0;
        self.refresh();
      }
    };

    self.enableLinks = function() {
      self.link('apos-delete', 'item', function($button, _id) {
        self.remove(_id);
      });
      self.link('apos-raise', 'item', function($button, _id) {
        var index = _.findIndex(self.choices, { value: _id });
        if (index === -1) {
          return;
        }
        if (index === 0) {
          return;
        }
        var tmp = self.choices[index - 1];
        self.choices[index - 1] = self.choices[index];
        self.choices[index] = tmp;
        return self.refresh();
      });
      self.link('apos-lower', 'item', function($button, _id) {
        var index = _.findIndex(self.choices, { value: _id });
        if (index === -1) {
          return;
        }
        if (index === (self.choices.length - 1)) {
          return;
        }
        var tmp = self.choices[index + 1];
        self.choices[index + 1] = self.choices[index];
        self.choices[index] = tmp;
        return self.refresh();
      });
      self.link('apos-relate', 'item', function($button, _id) {
        var choice = _.find(self.choices, { value: _id });
        if (!choice) {
          return;
        }
        var editorType = self.field.relationshipEditor || self.manager.getToolType('relationship-editor');
        apos.create(editorType, {
          choice: choice,
          field: self.field,
          action: self.action,
          chooser: self
        });
      });
      self.link('apos-browse', function() {
        self.launchBrowser();
      });
    };

    self.enableAutocomplete = function() {
      self.$autocomplete = self.$el.find('[data-autocomplete]');
      self.$autocomplete.autocomplete({
        source: function(request, response) {
          return self.api('autocomplete', {
            term: request.term,
            field: self.field
          }, response);
        },
        minLength: 1,
        // Stomp out suggestions of choices already made
        response: function(event, ui) {
          var content = ui.content;
          var filtered = _.filter(content, function(datum) {
            return !_.find(self.choices, { value: datum.value });
          });
          // "Why don't you just assign to ui.content?" jquery.ui.autocomplete
          // is holding a reference to the original array. If I assign to ui.content
          // I'm not changing that original array and jquery.ui.autocomplete ignores me.
          content.length = 0;
          $.each(filtered, function(i, datum) {
            content.push(datum);
          });
        },
        focus: function(event, ui) {
          self.$autocomplete.val(ui.item.label);
          return false;
        },
        select: function(event, ui) {
          self.$autocomplete.val('');
          self.add(ui.item.value);
          return false;
        },
        position: {  collision: 'flip'  }
      });
    };
    self.getBrowserType = function() {
      return self.manager.getToolType('manager-modal');
    };

    self.launchBrowser = function() {
      return self.manager.getTool('manager-modal', {
        decorate: self.decorateManager,
        chooser: self,
        source: 'chooser-modal',
        transition: 'slide'
      });
    };
    // Create a new chooser with the same data and options, merging in any
    // additional options from the first argument. Async because
    // the constructor is async. Delivers (err, newChooser)
    self.clone = function(options, callback) {
      var _options = {};
      _.assign(_options, self.options);
      _.assign(_options, options);
      return apos.create(self.__meta.name, _options, function(err, chooser) {
        if (err) {
          return callback(err);
        }
        return self.get(function(err, data) {
          if (err) {
            return callback(err);
          }
          chooser.set(data);
          return callback(null, chooser);
        });
      });
    };
    self.onChange = function() {
      if (self.limit && self.choices.length >= self.limit) {
        self.$el.addClass('apos-chooser-full');
        self.$autocomplete.prop('disabled', true);
      } else {
        self.$el.removeClass('apos-chooser-full');
        self.$autocomplete.prop('disabled', false);
      }
      if (self.options.change) {
        self.options.change();
      }
    };

    self.enableInlineSchema = function() {
      self.inlineSchema = _.filter(self.field.relationship || [], { inline: true });
    };

    // Adds and overrides methods of the apostrophe-pieces-manager-modal to
    // accommodate its use as a full-featured selection tool for the chooser,
    // including the ability to create new items on the fly and choose them

    self.decorateManager = function(manager, options) {
      manager.parentChooser = options.chooser;

      // TODO make this actually detect changes properly
      manager.unsavedChanges = true;

      var superBeforeShow = manager.beforeShow;
      manager.beforeShow = function(callback) {
        return superBeforeShow(function() {
          return manager.enableChooser(callback);
        });
      };

      manager.enableChooser = function(callback) {
        if (!manager.parentChooser) {
          return setImmediate(callback);
        }
        manager.enableCheckboxEventsForChooser();
        return manager.parentChooser.clone(
          { $el: manager.$el.find('[data-chooser]'), browse: false, autocomplete: false, change: manager.reflectChooserInCheckboxes },
          function(err, chooser) {
            if (err) {
              return callback(err);
            }
            manager.chooser = chooser;
            return callback(null);
          }
        );
      };

      manager.reflectChooserInCheckboxes = function() {
        if (!manager.chooser) {
          return;
        }
        return manager.chooser.get(function(err, choices) {
          if (err) {
            return;
          }
          manager.$el.find('[data-piece] input[type="checkbox"]').each(function() {
            var $box = $(this);
            var id = $box.closest('[data-piece]').attr('data-piece');
            var choice = _.find(choices, { value: id });
            var checked = choice && (!choice.__removed);
            $box.prop('checked', checked);
          });
        });
      };

      manager.enableCheckboxEventsForChooser = function() {
        manager.$el.on('change', '[data-piece] input[type="checkbox"]', function(e) {
          // in rare circumstances, might not be ready yet, don't crash
          if (!manager.chooser) {
            return;
          }
          var $box = $(this);
          var method = $box.prop('checked') ? manager.chooser.add : manager.chooser.remove;
          if (!method($box.closest('[data-piece]').attr('data-piece'))) {
            // If the operation could not be completed, change back the state
            // of the checkbox.
            $box.prop('checked', function(index, value) {
              return !value;
            });
          }
        });
      };

      manager.saveContent = function(callback) {
        if (!manager.chooser) {
          // This should not happen, but be graceful
          return callback(null);
        }
        // Pass our choices back to the chooser hanging out in a schema form that
        // initially triggered us via "browse"
        return manager.chooser.get(function(err, choices) {
          if (err) {
            return callback(err);
          }
          manager.parentChooser.set(choices);
          return callback(null);
        });
      };

      var superManagerSave = manager.save;
      manager.save = function(callback) {
        return superManagerSave(function(err) {
          if (err) {
            return callback && callback(err);
          }
          manager.parentChooser.afterManagerSave();
          return callback && callback(null);
        });
      };

      var superManagerCancel = manager.cancel;
      manager.cancel = function(callback) {
        return superManagerCancel(function(err) {
          if (err) {
            return callback && callback(err);
          }
          manager.parentChooser.afterManagerCancel();
          return callback && callback(null);
        });
      };

      manager.getConfirmCancelText = function() {
        return 'Are you sure you want to discard unsaved changes to this selection of '
          + options.pluralLabel.toLowerCase() + '?';
      }

      manager.beforeList = function(listOptions) {
        // The `limit` hint would break normal pagination in the manage view; the
        // chooser handles that one on its own. -Tom
        _.extend(listOptions, _.omit(self.field.hints, 'limit'), { chooser: true });
      };

      manager.afterRefresh = function() {
        manager.reflectChooserInCheckboxes();
      };
    };
    self.afterManagerSave = function() {};
    self.afterManagerCancel = function() {};
  }
});
<commit_msg>Retain inline relationship forms already present correctly when refreshing the list<commit_after>apos.define('apostrophe-doc-type-manager-chooser', {
  extend: 'apostrophe-context',
  beforeConstruct: function(self, options) {
    self.manager = options.manager;
    self.field = options.field;
    self.$el = options.$el;
    self.$el.data('aposChooser', self);
    if (self.field.type === 'joinByOne') {
      self.limit = 1;
    } else {
      self.limit = (self.field.hints && self.field.hints.limit) || self.field.limit;
    }
    self.choices = [];
  },
  afterConstruct: function(self, callback) {
    self.removed = self.options.removed;
    self.enableInlineSchema();

    return async.series([
      self.load
    ], function(err) {
      if (err) {
        return callback(err);
      }
      self.enableLinks();
      self.enableAutocomplete();
      return callback(null);
    });
  },
  construct: function(self, options) {
    self.load = function(callback) {
      var args = {};
      // browse button can be shut off, for instance if we're already appearing in
      // a manage modal in response to a browse button
      if (options.browse !== false) {
        args.browse = true;
      }
      if (options.autocomplete !== false) {
        args.autocomplete = true;
      }
      if (self.removed) {
        args.removed = true;
      }
      return self.html('chooser', args, function(html) {
        self.$el.html(html);
        self.$choices = self.$el.find('[data-choices]:first');
        self.set([]);
        return callback(null);
      }, function(err) {
        return callback(err);
      });
    };
    self.set = function(choices) {
      self.choices = choices;
      return self.refresh();
    };
    self.get = function(callback) {
      if (!self.refreshing) {
        return async.eachSeries(self.choices, function(choice, callback) {
          var $relationship = self.$choices.find('[data-relationship-inline="' + choice.value + '"]');
          return apos.schemas.convert($relationship, self.inlineSchema, choice, callback);
        }, function(err) {
          if (err) {
            return callback(err);
          }
          return callback(null, self.choices);
        });
      }
      setTimeout(function() {
        return self.get(callback);
      }, 50);
    };
    self.getFinal = function(callback) {
      return self.finalize(function(err) {
        if (err) {
          return callback(err);
        }
        return self.get(callback);
      });
    };
    self.finalize = function(callback) {
      // A hook to implement things like minimums, autocropping, etc.
      return setImmediate(callback);
    };
    self.add = function(_id) {
      var existing = _.find(self.choices, { value: _id });
      if (existing) {
        if (existing.__removed) {
          delete existing.__removed;
        }
      } else {
        if ((!self.limit) || (self.choices.length < self.limit)) {
          self.choices.push({ value: _id });
        }
      }
      self.refresh();
      return true;
    };
    self.remove = function(_id) {
      if (self.removed) {
        // We are striking things through, not forgetting about them
        var removed = _.find(self.choices, { value: _id });
        if (removed) {
          removed.__removed = !removed.__removed;
        }
      } else {
        self.choices = _.filter(self.choices, function(choice) {
          return choice.value !== _id;
        });
      }
      self.refresh();
      return true;
    }
    self.refreshing = 0;
    self.last = [];
    self.refresh = function() {
      if (self.refreshing) {
        self.refreshing++;
        return;
      }
      self.refreshing++;
      var $currentInlineRelationships = self.$choices.find('[data-relationship-inline]');
      self.$choices.html('');
      return self.api('chooser-choices', { choices: self.choices, field: self.field, validate: true }, function(result) {
        // If we're not going to make another API call in a moment and blow this one out anyway,
        // display and accept the validated results. If we are, don't do that, because it's a waste
        // of time and because accepting the validated results would sabotage the *next* refresh. -Tom

        if (self.refreshing > 1) {
          // We're superfluous, the last guy matters
          self.decrementRefreshing();
          return;
        }

        if (result.status !== 'ok') {
          self.decrementRefreshing();
          return;
        }

        self.choices = result.choices;
        self.$choices.html(result.html);
        return async.eachSeries(self.choices || [], function(choice, callback) {
          var $current = $currentInlineRelationships.filter('[data-relationship-inline="' + choice.value + '"]');
          var $new = self.$choices.find('[data-relationship-inline="' + choice.value + '"]');
          if ($current.length) {
            // Don't blow out the relationship forms for items already among the choices as that would
            // lose work in progress when we're just adding another choice
            $new.replaceWith($current);
            return setImmediate(callback);
          }
          return apos.schemas.populate(self.$choices.find('[data-relationship-inline="' + choice.value + '"]'), self.inlineSchema, choice, callback);
        }, function(err) {
          if (err) {
            // Ouch
            alert('Unable to populate form correctly, try again later');
            self.decrementRefreshing();
            return;
          }
          var compare = JSON.stringify(self.choices);
          if (self.last !== compare) {
            self.last = compare;
            self.onChange();
          }
          self.decrementRefreshing();
        });

      }, function(err) {
        self.decrementRefreshing();
      });
    };

    self.decrementRefreshing = function() {
      self.refreshing--;
      // If one or more additional refreshes have been requested, carrying out
      // one more is sufficient
      if (self.refreshing > 0) {
        self.refreshing = 0;
        self.refresh();
      }
    };

    self.enableLinks = function() {
      self.link('apos-delete', 'item', function($button, _id) {
        self.remove(_id);
      });
      self.link('apos-raise', 'item', function($button, _id) {
        var index = _.findIndex(self.choices, { value: _id });
        if (index === -1) {
          return;
        }
        if (index === 0) {
          return;
        }
        var tmp = self.choices[index - 1];
        self.choices[index - 1] = self.choices[index];
        self.choices[index] = tmp;
        return self.refresh();
      });
      self.link('apos-lower', 'item', function($button, _id) {
        var index = _.findIndex(self.choices, { value: _id });
        if (index === -1) {
          return;
        }
        if (index === (self.choices.length - 1)) {
          return;
        }
        var tmp = self.choices[index + 1];
        self.choices[index + 1] = self.choices[index];
        self.choices[index] = tmp;
        return self.refresh();
      });
      self.link('apos-relate', 'item', function($button, _id) {
        var choice = _.find(self.choices, { value: _id });
        if (!choice) {
          return;
        }
        var editorType = self.field.relationshipEditor || self.manager.getToolType('relationship-editor');
        apos.create(editorType, {
          choice: choice,
          field: self.field,
          action: self.action,
          chooser: self
        });
      });
      self.link('apos-browse', function() {
        self.launchBrowser();
      });
    };

    self.enableAutocomplete = function() {
      self.$autocomplete = self.$el.find('[data-autocomplete]');
      self.$autocomplete.autocomplete({
        source: function(request, response) {
          return self.api('autocomplete', {
            term: request.term,
            field: self.field
          }, response);
        },
        minLength: 1,
        // Stomp out suggestions of choices already made
        response: function(event, ui) {
          var content = ui.content;
          var filtered = _.filter(content, function(datum) {
            return !_.find(self.choices, { value: datum.value });
          });
          // "Why don't you just assign to ui.content?" jquery.ui.autocomplete
          // is holding a reference to the original array. If I assign to ui.content
          // I'm not changing that original array and jquery.ui.autocomplete ignores me.
          content.length = 0;
          $.each(filtered, function(i, datum) {
            content.push(datum);
          });
        },
        focus: function(event, ui) {
          self.$autocomplete.val(ui.item.label);
          return false;
        },
        select: function(event, ui) {
          self.$autocomplete.val('');
          self.add(ui.item.value);
          return false;
        },
        position: {  collision: 'flip'  }
      });
    };
    self.getBrowserType = function() {
      return self.manager.getToolType('manager-modal');
    };

    self.launchBrowser = function() {
      return self.manager.getTool('manager-modal', {
        decorate: self.decorateManager,
        chooser: self,
        source: 'chooser-modal',
        transition: 'slide'
      });
    };
    // Create a new chooser with the same data and options, merging in any
    // additional options from the first argument. Async because
    // the constructor is async. Delivers (err, newChooser)
    self.clone = function(options, callback) {
      var _options = {};
      _.assign(_options, self.options);
      _.assign(_options, options);
      return apos.create(self.__meta.name, _options, function(err, chooser) {
        if (err) {
          return callback(err);
        }
        return self.get(function(err, data) {
          if (err) {
            return callback(err);
          }
          chooser.set(data);
          return callback(null, chooser);
        });
      });
    };
    self.onChange = function() {
      if (self.limit && self.choices.length >= self.limit) {
        self.$el.addClass('apos-chooser-full');
        self.$autocomplete.prop('disabled', true);
      } else {
        self.$el.removeClass('apos-chooser-full');
        self.$autocomplete.prop('disabled', false);
      }
      if (self.options.change) {
        self.options.change();
      }
    };

    self.enableInlineSchema = function() {
      self.inlineSchema = _.filter(self.field.relationship || [], { inline: true });
    };

    // Adds and overrides methods of the apostrophe-pieces-manager-modal to
    // accommodate its use as a full-featured selection tool for the chooser,
    // including the ability to create new items on the fly and choose them

    self.decorateManager = function(manager, options) {
      manager.parentChooser = options.chooser;

      // TODO make this actually detect changes properly
      manager.unsavedChanges = true;

      var superBeforeShow = manager.beforeShow;
      manager.beforeShow = function(callback) {
        return superBeforeShow(function() {
          return manager.enableChooser(callback);
        });
      };

      manager.enableChooser = function(callback) {
        if (!manager.parentChooser) {
          return setImmediate(callback);
        }
        manager.enableCheckboxEventsForChooser();
        return manager.parentChooser.clone(
          { $el: manager.$el.find('[data-chooser]'), browse: false, autocomplete: false, change: manager.reflectChooserInCheckboxes },
          function(err, chooser) {
            if (err) {
              return callback(err);
            }
            manager.chooser = chooser;
            return callback(null);
          }
        );
      };

      manager.reflectChooserInCheckboxes = function() {
        if (!manager.chooser) {
          return;
        }
        return manager.chooser.get(function(err, choices) {
          if (err) {
            return;
          }
          manager.$el.find('[data-piece] input[type="checkbox"]').each(function() {
            var $box = $(this);
            var id = $box.closest('[data-piece]').attr('data-piece');
            var choice = _.find(choices, { value: id });
            var checked = choice && (!choice.__removed);
            $box.prop('checked', checked);
          });
        });
      };

      manager.enableCheckboxEventsForChooser = function() {
        manager.$el.on('change', '[data-piece] input[type="checkbox"]', function(e) {
          // in rare circumstances, might not be ready yet, don't crash
          if (!manager.chooser) {
            return;
          }
          var $box = $(this);
          var method = $box.prop('checked') ? manager.chooser.add : manager.chooser.remove;
          if (!method($box.closest('[data-piece]').attr('data-piece'))) {
            // If the operation could not be completed, change back the state
            // of the checkbox.
            $box.prop('checked', function(index, value) {
              return !value;
            });
          }
        });
      };

      manager.saveContent = function(callback) {
        if (!manager.chooser) {
          // This should not happen, but be graceful
          return callback(null);
        }
        // Pass our choices back to the chooser hanging out in a schema form that
        // initially triggered us via "browse"
        return manager.chooser.get(function(err, choices) {
          if (err) {
            return callback(err);
          }
          manager.parentChooser.set(choices);
          return callback(null);
        });
      };

      var superManagerSave = manager.save;
      manager.save = function(callback) {
        return superManagerSave(function(err) {
          if (err) {
            return callback && callback(err);
          }
          manager.parentChooser.afterManagerSave();
          return callback && callback(null);
        });
      };

      var superManagerCancel = manager.cancel;
      manager.cancel = function(callback) {
        return superManagerCancel(function(err) {
          if (err) {
            return callback && callback(err);
          }
          manager.parentChooser.afterManagerCancel();
          return callback && callback(null);
        });
      };

      manager.getConfirmCancelText = function() {
        return 'Are you sure you want to discard unsaved changes to this selection of '
          + options.pluralLabel.toLowerCase() + '?';
      }

      manager.beforeList = function(listOptions) {
        // The `limit` hint would break normal pagination in the manage view; the
        // chooser handles that one on its own. -Tom
        _.extend(listOptions, _.omit(self.field.hints, 'limit'), { chooser: true });
      };

      manager.afterRefresh = function() {
        manager.reflectChooserInCheckboxes();
      };
    };
    self.afterManagerSave = function() {};
    self.afterManagerCancel = function() {};
  }
});
<|endoftext|>


<commit_before>// Copyright 2015, University of Colorado Boulder

/**
 * Abstract class for color profiles for simulations. See GravityAndOrbitsColors for an example.
 * This file was modelled after MoleculeShapesColors.
 *
 * ColorProfile gives the option to synchronize the sim running in an iframe with a color picker.
 * To create a file with this capacity, model it after gravity-and-orbits-colors.html, with the colors array
 * changed to match the color profile you are using, and the title and iframe src changed.
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 * @author Aaron Davis
 */
define( function( require ) {
  'use strict';

  // modules
  var Color = require( 'SCENERY/util/Color' );
  var inherit = require( 'PHET_CORE/inherit' );
  var PropertySet = require( 'AXON/PropertySet' );
  var sceneryPhet = require( 'SCENERY_PHET/sceneryPhet' );

  /**
   * @param {Array.<Color|string>} colors
   * @constructor
   */
  function ColorProfile( colors ) {

    var self = this;

    this.colors = colors; // @private

    // initial properties object, to load into the PropertySet (so reset works nicely)
    // all properties are @public (read-only) except profileNameProperty, which is @public
    var initialProperties = {
      profileName: 'default' // {string} @public - name of the color profile, e.g. 'default' or 'projector'
    };

    for ( var key in colors ) {
      assert && assert( colors[ key ].hasOwnProperty( 'default' ), 'missing default color for "' + key + '"' );

      // convert all color strings to Color objects
      for ( var color in colors[ key ] ) {
        colors[ key ][ color ] = Color.toColor( colors[ key ][ color ] );
      }
      initialProperties[ key ] = colors[ key ].default;
    }
    PropertySet.call( this, initialProperties );

    // receives iframe communication to set a color
    window.addEventListener( 'message', function( evt ) {
      var data = JSON.parse( evt.data );
      if ( data.type === 'setColor' ) {
        self[ data.name ] = new Color( data.value );
      }
    } );

    // @public Applies all colors for the specific named color scheme, ignoring colors that aren't specified for it.
    this.profileNameProperty.link( function( profileName ) {
      for ( var key in self.colors ) {
        var oldColor = self[ key ];
        var colorObject = self.colors[ key ];
        var newColor = ( profileName in colorObject ) ? colorObject[ profileName ] : colorObject.default;
        if ( !newColor.equals( oldColor ) ) {
          self[ key ] = newColor;
          self.reportColor( key );
        }
      }
      self.trigger( 'profileChanged' );
    } );

    // initial communication
    for ( var colorName in colors ) {
      this.reportColor( colorName );
    }
  }

  sceneryPhet.register( 'ColorProfile', ColorProfile );

  return inherit( PropertySet, ColorProfile, {

    // @public sends iframe communication to report the current color for the key name
    reportColor: function( key ) {
      var hexColor = this[ key ].toNumber().toString( 16 );
      while ( hexColor.length < 6 ) {
        hexColor = '0' + hexColor;
      }

      window.parent && window.parent.postMessage( JSON.stringify( {
        type: 'reportColor',
        name: key,
        value: '#' + hexColor
      } ), '*' );
    }
  } );
} );
<commit_msg>improve doc of @param colors somewhat, https://github.com/phetsims/scenery-phet/issues/277<commit_after>// Copyright 2015, University of Colorado Boulder

/**
 * Abstract class for color profiles for simulations. See GravityAndOrbitsColors for an example.
 * This file was modelled after MoleculeShapesColors.
 *
 * ColorProfile gives the option to synchronize the sim running in an iframe with a color picker.
 * To create a file with this capacity, model it after gravity-and-orbits-colors.html, with the colors array
 * changed to match the color profile you are using, and the title and iframe src changed.
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 * @author Aaron Davis
 */
define( function( require ) {
  'use strict';

  // modules
  var Color = require( 'SCENERY/util/Color' );
  var inherit = require( 'PHET_CORE/inherit' );
  var PropertySet = require( 'AXON/PropertySet' );
  var sceneryPhet = require( 'SCENERY_PHET/sceneryPhet' );

  /**
   * @param {Object} colors - object hash, whose property names become Property names.
   *                          Each property is another hash, whose properties are the colors for each scheme.
   *                          (Confusing? You bet. See https://github.com/phetsims/scenery-phet/issues/277)
   * @constructor
   */
  function ColorProfile( colors ) {

    var self = this;

    this.colors = colors; // @private

    // initial properties object, to load into the PropertySet (so reset works nicely)
    // all properties are @public (read-only) except profileNameProperty, which is @public
    var initialProperties = {
      profileName: 'default' // {string} @public - name of the color profile, e.g. 'default' or 'projector'
    };

    for ( var key in colors ) {
      assert && assert( colors[ key ].hasOwnProperty( 'default' ), 'missing default color for "' + key + '"' );

      // convert all color strings to Color objects
      for ( var color in colors[ key ] ) {
        colors[ key ][ color ] = Color.toColor( colors[ key ][ color ] );
      }
      initialProperties[ key ] = colors[ key ].default;
    }
    PropertySet.call( this, initialProperties );

    // receives iframe communication to set a color
    window.addEventListener( 'message', function( evt ) {
      var data = JSON.parse( evt.data );
      if ( data.type === 'setColor' ) {
        self[ data.name ] = new Color( data.value );
      }
    } );

    // @public Applies all colors for the specific named color scheme, ignoring colors that aren't specified for it.
    this.profileNameProperty.link( function( profileName ) {
      for ( var key in self.colors ) {
        var oldColor = self[ key ];
        var colorObject = self.colors[ key ];
        var newColor = ( profileName in colorObject ) ? colorObject[ profileName ] : colorObject.default;
        if ( !newColor.equals( oldColor ) ) {
          self[ key ] = newColor;
          self.reportColor( key );
        }
      }
      self.trigger( 'profileChanged' );
    } );

    // initial communication
    for ( var colorName in colors ) {
      this.reportColor( colorName );
    }
  }

  sceneryPhet.register( 'ColorProfile', ColorProfile );

  return inherit( PropertySet, ColorProfile, {

    // @public sends iframe communication to report the current color for the key name
    reportColor: function( key ) {
      var hexColor = this[ key ].toNumber().toString( 16 );
      while ( hexColor.length < 6 ) {
        hexColor = '0' + hexColor;
      }

      window.parent && window.parent.postMessage( JSON.stringify( {
        type: 'reportColor',
        name: key,
        value: '#' + hexColor
      } ), '*' );
    }
  } );
} );
<|endoftext|>