<commit_before>const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Main = imports.ui.main;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const St = imports.gi.St;

const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Util = Me.imports.util;

function LOG(message) {
	// log("[pixel-saver]: " + message);
}

function WARN(message) {
	log("[pixel-saver]: " + message);
}

/*
 * Buttons
 */
const DCONF_META_PATH = 'org.gnome.desktop.wm.preferences';

let actors = [], boxes = [];
function createButtons() {
	// Ensure we do not create buttons twice.
	destroyButtons();

	actors = [new St.Bin({ style_class: 'box-bin'}), new St.Bin({ style_class: 'box-bin'})];
	boxes = [new St.BoxLayout({ style_class: 'button-box' }), new St.BoxLayout({ style_class: 'button-box' })];

	for (let i = 0; i < actors.length; ++i) {
		actors[i].add_actor(boxes[i]);
	}

	let order = new Gio.Settings({schema_id: DCONF_META_PATH}).get_string('button-layout');
	LOG('Buttons layout : ' + order);

	let orders = order.replace(/ /g, '').split(':');

	orders[0] = orders[0].split(',');
	orders[1] = orders[1].split(',');

	const callbacks = {
		minimize : minimize,
		maximize : maximize,
		close    : close
	};

	for (let bi = 0; bi < boxes.length; ++bi) {
		let order = orders[bi],
			box = boxes[bi];

		for (let i = 0; i < order.length; ++i) {
			if(!order[i]) {
				continue;
			}

			if (!callbacks[order[i]]) {
				// skip if the butto name is not right...
				WARN("\'%s\' is not a valid button.".format(order[i]));
				continue;
			}

			let button = new St.Button({
				style_class: order[i]  + ' window-button',
				track_hover: true
			});

			button.connect('button-press-event', callbacks[order[i]]);
			box.add(button);
		}
	}

	Mainloop.idle_add(function () {
		// 1 for activity button and -1 for the menu
		if(boxes[0].get_children().length) {
			Main.panel._leftBox.insert_child_at_index(actors[0], 1);
		}

		if(boxes[1].get_children().length) {
			Main.panel._rightBox.insert_child_at_index(actors[1], Main.panel._rightBox.get_children().length - 1);
		}

		updateVisibility();

		return false;
	});
}

function destroyButtons() {
	for (let i = 0; i < actors.length; ++i) {
		actors[i].destroy();
		boxes[i].destroy();
	}

	actors = [];
	boxes = [];
}

/*
 * Buttons actions
 */
const MAXIMIZED = Util.MAXIMIZED;

function minimize() {
	let win = Util.getWindow();
	if (!win || win.minimized) {
		WARN('impossible to minimize');
		return;
	}

	win.minimize();
}

function maximize() {
	let win = Util.getWindow();
	if (!win) {
		WARN('impossible to maximize');
		return;
	}

	if (win.get_maximized() === MAXIMIZED) {
		win.unmaximize(MAXIMIZED);
	} else {
		WARN('window shoud already be maximized');
		win.maximize(MAXIMIZED);
	}

	win.activate(global.get_current_time());
}

function close() {
	let win = Util.getWindow();
	if (!win) {
		WARN('impossible to close');
		return;
	}

	win.delete(global.get_current_time());
}

/*
 * Theming
 */
let activeCSS = false;
function loadTheme() {
	let theme = Meta.prefs_get_theme(),
		cssPath = GLib.build_filenamev([extensionPath, 'themes', theme, 'style.css']);

	LOG('Load theme ' + theme);

	if (!GLib.file_test(cssPath, GLib.FileTest.EXISTS)) {
		cssPath = GLib.build_filenamev([extensionPath, 'themes/default/style.css']);
	}

	if(cssPath === activeCSS) {
		return;
	}

	unloadTheme();

	// load the new style
	St.ThemeContext.get_for_stage(global.stage).get_theme().load_stylesheet(cssPath);

	// Force style update.
	for (let i = 0; i < actors.length; ++i) {
		actors[i].grab_key_focus();
	}

	activeCSS = cssPath;
}

function unloadTheme() {
	if(activeCSS) {
		LOG('Unload ' + activeCSS);

		St.ThemeContext.get_for_stage(global.stage).get_theme().unload_stylesheet(activeCSS);
		activeCSS = false;
	}
}

/*
 * callbacks
 */
function updateVisibility() {
	// If we have a window to control, then we show the buttons.
	let visible = !Main.overview.visible && !!Util.getWindow();

	for (let i = 0; i < actors.length; ++i) {
		let actor = actors[i];
		if(!boxes[i].get_children().length) {
			continue;
		}

		if(visible) {
			actor.show();
		} else {
			actor.hide();
		}
	}

	return false;
}

/*
 * Subextension hooks
 */
let extensionPath;
function init(extensionMeta) {
	extensionPath = extensionMeta.path;
}

let wmCallbackIDs = [];
let overviewCallbackIDs = [];
function enable() {
	createButtons();
	loadTheme();

	overviewCallbackIDs.push(Main.overview.connect('showing', updateVisibility));
	overviewCallbackIDs.push(Main.overview.connect('hidden', updateVisibility));

	wmCallbackIDs.push(global.window_manager.connect('switch-workspace', updateVisibility));
	wmCallbackIDs.push(global.window_manager.connect('map', updateVisibility));
	wmCallbackIDs.push(global.window_manager.connect('minimize', updateVisibility));
	wmCallbackIDs.push(global.window_manager.connect('maximize', updateVisibility));
	wmCallbackIDs.push(global.window_manager.connect('unmaximize', updateVisibility));

	// note: 'destroy' needs a delay for .list_windows() report correctly
    wmCallbackIDs.push(global.window_manager.connect('destroy', function () {
		Mainloop.idle_add(updateVisibility);
	}));
}

function disable() {
	for (let i = 0; i < wmCallbackIDs.length; ++i) {
		global.window_manager.disconnect(wmCallbackIDs[i]);
	}

	for (let i = 0; i < overviewCallbackIDs.length; ++i) {
		Main.overview.disconnect(overviewCallbackIDs[i]);
	}

	wmCallbackIDs = [];
	overviewCallbackIDs = [];

	unloadTheme();
	destroyButtons();
}

<commit_msg>Do not show button when window is not decorated.<commit_after>const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Main = imports.ui.main;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const St = imports.gi.St;

const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Util = Me.imports.util;

function LOG(message) {
	// log("[pixel-saver]: " + message);
}

function WARN(message) {
	log("[pixel-saver]: " + message);
}

/*
 * Buttons
 */
const DCONF_META_PATH = 'org.gnome.desktop.wm.preferences';

let actors = [], boxes = [];
function createButtons() {
	// Ensure we do not create buttons twice.
	destroyButtons();

	actors = [new St.Bin({ style_class: 'box-bin'}), new St.Bin({ style_class: 'box-bin'})];
	boxes = [new St.BoxLayout({ style_class: 'button-box' }), new St.BoxLayout({ style_class: 'button-box' })];

	for (let i = 0; i < actors.length; ++i) {
		actors[i].add_actor(boxes[i]);
	}

	let order = new Gio.Settings({schema_id: DCONF_META_PATH}).get_string('button-layout');
	LOG('Buttons layout : ' + order);

	let orders = order.replace(/ /g, '').split(':');

	orders[0] = orders[0].split(',');
	orders[1] = orders[1].split(',');

	const callbacks = {
		minimize : minimize,
		maximize : maximize,
		close    : close
	};

	for (let bi = 0; bi < boxes.length; ++bi) {
		let order = orders[bi],
			box = boxes[bi];

		for (let i = 0; i < order.length; ++i) {
			if(!order[i]) {
				continue;
			}

			if (!callbacks[order[i]]) {
				// skip if the butto name is not right...
				WARN("\'%s\' is not a valid button.".format(order[i]));
				continue;
			}

			let button = new St.Button({
				style_class: order[i]  + ' window-button',
				track_hover: true
			});

			button.connect('button-press-event', callbacks[order[i]]);
			box.add(button);
		}
	}

	Mainloop.idle_add(function () {
		// 1 for activity button and -1 for the menu
		if(boxes[0].get_children().length) {
			Main.panel._leftBox.insert_child_at_index(actors[0], 1);
		}

		if(boxes[1].get_children().length) {
			Main.panel._rightBox.insert_child_at_index(actors[1], Main.panel._rightBox.get_children().length - 1);
		}

		updateVisibility();

		return false;
	});
}

function destroyButtons() {
	for (let i = 0; i < actors.length; ++i) {
		actors[i].destroy();
		boxes[i].destroy();
	}

	actors = [];
	boxes = [];
}

/*
 * Buttons actions
 */
const MAXIMIZED = Util.MAXIMIZED;

function minimize() {
	let win = Util.getWindow();
	if (!win || win.minimized) {
		WARN('impossible to minimize');
		return;
	}

	win.minimize();
}

function maximize() {
	let win = Util.getWindow();
	if (!win) {
		WARN('impossible to maximize');
		return;
	}

	if (win.get_maximized() === MAXIMIZED) {
		win.unmaximize(MAXIMIZED);
	} else {
		WARN('window shoud already be maximized');
		win.maximize(MAXIMIZED);
	}

	win.activate(global.get_current_time());
}

function close() {
	let win = Util.getWindow();
	if (!win) {
		WARN('impossible to close');
		return;
	}

	win.delete(global.get_current_time());
}

/*
 * Theming
 */
let activeCSS = false;
function loadTheme() {
	let theme = Meta.prefs_get_theme(),
		cssPath = GLib.build_filenamev([extensionPath, 'themes', theme, 'style.css']);

	LOG('Load theme ' + theme);

	if (!GLib.file_test(cssPath, GLib.FileTest.EXISTS)) {
		cssPath = GLib.build_filenamev([extensionPath, 'themes/default/style.css']);
	}

	if(cssPath === activeCSS) {
		return;
	}

	unloadTheme();

	// load the new style
	St.ThemeContext.get_for_stage(global.stage).get_theme().load_stylesheet(cssPath);

	// Force style update.
	for (let i = 0; i < actors.length; ++i) {
		actors[i].grab_key_focus();
	}

	activeCSS = cssPath;
}

function unloadTheme() {
	if(activeCSS) {
		LOG('Unload ' + activeCSS);

		St.ThemeContext.get_for_stage(global.stage).get_theme().unload_stylesheet(activeCSS);
		activeCSS = false;
	}
}

/*
 * callbacks
 */
function updateVisibility() {
	// If we have a window to control, then we show the buttons.
	let visible = !Main.overview.visible;
	if (visible) {
		visible = false;
		let win = Util.getWindow();
		if (win) {
			visible = win.decorated;
		}
	}

	for (let i = 0; i < actors.length; ++i) {
		let actor = actors[i];
		if(!boxes[i].get_children().length) {
			continue;
		}

		if(visible) {
			actor.show();
		} else {
			actor.hide();
		}
	}

	return false;
}

/*
 * Subextension hooks
 */
let extensionPath;
function init(extensionMeta) {
	extensionPath = extensionMeta.path;
}

let wmCallbackIDs = [];
let overviewCallbackIDs = [];
function enable() {
	createButtons();
	loadTheme();

	overviewCallbackIDs.push(Main.overview.connect('showing', updateVisibility));
	overviewCallbackIDs.push(Main.overview.connect('hidden', updateVisibility));

	wmCallbackIDs.push(global.window_manager.connect('switch-workspace', updateVisibility));
	wmCallbackIDs.push(global.window_manager.connect('map', updateVisibility));
	wmCallbackIDs.push(global.window_manager.connect('minimize', updateVisibility));
	wmCallbackIDs.push(global.window_manager.connect('maximize', updateVisibility));
	wmCallbackIDs.push(global.window_manager.connect('unmaximize', updateVisibility));

	// note: 'destroy' needs a delay for .list_windows() report correctly
    wmCallbackIDs.push(global.window_manager.connect('destroy', function () {
		Mainloop.idle_add(updateVisibility);
	}));
}

function disable() {
	for (let i = 0; i < wmCallbackIDs.length; ++i) {
		global.window_manager.disconnect(wmCallbackIDs[i]);
	}

	for (let i = 0; i < overviewCallbackIDs.length; ++i) {
		Main.overview.disconnect(overviewCallbackIDs[i]);
	}

	wmCallbackIDs = [];
	overviewCallbackIDs = [];

	unloadTheme();
	destroyButtons();
}

<|endoftext|>


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

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, forin: true, maxerr: 50, regexp: true */
/*global define, $, window, document */

/**
 * RemoteFunctions define the functions to be executed in the browser. This
 * modules should define a single function that returns an object of all
 * exported functions.
 */
function RemoteFunctions(experimental) {
    "use strict";

    var lastKeepAliveTime = Date.now();

    var HIGHLIGHT_CLASSNAME = "__brackets-ld-highlight",
        KEEP_ALIVE_TIMEOUT  = 3000;   // Keep alive timeout value, in milliseconds

    // determine the color for a type
    function _typeColor(type, highlight) {
        switch (type) {
        case "html":
            return highlight ? "#eec" : "#ffe";
        case "css":
            return highlight ? "#cee" : "#eff";
        case "js":
            return highlight ? "#ccf" : "#eef";
        default:
            return highlight ? "#ddd" : "#eee";
        }
    }

    // compute the screen offset of an element
    function _screenOffset(element, key) {
        var bounds = element.getBoundingClientRect();
        if (key === "offsetLeft") {
            return bounds.left + window.pageXOffset;
        } else {
            return bounds.top + window.pageYOffset;
        }
    }

    // set an event on a element
    function _trigger(element, name, value, autoRemove) {
        var key = "data-ld-" + name;
        if (value !== undefined && value !== null) {
            element.setAttribute(key, value);
            if (autoRemove) {
                window.setTimeout(element.removeAttribute.bind(element, key));
            }
        } else {
            element.removeAttribute(key);
        }
    }

    // construct the info menu
    function Menu(element) {
        this.element = element;
        _trigger(this.element, "showgoto", 1, true);
        window.setTimeout(window.remoteShowGoto);
        this.remove = this.remove.bind(this);
    }

    Menu.prototype = {
        onClick: function (url, event) {
            event.preventDefault();
            _trigger(this.element, "goto", url, true);
            this.remove();
        },

        createBody: function () {
            if (this.body) {
                return;
            }

            // compute the position on screen
            var x = _screenOffset(this.element, "offsetLeft");
            var y = _screenOffset(this.element, "offsetTop") + this.element.offsetHeight;

            // create the container
            this.body = document.createElement("div");
            this.body.style.setProperty("z-index", 2147483647);
            this.body.style.setProperty("position", "absolute");
            this.body.style.setProperty("left", x + "px");
            this.body.style.setProperty("top", y + "px");
            this.body.style.setProperty("font-size", "11pt");

            // draw the background
            this.body.style.setProperty("background", "#fff");
            this.body.style.setProperty("border", "1px solid #888");
            this.body.style.setProperty("-webkit-box-shadow", "2px 2px 6px 0px #ccc");
            this.body.style.setProperty("border-radius", "6px");
            this.body.style.setProperty("padding", "6px");
        },

        addItem: function (target) {
            var item = document.createElement("div");
            item.style.setProperty("padding", "2px 6px");
            if (this.body.childNodes.length > 0) {
                item.style.setProperty("border-top", "1px solid #ccc");
            }
            item.style.setProperty("cursor", "pointer");
            item.style.setProperty("background", _typeColor(target.type));
            item.innerHTML = target.name;
            item.addEventListener("click", this.onClick.bind(this, target.url));

            if (target.file) {
                var file = document.createElement("i");
                file.style.setProperty("float", "right");
                file.style.setProperty("margin-left", "12px");
                file.innerHTML = " " + target.file;
                item.appendChild(file);
            }
            this.body.appendChild(item);
        },

        show: function () {
            if (!this.body) {
                this.body = this.createBody();
            }
            if (!this.body.parentNode) {
                document.body.appendChild(this.body);
            }
            document.addEventListener("click", this.remove);
        },

        remove: function () {
            if (this.body && this.body.parentNode) {
                document.body.removeChild(this.body);
            }
            document.removeEventListener("click", this.remove);
        }

    };

    function Editor(element) {
        this.onBlur = this.onBlur.bind(this);
        this.onKeyPress = this.onKeyPress.bind(this);

        this.element = element;
        this.element.setAttribute("contenteditable", "true");
        this.element.focus();
        this.element.addEventListener("blur", this.onBlur);
        this.element.addEventListener("keypress", this.onKeyPress);

        this.revertText = this.element.innerHTML;

        _trigger(this.element, "edit", 1);
    }

    Editor.prototype = {
        onBlur: function (event) {
            this.element.removeAttribute("contenteditable");
            this.element.removeEventListener("blur", this.onBlur);
            this.element.removeEventListener("keypress", this.onKeyPress);
            _trigger(this.element, "edit", 0, true);
        },

        onKeyPress: function (event) {
            switch (event.which) {
            case 13: // return
                this.element.blur();
                break;
            case 27: // esc
                this.element.innerHTML = this.revertText;
                this.element.blur();
                break;
            }
        }
    };

    function Highlight(color, trigger) {
        this.color = color;
        this.trigger = !!trigger;
        this.elements = [];
        this.selector = "";
    }

    Highlight.prototype = {
        _elementExists: function (element) {
            var i;
            for (i in this.elements) {
                if (this.elements[i] === element) {
                    return true;
                }
            }
            return false;
        },

        _makeHighlightDiv: function (element, doAnimation) {
            var elementBounds = element.getBoundingClientRect(),
                highlight = window.document.createElement("div"),
                styles = window.getComputedStyle(element);

            highlight.className = HIGHLIGHT_CLASSNAME;

            var stylesToSet = {
                "left": _screenOffset(element, "offsetLeft") + "px",
                "top": _screenOffset(element, "offsetTop") + "px",
                "width": (elementBounds.width - 2) + "px",
                "height": (elementBounds.height - 2) + "px",
                "z-index": 2000000,
                "position": "absolute",
                "pointer-events": "none",
                "border-top-left-radius": styles.borderTopLeftRadius,
                "border-top-right-radius": styles.borderTopRightRadius,
                "border-bottom-left-radius": styles.borderBottomLeftRadius,
                "border-bottom-right-radius": styles.borderBottomRightRadius,
                "border-style": "solid",
                "border-width": "1px",
                "border-color": "rgb(94,167,255)"
            };

            var animateStartValues = {
                "opacity": 0,
                "background": "rgba(94,167,255, 0.5)",
                "box-shadow": "0 0 6px 1px rgba(94,167,255, 0.6), inset 0 0 4px 1px rgba(255,255,255,1)"
            };

            var animateEndValues = {
                "opacity": 1,
                "background": "rgba(94,167,255, 0.1)",
                "box-shadow": "0 0 1px 0 rgba(94,167,255, 0), inset 0 0 4px 1px rgba(255,255,255,0.8)"
            };

            var transitionValues = {
                "-webkit-transition-property": "opacity, box-shadow, background",
                "-webkit-transition-duration": "0.3s, 0.4s, 0.4s",
                "transition-property": "opacity, box-shadow, background",
                "transition-duration": "0.3s, 0.4s, 0.4s"
            };

            function _setStyleValues(styleValues, obj) {
                var prop;

                for (prop in styleValues) {
                    obj.setProperty(prop, styleValues[prop]);
                }
            }

            _setStyleValues(stylesToSet, highlight.style);
            _setStyleValues(
                doAnimation ? animateStartValues : animateEndValues,
                highlight.style
            );

            if (doAnimation) {
                _setStyleValues(transitionValues, highlight.style);

                window.setTimeout(function () {
                    _setStyleValues(animateEndValues, highlight.style);
                }, 0);
            }

            window.document.body.appendChild(highlight);
        },

        add: function (element, doAnimation) {
            if (this._elementExists(element) || element === document) {
                return;
            }
            if (this.trigger) {
                _trigger(element, "highlight", 1);
            }
            this.elements.push(element);

            this._makeHighlightDiv(element, doAnimation);
        },

        clear: function () {
            var i, highlights = window.document.querySelectorAll("." + HIGHLIGHT_CLASSNAME),
                body = window.document.body;

            for (i = 0; i < highlights.length; i++) {
                body.removeChild(highlights[i]);
            }

            this.elements = [];
        },

        redraw: function () {
            var i, highlighted;

            // When redrawing a selector-based highlight, run a new selector
            // query to ensure we have the latest set of elements to highlight.
            if (this.selector) {
                highlighted = window.document.querySelectorAll(this.selector);
            } else {
                highlighted = this.elements.slice(0);
            }

            this.clear();
            for (i = 0; i < highlighted.length; i++) {
                this.add(highlighted[i], false);
            }
        }
    };

    var _currentEditor;
    function _toggleEditor(element) {
        _currentEditor = new Editor(element);
    }

    var _currentMenu;
    function _toggleMenu(element) {
        if (_currentMenu) {
            _currentMenu.remove();
        }
        _currentMenu = new Menu(element);
    }

    var _localHighlight;
    var _remoteHighlight;
    var _setup = false;

    /** Event Handlers ***********************************************************/

    function onMouseOver(event) {
        if (!event.metaKey) {
            return;
        }
        _localHighlight.add(event.target, true);
    }

    function onMouseOut(event) {
        if (!event.metaKey) {
            return;
        }
        _localHighlight.clear();
    }

    function onMouseMove(event) {
        onMouseOver(event);
        document.removeEventListener("mousemove", onMouseMove);
    }

    function onClick(event) {
        if (!event.metaKey) {
            return;
        }
        event.preventDefault();
        event.stopPropagation();
        if (event.altKey) {
            _toggleEditor(event.target);
        } else {
            _toggleMenu(event.target);
        }
    }

    function onKeyUp(event) {
        if (_setup && !event.metaKey) {
            document.removeEventListener("keyup", onKeyUp);
            document.removeEventListener("mouseover", onMouseOver);
            document.removeEventListener("mouseout", onMouseOut);
            document.removeEventListener("mousemove", onMouseMove);
            document.removeEventListener("click", onClick);
            _localHighlight.clear();
            _localHighlight = undefined;
            _setup = false;
        }
    }

    function onKeyDown(event) {
        if (!_setup && event.metaKey) {
            document.addEventListener("keyup", onKeyUp);
            document.addEventListener("mouseover", onMouseOver);
            document.addEventListener("mouseout", onMouseOut);
            document.addEventListener("mousemove", onMouseMove);
            document.addEventListener("click", onClick);
            _localHighlight = new Highlight("#ecc", true);
            _setup = true;
        }
    }

    /** Public Commands **********************************************************/

    // keep alive. Called once a second when a Live Development connection is active.
    // If several seconds have passed without this method being called, we can assume
    // that the connection has been severed and we should remove all our code/hooks.
    function keepAlive() {
        lastKeepAliveTime = Date.now();
    }

    // show goto
    function showGoto(targets) {
        if (!_currentMenu) {
            return;
        }
        _currentMenu.createBody();
        var i;
        for (i in targets) {
            _currentMenu.addItem(targets[i]);
        }
        _currentMenu.show();
    }

    // remove active highlights
    function hideHighlight() {
        if (_remoteHighlight) {
            _remoteHighlight.clear();
            _remoteHighlight = null;
        }
    }

    // highlight a node
    function highlight(node, clear) {
        if (!_remoteHighlight) {
            _remoteHighlight = new Highlight("#cfc");
        }
        if (clear) {
            _remoteHighlight.clear();
        }
        _remoteHighlight.add(node, true);
    }

    // highlight a rule
    function highlightRule(rule) {
        hideHighlight();
        var i, nodes = document.querySelectorAll(rule);
        for (i = 0; i < nodes.length; i++) {
            highlight(nodes[i]);
        }
        _remoteHighlight.selector = rule;
    }

    // redraw active highlights
    function redrawHighlights() {
        if (_remoteHighlight) {
            _remoteHighlight.redraw();
        }
    }

    // init
    if (experimental) {
        window.document.addEventListener("keydown", onKeyDown);
    }

    window.addEventListener("resize", redrawHighlights);
    // Add a capture-phase scroll listener to update highlights when
    // any element scrolls.

    function _scrollHandler(e) {
        // Document scrolls can be updated immediately. Any other scrolls
        // need to be updated on a timer to ensure the layout is correct.
        if (e.target === document) {
            redrawHighlights();
        } else {
            if (_remoteHighlight || _localHighlight) {
                window.setTimeout(redrawHighlights, 0);
            }
        }
    }

    window.addEventListener("scroll", _scrollHandler, true);

    var aliveTest = window.setInterval(function () {
        if (Date.now() > lastKeepAliveTime + KEEP_ALIVE_TIMEOUT) {
            // Remove highlights
            hideHighlight();

            // Remove listeners
            window.removeEventListener("resize", redrawHighlights);
            window.removeEventListener("scroll", _scrollHandler, true);

            // Clear this interval
            window.clearInterval(aliveTest);
        }
    }, 1000);

    return {
        "keepAlive": keepAlive,
        "showGoto": showGoto,
        "hideHighlight": hideHighlight,
        "highlight": highlight,
        "highlightRule": highlightRule,
        "redrawHighlights": redrawHighlights
    };
}<commit_msg>bugfix: if a highlight was triggered to Brackets, the trigger must be removed when the highlight is removed<commit_after>/*
 * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, forin: true, maxerr: 50, regexp: true */
/*global define, $, window, document */

/**
 * RemoteFunctions define the functions to be executed in the browser. This
 * modules should define a single function that returns an object of all
 * exported functions.
 */
function RemoteFunctions(experimental) {
    "use strict";

    var lastKeepAliveTime = Date.now();

    var HIGHLIGHT_CLASSNAME = "__brackets-ld-highlight",
        KEEP_ALIVE_TIMEOUT  = 3000;   // Keep alive timeout value, in milliseconds

    // determine the color for a type
    function _typeColor(type, highlight) {
        switch (type) {
        case "html":
            return highlight ? "#eec" : "#ffe";
        case "css":
            return highlight ? "#cee" : "#eff";
        case "js":
            return highlight ? "#ccf" : "#eef";
        default:
            return highlight ? "#ddd" : "#eee";
        }
    }

    // compute the screen offset of an element
    function _screenOffset(element, key) {
        var bounds = element.getBoundingClientRect();
        if (key === "offsetLeft") {
            return bounds.left + window.pageXOffset;
        } else {
            return bounds.top + window.pageYOffset;
        }
    }

    // set an event on a element
    function _trigger(element, name, value, autoRemove) {
        var key = "data-ld-" + name;
        if (value !== undefined && value !== null) {
            element.setAttribute(key, value);
            if (autoRemove) {
                window.setTimeout(element.removeAttribute.bind(element, key));
            }
        } else {
            element.removeAttribute(key);
        }
    }

    // construct the info menu
    function Menu(element) {
        this.element = element;
        _trigger(this.element, "showgoto", 1, true);
        window.setTimeout(window.remoteShowGoto);
        this.remove = this.remove.bind(this);
    }

    Menu.prototype = {
        onClick: function (url, event) {
            event.preventDefault();
            _trigger(this.element, "goto", url, true);
            this.remove();
        },

        createBody: function () {
            if (this.body) {
                return;
            }

            // compute the position on screen
            var x = _screenOffset(this.element, "offsetLeft");
            var y = _screenOffset(this.element, "offsetTop") + this.element.offsetHeight;

            // create the container
            this.body = document.createElement("div");
            this.body.style.setProperty("z-index", 2147483647);
            this.body.style.setProperty("position", "absolute");
            this.body.style.setProperty("left", x + "px");
            this.body.style.setProperty("top", y + "px");
            this.body.style.setProperty("font-size", "11pt");

            // draw the background
            this.body.style.setProperty("background", "#fff");
            this.body.style.setProperty("border", "1px solid #888");
            this.body.style.setProperty("-webkit-box-shadow", "2px 2px 6px 0px #ccc");
            this.body.style.setProperty("border-radius", "6px");
            this.body.style.setProperty("padding", "6px");
        },

        addItem: function (target) {
            var item = document.createElement("div");
            item.style.setProperty("padding", "2px 6px");
            if (this.body.childNodes.length > 0) {
                item.style.setProperty("border-top", "1px solid #ccc");
            }
            item.style.setProperty("cursor", "pointer");
            item.style.setProperty("background", _typeColor(target.type));
            item.innerHTML = target.name;
            item.addEventListener("click", this.onClick.bind(this, target.url));

            if (target.file) {
                var file = document.createElement("i");
                file.style.setProperty("float", "right");
                file.style.setProperty("margin-left", "12px");
                file.innerHTML = " " + target.file;
                item.appendChild(file);
            }
            this.body.appendChild(item);
        },

        show: function () {
            if (!this.body) {
                this.body = this.createBody();
            }
            if (!this.body.parentNode) {
                document.body.appendChild(this.body);
            }
            document.addEventListener("click", this.remove);
        },

        remove: function () {
            if (this.body && this.body.parentNode) {
                document.body.removeChild(this.body);
            }
            document.removeEventListener("click", this.remove);
        }

    };

    function Editor(element) {
        this.onBlur = this.onBlur.bind(this);
        this.onKeyPress = this.onKeyPress.bind(this);

        this.element = element;
        this.element.setAttribute("contenteditable", "true");
        this.element.focus();
        this.element.addEventListener("blur", this.onBlur);
        this.element.addEventListener("keypress", this.onKeyPress);

        this.revertText = this.element.innerHTML;

        _trigger(this.element, "edit", 1);
    }

    Editor.prototype = {
        onBlur: function (event) {
            this.element.removeAttribute("contenteditable");
            this.element.removeEventListener("blur", this.onBlur);
            this.element.removeEventListener("keypress", this.onKeyPress);
            _trigger(this.element, "edit", 0, true);
        },

        onKeyPress: function (event) {
            switch (event.which) {
            case 13: // return
                this.element.blur();
                break;
            case 27: // esc
                this.element.innerHTML = this.revertText;
                this.element.blur();
                break;
            }
        }
    };

    function Highlight(color, trigger) {
        this.color = color;
        this.trigger = !!trigger;
        this.elements = [];
        this.selector = "";
    }

    Highlight.prototype = {
        _elementExists: function (element) {
            var i;
            for (i in this.elements) {
                if (this.elements[i] === element) {
                    return true;
                }
            }
            return false;
        },

        _makeHighlightDiv: function (element, doAnimation) {
            var elementBounds = element.getBoundingClientRect(),
                highlight = window.document.createElement("div"),
                styles = window.getComputedStyle(element);

            highlight.className = HIGHLIGHT_CLASSNAME;

            var stylesToSet = {
                "left": _screenOffset(element, "offsetLeft") + "px",
                "top": _screenOffset(element, "offsetTop") + "px",
                "width": (elementBounds.width - 2) + "px",
                "height": (elementBounds.height - 2) + "px",
                "z-index": 2000000,
                "position": "absolute",
                "pointer-events": "none",
                "border-top-left-radius": styles.borderTopLeftRadius,
                "border-top-right-radius": styles.borderTopRightRadius,
                "border-bottom-left-radius": styles.borderBottomLeftRadius,
                "border-bottom-right-radius": styles.borderBottomRightRadius,
                "border-style": "solid",
                "border-width": "1px",
                "border-color": "rgb(94,167,255)"
            };

            var animateStartValues = {
                "opacity": 0,
                "background": "rgba(94,167,255, 0.5)",
                "box-shadow": "0 0 6px 1px rgba(94,167,255, 0.6), inset 0 0 4px 1px rgba(255,255,255,1)"
            };

            var animateEndValues = {
                "opacity": 1,
                "background": "rgba(94,167,255, 0.1)",
                "box-shadow": "0 0 1px 0 rgba(94,167,255, 0), inset 0 0 4px 1px rgba(255,255,255,0.8)"
            };

            var transitionValues = {
                "-webkit-transition-property": "opacity, box-shadow, background",
                "-webkit-transition-duration": "0.3s, 0.4s, 0.4s",
                "transition-property": "opacity, box-shadow, background",
                "transition-duration": "0.3s, 0.4s, 0.4s"
            };

            function _setStyleValues(styleValues, obj) {
                var prop;

                for (prop in styleValues) {
                    obj.setProperty(prop, styleValues[prop]);
                }
            }

            _setStyleValues(stylesToSet, highlight.style);
            _setStyleValues(
                doAnimation ? animateStartValues : animateEndValues,
                highlight.style
            );

            if (doAnimation) {
                _setStyleValues(transitionValues, highlight.style);

                window.setTimeout(function () {
                    _setStyleValues(animateEndValues, highlight.style);
                }, 0);
            }

            window.document.body.appendChild(highlight);
        },

        add: function (element, doAnimation) {
            if (this._elementExists(element) || element === document) {
                return;
            }
            if (this.trigger) {
                _trigger(element, "highlight", 1);
            }
            this.elements.push(element);

            this._makeHighlightDiv(element, doAnimation);
        },

        clear: function () {
            var i, highlights = window.document.querySelectorAll("." + HIGHLIGHT_CLASSNAME),
                body = window.document.body;

            for (i = 0; i < highlights.length; i++) {
                body.removeChild(highlights[i]);
            }

            if (this.trigger) {
                for (i = 0; i < this.elements.length; i++) {
                    _trigger(this.elements[i], "highlight", 0);
                }
            }

            this.elements = [];
        },

        redraw: function () {
            var i, highlighted;

            // When redrawing a selector-based highlight, run a new selector
            // query to ensure we have the latest set of elements to highlight.
            if (this.selector) {
                highlighted = window.document.querySelectorAll(this.selector);
            } else {
                highlighted = this.elements.slice(0);
            }

            this.clear();
            for (i = 0; i < highlighted.length; i++) {
                this.add(highlighted[i], false);
            }
        }
    };

    var _currentEditor;
    function _toggleEditor(element) {
        _currentEditor = new Editor(element);
    }

    var _currentMenu;
    function _toggleMenu(element) {
        if (_currentMenu) {
            _currentMenu.remove();
        }
        _currentMenu = new Menu(element);
    }

    var _localHighlight;
    var _remoteHighlight;
    var _setup = false;

    /** Event Handlers ***********************************************************/

    function onMouseOver(event) {
        if (!event.metaKey) {
            return;
        }
        _localHighlight.add(event.target, true);
    }

    function onMouseOut(event) {
        if (!event.metaKey) {
            return;
        }
        _localHighlight.clear();
    }

    function onMouseMove(event) {
        onMouseOver(event);
        document.removeEventListener("mousemove", onMouseMove);
    }

    function onClick(event) {
        if (!event.metaKey) {
            return;
        }
        event.preventDefault();
        event.stopPropagation();
        if (event.altKey) {
            _toggleEditor(event.target);
        } else {
            _toggleMenu(event.target);
        }
    }

    function onKeyUp(event) {
        if (_setup && !event.metaKey) {
            document.removeEventListener("keyup", onKeyUp);
            document.removeEventListener("mouseover", onMouseOver);
            document.removeEventListener("mouseout", onMouseOut);
            document.removeEventListener("mousemove", onMouseMove);
            document.removeEventListener("click", onClick);
            _localHighlight.clear();
            _localHighlight = undefined;
            _setup = false;
        }
    }

    function onKeyDown(event) {
        if (!_setup && event.metaKey) {
            document.addEventListener("keyup", onKeyUp);
            document.addEventListener("mouseover", onMouseOver);
            document.addEventListener("mouseout", onMouseOut);
            document.addEventListener("mousemove", onMouseMove);
            document.addEventListener("click", onClick);
            _localHighlight = new Highlight("#ecc", true);
            _setup = true;
        }
    }

    /** Public Commands **********************************************************/

    // keep alive. Called once a second when a Live Development connection is active.
    // If several seconds have passed without this method being called, we can assume
    // that the connection has been severed and we should remove all our code/hooks.
    function keepAlive() {
        lastKeepAliveTime = Date.now();
    }

    // show goto
    function showGoto(targets) {
        if (!_currentMenu) {
            return;
        }
        _currentMenu.createBody();
        var i;
        for (i in targets) {
            _currentMenu.addItem(targets[i]);
        }
        _currentMenu.show();
    }

    // remove active highlights
    function hideHighlight() {
        if (_remoteHighlight) {
            _remoteHighlight.clear();
            _remoteHighlight = null;
        }
    }

    // highlight a node
    function highlight(node, clear) {
        if (!_remoteHighlight) {
            _remoteHighlight = new Highlight("#cfc");
        }
        if (clear) {
            _remoteHighlight.clear();
        }
        _remoteHighlight.add(node, true);
    }

    // highlight a rule
    function highlightRule(rule) {
        hideHighlight();
        var i, nodes = document.querySelectorAll(rule);
        for (i = 0; i < nodes.length; i++) {
            highlight(nodes[i]);
        }
        _remoteHighlight.selector = rule;
    }

    // redraw active highlights
    function redrawHighlights() {
        if (_remoteHighlight) {
            _remoteHighlight.redraw();
        }
    }

    // init
    if (experimental) {
        window.document.addEventListener("keydown", onKeyDown);
    }

    window.addEventListener("resize", redrawHighlights);
    // Add a capture-phase scroll listener to update highlights when
    // any element scrolls.

    function _scrollHandler(e) {
        // Document scrolls can be updated immediately. Any other scrolls
        // need to be updated on a timer to ensure the layout is correct.
        if (e.target === document) {
            redrawHighlights();
        } else {
            if (_remoteHighlight || _localHighlight) {
                window.setTimeout(redrawHighlights, 0);
            }
        }
    }

    window.addEventListener("scroll", _scrollHandler, true);

    var aliveTest = window.setInterval(function () {
        if (Date.now() > lastKeepAliveTime + KEEP_ALIVE_TIMEOUT) {
            // Remove highlights
            hideHighlight();

            // Remove listeners
            window.removeEventListener("resize", redrawHighlights);
            window.removeEventListener("scroll", _scrollHandler, true);

            // Clear this interval
            window.clearInterval(aliveTest);
        }
    }, 1000);

    return {
        "keepAlive": keepAlive,
        "showGoto": showGoto,
        "hideHighlight": hideHighlight,
        "highlight": highlight,
        "highlightRule": highlightRule,
        "redrawHighlights": redrawHighlights
    };
}<|endoftext|>


<commit_before>(function () {

    "use strict";

    /**
     Quick-and-dirty utility for debugging XEO {{#crossLink "Scene"}}Scenes{{/crossLink}}.

     The utility has fluent builder API that lets you create and update simple objects to help you
     debug or demo things on XEO.

     The utility does not clean up any components it created with your {{#crossLink "Scene"}}Scenes{{/crossLink}}.

     ## Example

     Drawing a red triangle:

     ```` javascript
     XEO.debug
     .id("myTriangle")  // Supply an ID when you want to update the line if already existing
     .color([1,0,0])
     .pos([-10, -10, 0])
     .pos([10, -10, 0])
     .pos([0, -4, 0])
     .line();

     ````

     Updating the triangle to change it's color and position:

     ```` javascript
     XEO.debug
     .id("myTriangle")
     .pos([-15, -15, 0])
     .pos([15, -15, 0])
     .pos([0, 5, 0])
     .color([0,1,0])
     .line();

     ````

     Creating a label at a Given World position:

     ```` javascript
     XEO.debug
     .pos([-10, 34, 2])
     .text("Check this out!")
     .label();

     ````
     @class XEO.debug
     @static
     @author xeolabs / http://xeolabs.com/
     */
    XEO.debug = new (function () {

        // Converts XEO color to CSS
        function cssColor(color) {
            return "rgb(" +
                Math.floor(color[0] * 255) + "," +
                Math.floor(color[1] * 255) + "," +
                Math.floor(color[2] * 255) + ")";
        }

        var scene;
        var id;
        var color;
        var fillColor;
        var opacity;
        var lineWidth;
        var diffuse;
        var pos;
        var posi;
        var text;
        var radius;

        this.scene = function (_scene) {
            scene = _scene;
            return this;
        };

        function getScene() {
            return scene || XEO.scene;
        }

        this.id = function (value) {
            id = value;
            return this;
        };

        this.color = function (value) {
            color = value;
            return this;
        };

        this.fillColor = function (value) {
            fillColor = value;
            return this;
        };

        this.lineWidth = function (value) {
            lineWidth = value;
            return this;
        };

        this.pos = function (value) {
            pos[posi++] = value;
            return this;
        };

        this.text = function (value) {
            text = value;
            return this;
        };

        this.radius = function (value) {
            radius = value;
            return this;
        };

        this._reset = function () {
            scene = undefined;
            color = [1, 0.4, 0.4];
            fillColor = [0, 0, 0];
            diffuse = [1, 0.4, 0.4];
            opacity = 1.0;
            lineWidth = 2.0;
            id = undefined;
            pos = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
            posi = 0;
            text = "";
            radius = 1.0;
        };

        this.line = function () {

            if (posi < 2) {
                console.error("[XEO.debug.line] Not enough calls to XEO.debug.pos() for XEO.debug.line() - need at least two.");
                return;
            }

            var _id = id || "__debugLine";

            var positions = [];
            var indices = [];

            for (var i = 0; i < posi; i++) {
                positions.push(pos[i][0]);
                positions.push(pos[i][1]);
                positions.push(pos[i][2]);

                indices.push(i);
                if (i < (posi - 1)) {
                    indices.push(i + 1);
                }
            }

            var object = getScene().objects[_id];

            if (!object) {
                new XEO.GameObject(getScene(), {
                    id: _id,
                    geometry: new XEO.Geometry({
                        primitive: "lines",
                        positions: positions,
                        indices: indices
                    }),
                    material: new XEO.PhongMaterial({
                        emissive: color,
                        opacity: opacity,
                        lineWidth: lineWidth
                    }),
                    modes: new XEO.Modes({  // This GameObject should not be pickable
                        picking: false,
                        transparent: opacity < 1.0
                    })
                });
            } else {
                object.geometry.positions = positions;
                object.geometry.indices = indices;
                object.material.emissive = color;
                object.material.opacity = opacity;
                object.modes.transparency = opacity < 1.0;
                object.material.lineWidth = lineWidth;
            }

            this._reset();

            return this;
        };

        /**
         * Creates or updates a floating CSS label
         *
         * @returns {XEO.debug}
         */
        this.label = function () {

            var _id = id || "__debugLabel";

            var object = getScene().objects[_id];

            if (!object) {

                object = new XEO.GameObject(getScene(), {
                    id: _id,
                    transform: new XEO.Translate({
                        xyz: pos[0]
                    }),
                    geometry: new XEO.SphereGeometry({
                        radius: 0.1
                    }),
                    modes: new XEO.Modes({  // This GameObject should not be pickable
                        picking: false,
                        transparent: true
                    }),
                    material: new XEO.PhongMaterial({ // Hides the sphere while still rendering it
                        opacity: 0
                    })
                });

                var body = document.getElementsByTagName("body")[0];

                var boxDiv = document.createElement('div');
                boxDiv.innerText = text;
                var style = boxDiv.style;
                style.color = cssColor(color);
                style.position = "absolute";
                style.padding = "10px";
                style.margin = "0";
                style.background = fillColor ? cssColor(fillColor) : "black";
                style.opacity = opacity;
                style.border = lineWidth + "px solid " + cssColor(color);
                style["z-index"] = "1000";
                style.width = "auto";
                style.height = "auto";
                style["border-radius"] = "5px";
                style.font = "bold 12px arial,serif";
                body.appendChild(boxDiv);

                var pointDiv = document.createElement('div');
                style = pointDiv.style;
                style.color = "white";
                style.background = "white";
                style.position = "absolute";
                style.padding = "3px";
                style.margin = "0";
                style.background = "white";
                style.opacity = 1.0;
                style.border = lineWidth + "px solid " + cssColor(color);
                style.width = "2px";
                style.height = "2px";
                style["border-radius"] = "5px";
                style["z-index"] = "1001";
                body.appendChild(pointDiv);

                object.canvasBoundary.on("updated",
                    function () {

                        var center = object.canvasBoundary.center;

                        boxDiv.style.left = center[0] - 3 + "px";
                        boxDiv.style.top = center[1] - 3 + "px";

                        pointDiv.style.left = center[0] - 5 + "px";
                        pointDiv.style.top = center[1] - 5 + "px";

                        var zIndex = 10000 + Math.floor(object.viewBoundary.center[2]);

                        boxDiv.style["z-index"] = zIndex;
                        pointDiv.style["z-index"] = zIndex + 1;
                    });

                object.boxDiv = boxDiv; // Dirty, but all is encapsulated by the debug utility
                object.pointDiv = boxDiv;

            } else {
                object.transform.xyz = pos[0];

                object.boxDiv.innerText = text;
                object.boxDiv.style.opacity = opacity;
                object.boxDiv.style.background = cssColor(fillColor);
                object.boxDiv.style.color = cssColor(color);

                var border = lineWidth + "px solid " + cssColor(color);
                object.boxDiv.style.border = border;
                object.pointDiv.style.border = border;
            }

            this._reset();

            return this;
        };

        this.label3d = function () {

            var _id = id || "__debugLabel3d";

            var object = getScene().objects[_id];

            if (!object) {

                object = new XEO.GameObject(getScene(), {
                    id: _id,
                    transform: new XEO.Translate({
                        xyz: pos[0]
                    }),
                    geometry: new XEO.VectorTextGeometry({
                        text: text
                    }),
                    modes: new XEO.Modes({  // This GameObject should not be pickable
                        picking: false,
                        transparent: true
                    }),
                    material: new XEO.PhongMaterial({ // Hides the sphere while still rendering it
                        emissive: color,
                        opacity: opacity,
                        lineWidth: lineWidth
                    }),
                    billboard: new XEO.Billboard({
                        spherical: true
                    })
                });

            } else {
                object.transform.xyz = pos[0];
                object.geometry.text = text;
                object.material.emissive = color;
                object.material.opacity = opacity;
                object.modes.transparency = opacity < 1.0;
                object.material.lineWidth = lineWidth;
            }

            this._reset();

            return this;
        };

        this._reset();
    })();

})();
<commit_msg>Debug utility additions<commit_after>(function () {

    "use strict";

    /**
     Quick-and-dirty utility for debugging XEO {{#crossLink "Scene"}}Scenes{{/crossLink}}.

     The utility has fluent builder API that lets you create and update simple objects to help you
     debug or demo things on XEO.

     The utility does not clean up any components it created with your {{#crossLink "Scene"}}Scenes{{/crossLink}}.

     ## Example

     Drawing a red triangle:

     ```` javascript
     XEO.debug
     .id("myTriangle")  // Supply an ID when you want to update the line if already existing
     .color([1,0,0])
     .pos([-10, -10, 0])
     .pos([10, -10, 0])
     .pos([0, -4, 0])
     .line();

     ````

     Updating the triangle to change it's color and position:

     ```` javascript
     XEO.debug
     .id("myTriangle")
     .pos([-15, -15, 0])
     .pos([15, -15, 0])
     .pos([0, 5, 0])
     .color([0,1,0])
     .line();

     ````

     Creating a label at a Given World position:

     ```` javascript
     XEO.debug
     .pos([-10, 34, 2])
     .text("Check this out!")
     .label();

     ````
     @class XEO.debug
     @static
     @author xeolabs / http://xeolabs.com/
     */
    XEO.debug = new (function () {

        // Converts XEO color to CSS
        function cssColor(color) {
            return "rgb(" +
                Math.floor(color[0] * 255) + "," +
                Math.floor(color[1] * 255) + "," +
                Math.floor(color[2] * 255) + ")";
        }

        var scene;
        var id;
        var color;
        var fillColor;
        var opacity;
        var lineWidth;
        var diffuse;
        var pos;
        var posi;
        var text;
        var radius;

        this.scene = function (_scene) {
            scene = _scene;
            return this;
        };

        function getScene() {
            return scene || XEO.scene;
        }

        this.id = function (value) {
            id = value;
            return this;
        };

        this.color = function (value) {
            color = value;
            return this;
        };

        this.fillColor = function (value) {
            fillColor = value;
            return this;
        };

        this.opacity = function (value) {
            opacity = value;
            return this;
        };

        this.lineWidth = function (value) {
            lineWidth = value;
            return this;
        };

        this.pos = function (value) {
            pos[posi++] = value;
            return this;
        };

        this.text = function (value) {
            text = value;
            return this;
        };

        this.radius = function (value) {
            radius = value;
            return this;
        };

        this._reset = function () {
            scene = undefined;
            color = [1, 0.4, 0.4];
            fillColor = [0, 0, 0];
            diffuse = [1, 0.4, 0.4];
            opacity = 1.0;
            lineWidth = 2.0;
            id = undefined;
            pos = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
            posi = 0;
            text = "";
            radius = 1.0;
        };

        this.line = function () {

            if (posi < 2) {
                console.error("[XEO.debug.line] Not enough calls to XEO.debug.pos() for XEO.debug.line() - need at least two.");
                return;
            }

            var _id = id || "__debugLine";

            var positions = [];
            var indices = [];

            for (var i = 0; i < posi; i++) {
                positions.push(pos[i][0]);
                positions.push(pos[i][1]);
                positions.push(pos[i][2]);

                indices.push(i);
                if (i < (posi - 1)) {
                    indices.push(i + 1);
                }
            }

            var object = getScene().objects[_id];

            if (!object) {
                new XEO.GameObject(getScene(), {
                    id: _id,
                    geometry: new XEO.Geometry({
                        primitive: "lines",
                        positions: positions,
                        indices: indices
                    }),
                    material: new XEO.PhongMaterial({
                        emissive: color,
                        opacity: opacity,
                        lineWidth: lineWidth
                    }),
                    modes: new XEO.Modes({  // This GameObject should not be pickable
                        picking: false,
                        transparent: opacity < 1.0
                    })
                });
            } else {
                object.geometry.positions = positions;
                object.geometry.indices = indices;
                object.material.emissive = color;
                object.material.opacity = opacity;
                object.modes.transparency = opacity < 1.0;
                object.material.lineWidth = lineWidth;
            }

            this._reset();

            return this;
        };

        this.label = function () {

            var _id = id || "__debugLabel";

            var object = getScene().objects[_id];

            if (!object) {

                object = new XEO.GameObject(getScene(), {
                    id: _id,
                    transform: new XEO.Translate({
                        xyz: pos[0]
                    }),
                    geometry: new XEO.SphereGeometry({
                        radius: 0.1
                    }),
                    modes: new XEO.Modes({  // This GameObject should not be pickable
                        picking: false,
                        transparent: true
                    }),
                    material: new XEO.PhongMaterial({ // Hides the sphere while still rendering it
                        opacity: 0
                    })
                });

                var body = document.getElementsByTagName("body")[0];

                var boxDiv = document.createElement('div');
                boxDiv.innerText = text;
                var style = boxDiv.style;
                style.color = cssColor(color);
                style.position = "absolute";
                style.padding = "10px";
                style.margin = "0";
                style.background = fillColor ? cssColor(fillColor) : "black";
                style.opacity = opacity;
                style.border = lineWidth + "px solid " + cssColor(color);
                style["z-index"] = "1000";
                style.width = "auto";
                style.height = "auto";
                style["border-radius"] = "5px";
                style.font = "bold 12px arial,serif";
                body.appendChild(boxDiv);

                var pointDiv = document.createElement('div');
                style = pointDiv.style;
                style.color = "white";
                style.background = "white";
                style.position = "absolute";
                style.padding = "3px";
                style.margin = "0";
                style.background = "white";
                style.opacity = 1.0;
                style.border = lineWidth + "px solid " + cssColor(color);
                style.width = "2px";
                style.height = "2px";
                style["border-radius"] = "5px";
                style["z-index"] = "1001";
                body.appendChild(pointDiv);

                object.canvasBoundary.on("updated",
                    function () {

                        var center = object.canvasBoundary.center;

                        boxDiv.style.left = center[0] - 3 + "px";
                        boxDiv.style.top = center[1] - 3 + "px";

                        pointDiv.style.left = center[0] - 5 + "px";
                        pointDiv.style.top = center[1] - 5 + "px";

                        var zIndex = 10000 + Math.floor(object.viewBoundary.center[2]);

                        boxDiv.style["z-index"] = zIndex;
                        pointDiv.style["z-index"] = zIndex + 1;
                    });

                object.boxDiv = boxDiv; // Dirty, but all is encapsulated by the debug utility
                object.pointDiv = boxDiv;

            } else {
                object.transform.xyz = pos[0];

                object.boxDiv.innerText = text;
                object.boxDiv.style.opacity = opacity;
                object.boxDiv.style.background = cssColor(fillColor);
                object.boxDiv.style.color = cssColor(color);

                var border = lineWidth + "px solid " + cssColor(color);
                object.boxDiv.style.border = border;
                object.pointDiv.style.border = border;
            }

            this._reset();

            return this;
        };

        this.sphere = function () {

            var _id = id || "__debugSphere";

            var object = getScene().objects[_id];

            if (!object) {

                object = new XEO.GameObject(getScene(), {
                    id: _id,
                    transform: new XEO.Translate({
                        xyz: pos[0]
                    }),
                    geometry: new XEO.SphereGeometry({
                        radius: radius
                    }),
                    modes: new XEO.Modes({  // This GameObject should not be pickable
                        picking: false,
                        transparent: opacity < 1.0,
                        backfaces: false
                    }),
                    material: new XEO.PhongMaterial({ // Hides the sphere while still rendering it
                        diffuse: color,
                        emissive: color,
                        opacity: opacity,
                        specular: [1,1,1]
                    })
                });

            } else {
                object.transform.xyz = pos[0];
                object.material.color = color;
                object.material.emissive = color;
                object.material.opacity = opacity;
                object.modes.transparency = opacity < 1.0;
            }

            this._reset();

            return this;
        };

        //---------------------------
        // Work in progress
        //---------------------------
        this.label3d = function () {

            var _id = id || "__debugLabel3d";

            var object = getScene().objects[_id];

            if (!object) {

                object = new XEO.GameObject(getScene(), {
                    id: _id,
                    transform: new XEO.Translate({
                        xyz: pos[0]
                    }),
                    geometry: new XEO.VectorTextGeometry({
                        text: text
                    }),
                    modes: new XEO.Modes({  // This GameObject should not be pickable
                        picking: false,
                        transparent: true
                    }),
                    material: new XEO.PhongMaterial({ // Hides the sphere while still rendering it
                        emissive: color,
                        opacity: opacity,
                        lineWidth: lineWidth
                    }),
                    billboard: new XEO.Billboard({
                        spherical: true
                    })
                });

            } else {
                object.transform.xyz = pos[0];
                object.geometry.text = text;
                object.material.emissive = color;
                object.material.opacity = opacity;
                object.modes.transparency = opacity < 1.0;
                object.material.lineWidth = lineWidth;
            }

            this._reset();

            return this;
        };

        this._reset();
    })();

})();
<|endoftext|>


<commit_before>
/* Dasca, an idle game by @CylonicRaider (github.com/CylonicRaider/dasca)
 * Abstract engine for JS-based idle games */

'use strict';

/* Construct a new clock
 * source is a function that, when called, returns the current time; scale
 * and offset modify source's output in a linear fashion: the reading of
 * source is multiplied by scale and offset is added to that to obtain the
 * current time. If scale is undefined or null, it defaults to 1; if offset
 * is null, it is computed such that the clock starts counting from zero. */
function Clock(source, scale, offset) {
  if (scale == null) scale = 1.0;
  if (offset == null) offset = -source() * scale;
  this.source = source;
  this.scale = scale;
  this.offset = offset;
}

Clock.prototype = {
  /* Sample the current time */
  now: function() {
    return this.source() * this.scale + this.offset;
  },

  /* Construct a new clock from this one, applying the given transformation
   * The new clock derives its time from the same (!) source as this one,
   * but its scale and offset are modified to simulate a clock constructed
   * like
   *     new Clock(this, scale, offset);
   */
  derive: function(scale, offset) {
    if (scale == null) scale = 1.0;
    if (offset != null) offset = this.offset * scale + offset;
    var ret = new Clock(this.source, this.scale * scale, offset);
    if (this._realTime) ret._realTime = true;
    return ret;
  },

  /* Serialization boilerplate */
  constructor: Clock
};

/* Construct a clock that returns (optionally scaled) real time
 * The clock counts from zero */
Clock.realTime = function(scale, start) {
  if (scale == null) scale = 1.0;
  scale *= 1e-3;
  var offset = (start == null) ? null : start - performance.now() * scale;
  var ret = new Clock(performance.now.bind(performance), scale, offset);
  ret._realTime = true;
  return ret;
};

/* Seralize a clock */
Clock.__save__ = function(clock) {
  if (! clock._realTime) throw new Error("Clock not serializable!");
  return {scale: clock.scale * 1e3, time: clock.now()};
};

/* Deserialize a clock */
Clock.__restore__ = function(clock) {
  return Clock.realTime(clock.scale, clock.time);
};

/* Serialize an object tree to JSON, storing type information */
function serialize(obj) {
  return JSON.stringify(obj, function(name, value) {
    /* Fail verbosely */
    if (typeof value == "function")
      throw new Error("Cannot serialize function");
    /* Only transform object values */
    if (typeof value != "object" || Array.isArray(value)) return value;
    /* Get a meaningful constructor name */
    var cons = value.constructor.__sername__;
    if (! cons) cons = value.constructor.name;
    if (! cons) cons = Object.prototype.toString(value).slice(8, -1);
    if (cons == "Object") cons = undefined;
    /* Copy properties into new object, or let object serialize itself */
    var ret;
    if (value.constructor.__save__) {
      ret = value.constructor.__save__(value);
    } else {
      ret = {};
      for (var prop in value) ret[prop] = value[prop];
    }
    /* Add __type__ */
    ret.__type__ = cons;
    /* Done */
    return ret;
  });
}

/* Deserialize a JSON string into an object structure */
function deserialize(obj) {
  return JSON.parse(obj, function(name, value) {
    /* Ignore non-objects */
    if (typeof value != "object" || Array.isArray(value)) return value;
    /* Check for a __type__ */
    if (value.__type__) {
      /* Obtain type object */
      var type = window[value.__type__];
      if (type && type.__restore__) {
        /* Use restorer function */
        value = type.__restore__(value);
      } else if (type) {
        /* Assume an object is deserializable as-is */
        var newVal = Object.create(type.prototype);
        for (var k in value) if (! /^__.+__$/.test(k)) newVal[k] = value[k];
        value = newVal;
      } else {
        /* Nope */
        throw new Error("Object not deserializable (cannot find type): " +
                        JSON.stringify(value));
      }
    }
    return value;
  });
}
<commit_msg>Update documentation<commit_after>
/* Dasca, an idle game by @CylonicRaider (github.com/CylonicRaider/dasca)
 * Abstract engine for JS-based idle games */

'use strict';

/* *** Clock ***
 * An object allowing to sample "time" (as defined by an external source)
 * with a linear transform in place. */

/* Construct a new clock
 * source is a function that, when called, returns the current time; scale
 * and offset modify source's output in a linear fashion: the reading of
 * source is multiplied by scale and offset is added to that to obtain the
 * current time. If scale is undefined or null, it defaults to 1; if offset
 * is null, it is computed such that the clock starts counting from zero. */
function Clock(source, scale, offset) {
  if (scale == null) scale = 1.0;
  if (offset == null) offset = -source() * scale;
  this.source = source;
  this.scale = scale;
  this.offset = offset;
}

Clock.prototype = {
  /* Sample the current time */
  now: function() {
    return this.source() * this.scale + this.offset;
  },

  /* Construct a new clock from this one, applying the given transformation
   * The new clock derives its time from the same (!) source as this one,
   * but its scale and offset are modified to simulate a clock constructed
   * like
   *     new Clock(this, scale, offset);
   */
  derive: function(scale, offset) {
    if (scale == null) scale = 1.0;
    if (offset != null) offset = this.offset * scale + offset;
    var ret = new Clock(this.source, this.scale * scale, offset);
    if (this._realTime) ret._realTime = true;
    return ret;
  },

  /* Serialization boilerplate */
  constructor: Clock
};

/* Construct a clock that returns (optionally scaled) real time
 * The clock counts from zero */
Clock.realTime = function(scale, start) {
  if (scale == null) scale = 1.0;
  scale *= 1e-3;
  var offset = (start == null) ? null : start - performance.now() * scale;
  var ret = new Clock(performance.now.bind(performance), scale, offset);
  ret._realTime = true;
  return ret;
};

/* Seralize a clock */
Clock.__save__ = function(clock) {
  if (! clock._realTime) throw new Error("Clock not serializable!");
  return {scale: clock.scale * 1e3, time: clock.now()};
};

/* Deserialize a clock */
Clock.__restore__ = function(data) {
  return Clock.realTime(data.scale, data.time);
};

/* *** Serialization ***
 * Serializes object trees (!) into JSON strings, allowing reified objects to
 * be of the correct type, to hook their (de)serialization process.
 * Input containing enumerable function properties is rejected (since those
 * are silently swallowed by JSON); use hooks to meaningfully handle them. */

/* Serialize an object tree to JSON, storing type information */
function serialize(obj) {
  return JSON.stringify(obj, function(name, value) {
    /* Fail verbosely */
    if (typeof value == "function")
      throw new Error("Cannot serialize function");
    /* Only transform object values */
    if (typeof value != "object" || Array.isArray(value)) return value;
    /* Get a meaningful constructor name */
    var cons = value.constructor.__sername__;
    if (! cons) cons = value.constructor.name;
    if (! cons) cons = Object.prototype.toString(value).slice(8, -1);
    if (cons == "Object") cons = undefined;
    /* Copy properties into new object, or let object serialize itself */
    var ret;
    if (value.constructor.__save__) {
      ret = value.constructor.__save__(value);
    } else {
      ret = {};
      for (var prop in value) ret[prop] = value[prop];
    }
    /* Add __type__ */
    ret.__type__ = cons;
    /* Done */
    return ret;
  });
}

/* Deserialize a JSON string into an object structure */
function deserialize(obj) {
  return JSON.parse(obj, function(name, value) {
    /* Ignore non-objects */
    if (typeof value != "object" || Array.isArray(value)) return value;
    /* Check for a __type__ */
    if (value.__type__) {
      /* Obtain type object */
      var type = window[value.__type__];
      if (type && type.__restore__) {
        /* Use restorer function */
        value = type.__restore__(value);
      } else if (type) {
        /* Assume an object is deserializable as-is */
        var newVal = Object.create(type.prototype);
        for (var k in value) if (! /^__.+__$/.test(k)) newVal[k] = value[k];
        value = newVal;
      } else {
        /* Nope */
        throw new Error("Object not deserializable (cannot find type): " +
                        JSON.stringify(value));
      }
    }
    return value;
  });
}
<|endoftext|>


<commit_before>var userid;
//arrays gebruikt voor autocompletes en selecteren waarde hiervan.
var studentLists = [];
var studentListsid = [];
var teachers = []
var teachersid = []

function pageViewModel(gvm) {
    gvm.projecttitle = ko.observable("");
    gvm.userId = -1;
    gvm.coupledCount = 0;

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);

    gvm.addBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AddBtn")}, gvm);

    // The table data observable array
    gvm.tabledata = ko.observableArray([]);

    // Add data to the table
    gvm.addTableData = function(studid, userid, studlist, name) {
        // Push data
        var tblOject = {tid: studid + "-" + userid, tstudlist: studlist, tteacher: name};
        gvm.tabledata.push(tblOject);

        // Attach delete handler to delete button
        $('#removebtn-' + studid + "-" + userid).bind('click', function(event, data){
            // Delete the table item
            deleteTableItem(studid + "-" + userid, tblOject);
            event.stopPropagation();
        });
            }

    gvm.clearTable = function() {
        gvm.tabledata.removeAll();
    }

 }

 function getAllTeachers() {
     teachers = [];
     teachersid = [];
     $.getJSON('/api/getteacherrapport', function(data) {
        $.each(data, function(i, item) {
            teachers.push(item.firstname + " " + item.lastname);
            teachersid.push(item.id);
        });
    });
    return teachers;
 }

function getAllStudentLists() {
    studentLists = [];
    studentListsid = [];
    $.getJSON('/api/studentlistsrapporten/' + userid, function (data) {
        $.each(data, function (i, item) {
            studentLists.push(item.name);
            studentListsid.push(item.id);
        });
    });
    return studentLists;
}

function getTeacherid() {

    // functie voor het opsplitsen van naam indien gewenst.
    // console.log(getTeacherID($('#teachersComplete').val().substr(0,$('#teachersComplete').val().indexOf(' ')), $('#teachersComplete').val().substr($('#teachersComplete').val().indexOf(' ')+1)));

    var i = 0;
    var teacher = 0;
    teachers.forEach(function(entry) {
        if (new String(entry).valueOf() == new String($('#teachersComplete').val()).valueOf()) {
            teacher = teachersid[i];
        }
        i+= 1;
    });
    return teacher
}

function getGroupid() {
    var i = 0;
    var studlijst;
    studentLists.forEach(function(entry) {
        if (new String(entry).valueOf() == new String($('#studentListComplete').val()).valueOf()) {
            studlijst = (studentListsid[i]);
        }
        i+= 1;
    });
    return studlijst;
}

 function addGroup(courseid, teacherid, studlijstid) {
     //TODO if teacher or studlijst = 0 dan bestaat deze niet!
     //TODO momenteel niet mogelijk om meer als 1 maal zelfde velden in te voeren maar geen foutboodschap

         $.ajax({
            url: "/api/coursecouple/" + courseid + "/" + studlijstid + "/" + teacherid,
             type: "POST",
             data: {'course': courseid, 'teacher': teacherid, 'studentlist': teacherid},
             success: function(data) {
                 loadTablePage(1,courseid);
                 //callback(true);
             },
             error: function(data) {
                 console.log('Failed to add new student');
                 //callback(false);
             }
         });
 }

/*
 * Load page of the table
 */
function loadTablePage(pagenr,course)
{
    $.getJSON('/api/getStudentGroupTeacherByCourseID/page/' + pagenr + '/' + course, function(data){

        /* Clear current table page */
        viewModel.clearTable();

        // Load table data
        $.each(data.data, function(i, item) {

           viewModel.addTableData(item.studid, item.userid , item.name , item.firstname + " " + item.lastname, item.id);

        });

        //TODO pagers doen werken
        //Momenteel wordt enkel alles geselecteerd met LIMIT 0,20
        //Maar de pagers zelf blijven dissabled waardoor het ook niet mogelijk is LIMIT 21,40 op te vragen.
        /* Let previous en next buttons work */

        if(data.prev == "none"){
            $('#pager-prev-btn').addClass('disabled');
        } else {
            $('#pager-prev-btn').removeClass('disabled');
            $('#pager-prev-btn a').click(function(){
                loadTablePage(data.prev);
            });
        }

        if (data.next == "none"){
            $('#pager-next-btn').addClass('disabled');
        } else {
            $('#pager-next-btn').removeClass('disabled');
            $('#pager-next-btn a').click(function(){
                loadTablePage(data.next);
            });
        }

        // Number of pager buttons
        var numItems = $('.pager-nr-btn').length;

        /* Calculate for the pager buttons */
        var lowPage = Math.floor(pagenr/numItems) + 1;

        $('.pager-nr-btn').each(function() {
            /* calculate current page number */
            var thispagenr = lowPage++;

            /* Add the page number */
            $(this).html('' + thispagenr + '');

            /* Add active class to current page */
            if(thispagenr == pagenr) {
                $(this).addClass('active');
            } else {
                $(this).removeClass('active');
            }

            /* Disable inactive classes and bind handlers to active classes */
            if(thispagenr > data.pagecount) {
                $(this).addClass('disabled');
            } else {
                /* Add click listener for button */
                $(this).click(function() {
                    loadTablePage(thispagenr, course);
                });
            }
        });
    });
}

/*
 * Delete item from table given the id.
 */
function deleteTableItem(id, tblOject) {
    showYesNoModal("Bent u zeker dat u dit item wil verwijderen? \r\n Let op: verwijderde items blijven in het systeem en kunnen weer actief gezet worden door een administrator. \r\n Gelieve de administrator te contacteren om een vak definitief te verwijderen.", function(val){
        if(val){
            //courseid = $('#projectHeader').attr("data-value");
            //studielijstid = "studid " + id.substr(0,id.indexOf('-'));
            //teacherid = "userid " + id.substr(id.indexOf('-')+1);

             $.ajax({
                url: "/api/setInactiveCourseStudlistCouple/" + $('#projectHeader').attr("data-value") + '/' + id.substr(0,id.indexOf('-')) + '/' + id.substr(id.indexOf('-')+1),
                type: "DELETE",
                success: function() {
                   viewModel.tabledata.remove(tblOject);
                }
             });

        }
    });
}

function initPage() {
    $('#addGroupForm').hide();

    $('#addCoursemembers').click(function() {
        $("#addGroupForm").show();
        $('#teachersComplete').autocomplete({ source: getAllTeachers() });
        $('#studentListComplete').autocomplete({ source: getAllStudentLists() });
    });

    $('#addGroupBtn').click(function() {
         addGroup($('#projectHeader').attr("data-value"), getTeacherid(), getGroupid());

        $('#studentListComplete').val("");
        $('#teachersComplete').val("");

        loadTablePage(1,$('#projectHeader').attr("data-value"));

        $('addGroupForm').hide();
    });

    $.getJSON('/api/currentuser', function(data) {
        viewModel.userId = data.id;
        userid = data.id;
    });
    loadTablePage(1,$('#projectHeader').attr("data-value"));
}
<commit_msg>manageStudentPage Maken students ophalen<commit_after>var userid;
//arrays gebruikt voor autocompletes en selecteren waarde hiervan.
var studentLists = [];
var studentListsid = [];
var teachers = []
var teachersid = []

function pageViewModel(gvm) {
    gvm.projecttitle = ko.observable("");
    gvm.userId = -1;
    gvm.coupledCount = 0;

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);

    gvm.addBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AddBtn")}, gvm);

    // The table data observable array
    gvm.tabledata = ko.observableArray([]);

    // Add data to the table
    gvm.addTableData = function(studid, userid, studlist, name) {
        // Push data
        var tblOject = {tid: studid + "-" + userid, tstudlist: studlist, tteacher: name};
        gvm.tabledata.push(tblOject);

        // Attach delete handler to delete button
        $('#removebtn-' + studid + "-" + userid).bind('click', function(event, data){
            // Delete the table item
            deleteTableItem(studid + "-" + userid, tblOject);
            event.stopPropagation();
        });
            }

    gvm.clearTable = function() {
        gvm.tabledata.removeAll();
    }

 }

 function getAllTeachers() {
     teachers = [];
     teachersid = [];
     $.getJSON('/api/getteacherrapport', function(data) {
        $.each(data, function(i, item) {
            teachers.push(item.firstname + " " + item.lastname);
            teachersid.push(item.id);
        });
    });
    return teachers;
 }

function getAllStudentLists() {
    studentLists = [];
    studentListsid = [];
    $.getJSON('/api/studentlistsrapporten/' + userid, function (data) {
        $.each(data, function (i, item) {
            studentLists.push(item.name);
            studentListsid.push(item.id);
        });
    });
    return studentLists;
}

function getTeacherid() {

    // functie voor het opsplitsen van naam indien gewenst.
    // console.log(getTeacherID($('#teachersComplete').val().substr(0,$('#teachersComplete').val().indexOf(' ')), $('#teachersComplete').val().substr($('#teachersComplete').val().indexOf(' ')+1)));

    var i = 0;
    var teacher = 0;
    teachers.forEach(function(entry) {
        if (new String(entry).valueOf() == new String($('#teachersComplete').val()).valueOf()) {
            teacher = teachersid[i];
        }
        i+= 1;
    });
    return teacher
}

function getGroupid() {
    var i = 0;
    var studlijst;
    studentLists.forEach(function(entry) {
        if (new String(entry).valueOf() == new String($('#studentListComplete').val()).valueOf()) {
            studlijst = (studentListsid[i]);
        }
        i+= 1;
    });
    return studlijst;
}

 function addGroup(courseid, teacherid, studlijstid) {
     //TODO if teacher or studlijst = 0 dan bestaat deze niet!
     //TODO momenteel niet mogelijk om meer als 1 maal zelfde velden in te voeren maar geen foutboodschap

         $.ajax({
            url: "/api/coursecouple/" + courseid + "/" + studlijstid + "/" + teacherid,
             type: "POST",
             data: {'course': courseid, 'teacher': teacherid, 'studentlist': teacherid},
             success: function(data) {
                 loadTablePage(1,courseid);
                 //callback(true);
             },
             error: function(data) {
                 console.log('Failed to add new student');
                 //callback(false);
             }
         });
 }

/*
 * Load page of the table
 */
function loadTablePage(pagenr,course)
{
    $.getJSON('/api/getStudentGroupTeacherByCourseID/page/' + pagenr + '/' + course, function(data){

        /* Clear current table page */
        viewModel.clearTable();

        // Load table data
        $.each(data.data, function(i, item) {

           viewModel.addTableData(item.studid, item.userid , item.name , item.firstname + " " + item.lastname, item.id);

        });

        //TODO pagers doen werken
        //Momenteel wordt enkel alles geselecteerd met LIMIT 0,20
        //Maar de pagers zelf blijven dissabled waardoor het ook niet mogelijk is LIMIT 21,40 op te vragen.
        /* Let previous en next buttons work */

        if(data.prev == "none"){
            $('#pager-prev-btn').addClass('disabled');
        } else {
            $('#pager-prev-btn').removeClass('disabled');
            $('#pager-prev-btn a').click(function(){
                loadTablePage(data.prev);
            });
        }

        if (data.next == "none"){
            $('#pager-next-btn').addClass('disabled');
        } else {
            $('#pager-next-btn').removeClass('disabled');
            $('#pager-next-btn a').click(function(){
                loadTablePage(data.next);
            });
        }

        // Number of pager buttons
        var numItems = $('.pager-nr-btn').length;

        /* Calculate for the pager buttons */
        var lowPage = Math.floor(pagenr/numItems) + 1;

        $('.pager-nr-btn').each(function() {
            /* calculate current page number */
            var thispagenr = lowPage++;

            /* Add the page number */
            $(this).html('' + thispagenr + '');

            /* Add active class to current page */
            if(thispagenr == pagenr) {
                $(this).addClass('active');
            } else {
                $(this).removeClass('active');
            }

            /* Disable inactive classes and bind handlers to active classes */
            if(thispagenr > data.pagecount) {
                $(this).addClass('disabled');
            } else {
                /* Add click listener for button */
                $(this).click(function() {
                    loadTablePage(thispagenr, course);
                });
            }
        });
    });
}

/*
 * Delete item from table given the id.
 */
function deleteTableItem(id, tblOject) {
    showYesNoModal("Bent u zeker dat u dit item wil verwijderen? \r\n Let op: verwijderde items blijven in het systeem en kunnen weer actief gezet worden door een administrator. \r\n Gelieve de administrator te contacteren om een vak definitief te verwijderen.", function(val){
        if(val){
            //courseid = $('#projectHeader').attr("data-value");
            //studielijstid = "studid " + id.substr(0,id.indexOf('-'));
            //teacherid = "userid " + id.substr(id.indexOf('-')+1);

             $.ajax({
                url: "/api/setInactiveCourseStudlistCouple/" + $('#projectHeader').attr("data-value") + '/' + id.substr(0,id.indexOf('-')) + '/' + id.substr(id.indexOf('-')+1),
                type: "DELETE",
                success: function() {
                   viewModel.tabledata.remove(tblOject);
                }
             });

        }
    });
}

function initPage() {
    console.log("initpage");
    $('#addGroupForm').hide();

    $('#addCoursemembers').click(function() {
        $("#addGroupForm").show();
        $('#teachersComplete').autocomplete({ source: getAllTeachers() });
        $('#studentListComplete').autocomplete({ source: getAllStudentLists() });
    });

    $('#addGroupBtn').click(function() {
         addGroup($('#projectHeader').attr("data-value"), getTeacherid(), getGroupid());

        $('#studentListComplete').val("");
        $('#teachersComplete').val("");

        loadTablePage(1,$('#projectHeader').attr("data-value"));

        $('addGroupForm').hide();
    });

    $.getJSON('/api/currentuser', function(data) {
        viewModel.userId = data.id;
        userid = data.id;
    });
    loadTablePage(1,$('#projectHeader').attr("data-value"));
}
<|endoftext|>