<commit_before>/*global define*/
define([
        '../Core/defineProperties',
        '../Core/DeveloperError'
    ], function(
            defineProperties,
        DeveloperError) {
    "use strict";

    /**
     * Defines the interface for data sources, which turn arbitrary data into a
     * {@link DynamicObjectCollection} for generic consumption. This object is an interface
     * for documentation purposes and is not intended to be instantiated directly.
     * @alias DataSource
     * @constructor
     *
     * @see DynamicObject
     * @see DataSourceDisplay
     */
    var DataSource = function() {
        DeveloperError.throwInstantiationError();
    };

    defineProperties(DataSource.prototype, {
        /**
         * Gets a human-readable name for this instance.
         * @memberof DataSource.prototype
         * @type {String}
         */
        name : {
            get : DeveloperError.throwInstantiationError()
        },
        /**
         * Gets the preferred clock settings for this data source.
         * @memberof DataSource.prototype
         * @type {DynamicClock}
         */
        clock : {
            get : DeveloperError.throwInstantiationError()
        },
        /**
         * Gets the collection of {@link DynamicObject} instances.
         * @memberof DataSource.prototype
         * @type {DynamicObjectCollection}
         */
        dynamicObjects : {
            get : DeveloperError.throwInstantiationError()
        },
        /**
         * Gets a value indicating if the data source is currently loading data.
         * @memberof DataSource.prototype
         * @type {Boolean}
         */
        isLoading : {
            get : DeveloperError.throwInstantiationError()
        },
        /**
         * Gets an event that will be raised when the underlying data changes.
         * @memberof DataSource.prototype
         * @type {Event}
         */
        changedEvent : {
            get : DeveloperError.throwInstantiationError()
        },
        /**
         * Gets an event that will be raised if an error is encountered during processing.
         * @memberof DataSource.prototype
         * @type {Event}
         */
        errorEvent : {
            get : DeveloperError.throwInstantiationError()
        },
        /**
         * Gets an event that will be raised when the value of isLoading changes.
         * @memberof DataSource.prototype
         * @type {Event}
         */
        loadingEvent : {
            get : DeveloperError.throwInstantiationError()
        }
    });

    /**
     * Updates the data source to the provided time.  This function is optional and
     * is not required to be implemented.  It is provided for data sources which
     * retrieve data based on the current animation time or scene state.
     * If implemented, update will be called by {@link DataSourceDisplay} once a frame.
     * @memberof DataSource
     * @function
     *
     * @param {JulianDate} time The simulation time.
     *
     * @returns {Boolean} True if this data source is ready to be displayed at the provided time, false otherwise.
     */
    DataSource.prototype.update = DeveloperError.throwInstantiationError;

    return DataSource;
});<commit_msg>Clean up whitespace.<commit_after>/*global define*/
define([
        '../Core/defineProperties',
        '../Core/DeveloperError'
    ], function(
        defineProperties,
        DeveloperError) {
    "use strict";

    /**
     * Defines the interface for data sources, which turn arbitrary data into a
     * {@link DynamicObjectCollection} for generic consumption. This object is an interface
     * for documentation purposes and is not intended to be instantiated directly.
     * @alias DataSource
     * @constructor
     *
     * @see DynamicObject
     * @see DataSourceDisplay
     */
    var DataSource = function() {
        DeveloperError.throwInstantiationError();
    };

    defineProperties(DataSource.prototype, {
        /**
         * Gets a human-readable name for this instance.
         * @memberof DataSource.prototype
         * @type {String}
         */
        name : {
            get : DeveloperError.throwInstantiationError()
        },
        /**
         * Gets the preferred clock settings for this data source.
         * @memberof DataSource.prototype
         * @type {DynamicClock}
         */
        clock : {
            get : DeveloperError.throwInstantiationError()
        },
        /**
         * Gets the collection of {@link DynamicObject} instances.
         * @memberof DataSource.prototype
         * @type {DynamicObjectCollection}
         */
        dynamicObjects : {
            get : DeveloperError.throwInstantiationError()
        },
        /**
         * Gets a value indicating if the data source is currently loading data.
         * @memberof DataSource.prototype
         * @type {Boolean}
         */
        isLoading : {
            get : DeveloperError.throwInstantiationError()
        },
        /**
         * Gets an event that will be raised when the underlying data changes.
         * @memberof DataSource.prototype
         * @type {Event}
         */
        changedEvent : {
            get : DeveloperError.throwInstantiationError()
        },
        /**
         * Gets an event that will be raised if an error is encountered during processing.
         * @memberof DataSource.prototype
         * @type {Event}
         */
        errorEvent : {
            get : DeveloperError.throwInstantiationError()
        },
        /**
         * Gets an event that will be raised when the value of isLoading changes.
         * @memberof DataSource.prototype
         * @type {Event}
         */
        loadingEvent : {
            get : DeveloperError.throwInstantiationError()
        }
    });

    /**
     * Updates the data source to the provided time.  This function is optional and
     * is not required to be implemented.  It is provided for data sources which
     * retrieve data based on the current animation time or scene state.
     * If implemented, update will be called by {@link DataSourceDisplay} once a frame.
     * @memberof DataSource
     * @function
     *
     * @param {JulianDate} time The simulation time.
     *
     * @returns {Boolean} True if this data source is ready to be displayed at the provided time, false otherwise.
     */
    DataSource.prototype.update = DeveloperError.throwInstantiationError;

    return DataSource;
});<|endoftext|>


<commit_before>var groups = []

// Save attempts to POST or PUT to /groups/
function save(idx) {
    var targets = []
    $.each($("#targetsTable").DataTable().rows().data(), function(i, target) {
        targets.push({
            first_name: unescapeHtml(target[0]),
            last_name: unescapeHtml(target[1]),
            email: unescapeHtml(target[2]),
            position: unescapeHtml(target[3])
        })
    })
    var group = {
            name: $("#name").val(),
            targets: targets
        }
        // Submit the group
    if (idx != -1) {
        // If we're just editing an existing group,
        // we need to PUT /groups/:id
        group.id = groups[idx].id
        api.groupId.put(group)
            .success(function(data) {
                successFlash("Group updated successfully!")
                load()
                dismiss()
                $("#modal").modal('hide')
            })
            .error(function(data) {
                modalError(data.responseJSON.message)
            })
    } else {
        // Else, if this is a new group, POST it
        // to /groups
        api.groups.post(group)
            .success(function(data) {
                successFlash("Group added successfully!")
                load()
                dismiss()
                $("#modal").modal('hide')
            })
            .error(function(data) {
                modalError(data.responseJSON.message)
            })
    }
}

function dismiss() {
    $("#targetsTable").dataTable().DataTable().clear().draw()
    $("#name").val("")
    $("#modal\\.flashes").empty()
}

function edit(idx) {
    targets = $("#targetsTable").dataTable({
        destroy: true, // Destroy any other instantiated table - http://datatables.net/manual/tech-notes/3#destroy
        columnDefs: [{
            orderable: false,
            targets: "no-sort"
        }]
    })
    $("#modalSubmit").unbind('click').click(function() {
        save(idx)
    })
    if (idx == -1) {
        group = {}
    } else {
        group = groups[idx]
        $("#name").val(group.name)
        $.each(group.targets, function(i, record) {
            targets.DataTable()
                .row.add([
                    escapeHtml(record.first_name),
                    escapeHtml(record.last_name),
                    escapeHtml(record.email),
                    escapeHtml(record.position),
                    ''
                ]).draw()
        });
    }
    // Handle file uploads
    $("#csvupload").fileupload({
        dataType: "json",
        add: function(e, data) {
            $("#modal\\.flashes").empty()
            var acceptFileTypes = /(csv|txt)$/i;
            var filename = data.originalFiles[0]['name']
            if (filename && !acceptFileTypes.test(filename.split(".").pop())) {
                modalError("Unsupported file extension (use .csv or .txt)")
                return false;
            }
            data.submit();
        },
        done: function(e, data) {
            $.each(data.result, function(i, record) {
                targets.DataTable()
                    .row.add([
                        escapeHtml(record.first_name),
                        escapeHtml(record.last_name),
                        escapeHtml(record.email),
                        escapeHtml(record.position),
                        ''
                    ]).draw()
            });
        }
    })
}

function deleteGroup(idx) {
    if (confirm("Delete " + groups[idx].name + "?")) {
        api.groupId.delete(groups[idx].id)
            .success(function(data) {
                successFlash(data.message)
                load()
            })
    }
}

function load() {
    $("#groupTable").hide()
    $("#emptyMessage").hide()
    $("#loading").show()
    api.groups.get()
        .success(function(gs) {
            $("#loading").hide()
            if (gs.length > 0) {
                groups = gs
                $("#emptyMessage").hide()
                $("#groupTable").show()
                groupTable = $("#groupTable").DataTable({
                    destroy: true,
                    columnDefs: [{
                        orderable: false,
                        targets: "no-sort"
                    }]
                });
                groupTable.clear();
                $.each(groups, function(i, group) {
                    var targets = ""
                    $.each(group.targets, function(i, target) {
                        targets += target.email + ", "
                        if (targets.length > 50) {
                            targets = targets.slice(0, -3) + "..."
                            return false;
                        }
                    })
                    groupTable.row.add([
                        escapeHtml(group.name),
                        escapeHtml(targets),
                        moment(group.modified_date).format('MMMM Do YYYY, h:mm:ss a'),
                        "
<button class='btn btn-primary' data-toggle='modal' data-target='#modal' onclick='edit(" + i + ")'>\
                    \
                    </button>\
                    <button class='btn btn-danger' onclick='deleteGroup(" + i + ")'>\
                    \
                    </button>
"
                    ]).draw()
                })
            } else {
                $("#emptyMessage").show()
            }
        })
        .error(function() {
            errorFlash("Error fetching groups")
        })
}

$(document).ready(function() {
    load()
        // Setup the event listeners
        // Handle manual additions
    $("#targetForm").submit(function() {
            targets.DataTable()
                .row.add([
                    escapeHtml($("#firstName").val()),
                    escapeHtml($("#lastName").val()),
                    escapeHtml($("#email").val()),
                    escapeHtml($("#position").val()),
                    ''
                ])
                .draw()
            $("#targetForm>div>input").val('')
            $("#firstName").focus()
            return false
        })
        // Handle Deletion
    $("#targetsTable").on("click", "span>i.fa-trash-o", function() {
        targets.DataTable()
            .row($(this).parents('tr'))
            .remove()
            .draw();
    })
    $("#modal").on("hide.bs.modal", function() {
        dismiss()
    })
})
<commit_msg>Clean up formatting of targets modal events<commit_after>var groups = []

// Save attempts to POST or PUT to /groups/
function save(idx) {
    var targets = []
    $.each($("#targetsTable").DataTable().rows().data(), function(i, target) {
        targets.push({
            first_name: unescapeHtml(target[0]),
            last_name: unescapeHtml(target[1]),
            email: unescapeHtml(target[2]),
            position: unescapeHtml(target[3])
        })
    })
    var group = {
            name: $("#name").val(),
            targets: targets
        }
        // Submit the group
    if (idx != -1) {
        // If we're just editing an existing group,
        // we need to PUT /groups/:id
        group.id = groups[idx].id
        api.groupId.put(group)
            .success(function(data) {
                successFlash("Group updated successfully!")
                load()
                dismiss()
                $("#modal").modal('hide')
            })
            .error(function(data) {
                modalError(data.responseJSON.message)
            })
    } else {
        // Else, if this is a new group, POST it
        // to /groups
        api.groups.post(group)
            .success(function(data) {
                successFlash("Group added successfully!")
                load()
                dismiss()
                $("#modal").modal('hide')
            })
            .error(function(data) {
                modalError(data.responseJSON.message)
            })
    }
}

function dismiss() {
    $("#targetsTable").dataTable().DataTable().clear().draw()
    $("#name").val("")
    $("#modal\\.flashes").empty()
}

function edit(idx) {
    targets = $("#targetsTable").dataTable({
        destroy: true, // Destroy any other instantiated table - http://datatables.net/manual/tech-notes/3#destroy
        columnDefs: [{
            orderable: false,
            targets: "no-sort"
        }]
    })
    $("#modalSubmit").unbind('click').click(function() {
        save(idx)
    })
    if (idx == -1) {
        group = {}
    } else {
        group = groups[idx]
        $("#name").val(group.name)
        $.each(group.targets, function(i, record) {
            targets.DataTable()
                .row.add([
                    escapeHtml(record.first_name),
                    escapeHtml(record.last_name),
                    escapeHtml(record.email),
                    escapeHtml(record.position),
                    ''
                ]).draw()
        });
    }
    // Handle file uploads
    $("#csvupload").fileupload({
        dataType: "json",
        add: function(e, data) {
            $("#modal\\.flashes").empty()
            var acceptFileTypes = /(csv|txt)$/i;
            var filename = data.originalFiles[0]['name']
            if (filename && !acceptFileTypes.test(filename.split(".").pop())) {
                modalError("Unsupported file extension (use .csv or .txt)")
                return false;
            }
            data.submit();
        },
        done: function(e, data) {
            $.each(data.result, function(i, record) {
                targets.DataTable()
                    .row.add([
                        escapeHtml(record.first_name),
                        escapeHtml(record.last_name),
                        escapeHtml(record.email),
                        escapeHtml(record.position),
                        ''
                    ]).draw()
            });
        }
    })
}

function deleteGroup(idx) {
    if (confirm("Delete " + groups[idx].name + "?")) {
        api.groupId.delete(groups[idx].id)
            .success(function(data) {
                successFlash(data.message)
                load()
            })
    }
}

function load() {
    $("#groupTable").hide()
    $("#emptyMessage").hide()
    $("#loading").show()
    api.groups.get()
        .success(function(gs) {
            $("#loading").hide()
            if (gs.length > 0) {
                groups = gs
                $("#emptyMessage").hide()
                $("#groupTable").show()
                groupTable = $("#groupTable").DataTable({
                    destroy: true,
                    columnDefs: [{
                        orderable: false,
                        targets: "no-sort"
                    }]
                });
                groupTable.clear();
                $.each(groups, function(i, group) {
                    var targets = ""
                    $.each(group.targets, function(i, target) {
                        targets += target.email + ", "
                        if (targets.length > 50) {
                            targets = targets.slice(0, -3) + "..."
                            return false;
                        }
                    })
                    groupTable.row.add([
                        escapeHtml(group.name),
                        escapeHtml(targets),
                        moment(group.modified_date).format('MMMM Do YYYY, h:mm:ss a'),
                        "
<button class='btn btn-primary' data-toggle='modal' data-target='#modal' onclick='edit(" + i + ")'>\
                    \
                    </button>\
                    <button class='btn btn-danger' onclick='deleteGroup(" + i + ")'>\
                    \
                    </button>
"
                    ]).draw()
                })
            } else {
                $("#emptyMessage").show()
            }
        })
        .error(function() {
            errorFlash("Error fetching groups")
        })
}

$(document).ready(function() {
    load()
    // Setup the event listeners
    // Handle manual additions
    $("#targetForm").submit(function() {
        targets.DataTable()
            .row.add([
                escapeHtml($("#firstName").val()),
                escapeHtml($("#lastName").val()),
                escapeHtml($("#email").val()),
                escapeHtml($("#position").val()),
                ''
            ])
            .draw();
        $("#targetForm>div>input").val('');
        $("#firstName").focus();
        return false;
    });
    // Handle Deletion
    $("#targetsTable").on("click", "span>i.fa-trash-o", function() {
        targets.DataTable()
            .row($(this).parents('tr'))
            .remove()
            .draw();
    });
    $("#modal").on("hide.bs.modal", function() {
        dismiss();
    });
});
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Configuration...
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const BACKGROUND_COLOR = '#eaeaea';
const BORDER_COLOR = '#e4e4e4';
const HIGHLIGHT_COLOR = '#f1f1f1';
const BORDER_WIDTH = 4;

const WALL_COLOR_DARK = '#333333';
const WALL_COLOR_MEDIUM = '#555555';
const WALL_COLOR_LIGHT = '#777777';
const WALL_THICKNESS = 3;

const GRID_COLOR = '#';
const GRID_WIDTH = 2;
const GRID_SPACING = 24;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Object definitions...
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Something in the world is drawable, so everything should inherit from this.
 */
function Drawable() {

}

Drawable.prototype = {
    draw: function (ctx, offX, offY) {
        alert("Inherit the draw function...");
    },
    mousemoveHandler: function () {
        alert("Inherit the mousemove function...");
    },
    mousedownHandler: function (evt) {
        alert("Inherit the mousedown function...");
    },
    mouseupHandler: function (evt) {
        alert("Inherit the mouseup function...")
    }
};

/**
 * A room is a container/"layer" for walls and other household objects.
 */
function Room() {
    this.walls = [];
}
Room.prototype = Drawable;
Room.prototype.constructor = Room;

/**
 * A wall has a start and endpoint, and fill in-between.
 */
function Wall(colA, rowA, colB, rowB) {
    this.endpointA = {c: colA, r: rowA, moving: false};
    this.endpointB = {c: colB, r: rowB, moving: false};
    this.draw = function (ctx, offX, offY) {
        // Upper-left corners of each endpoint.
        var aX = this.endpointA.c * GRID_SPACING - offX;
        var aY = this.endpointA.r * GRID_SPACING - offY;
        var bX = this.endpointB.c * GRID_SPACING - offX;
        var bY = this.endpointB.r * GRID_SPACING - offY;

        ctx.lineWidth = WALL_THICKNESS;

        // Draw lines connecting the two endpoints.
        ctx.strokeStyle = WALL_COLOR_MEDIUM;
        ctx.beginPath();
        ctx.moveTo(aX, aY);
        ctx.lineTo(bX, bY);
        ctx.lineTo(bX + GRID_SPACING, bY);
        ctx.lineTo(aX + GRID_SPACING, aY);
        ctx.lineTo(aX + GRID_SPACING, aY + GRID_SPACING);
        ctx.lineTo(bX + GRID_SPACING, bY + GRID_SPACING);
        ctx.lineTo(bX, bY + GRID_SPACING);
        ctx.lineTo(aX, aY + GRID_SPACING);
        ctx.stroke();

        // Draw handles on each endpoint. Fill in with a color if they're being dragged.
        ctx.fillStyle = WALL_COLOR_LIGHT;
        //TODO

        ctx.strokeStyle = WALL_COLOR_DARK;
        ctx.strokeRect(aX, aY, GRID_SPACING, GRID_SPACING);
        ctx.strokeRect(bX, bY, GRID_SPACING, GRID_SPACING);

    };

    this.mousemoveHandler = function () {
        // Turn cursor if we're over a handle.
        if (mouseCol == this.endpointA.c && mouseRow == this.endpointA.r) {
            setCursorGrab();
        } else if (mouseCol == this.endpointB.c && mouseRow == this.endpointB.r) {
            setCursorGrab();
        } else {
            setCursorDefault();
        }

        // If we're moving, keep the endpoint locations updated.
        if (this.endpointA.moving) {
            this.endpointA.r = mouseRow;
            this.endpointA.c = mouseCol;
        }
        if (this.endpointB.moving) {
            this.endpointB.r = mouseRow;
            this.endpointB.c = mouseCol;
        }
    };

    this.mousedownHandler = function (evt) {

        switch (evt.which) {
            case 1:
                // Check if there was a click in a handle - if so, set its moving property.
                if (mouseCol == this.endpointA.c && mouseRow == this.endpointA.r) {

                    this.endpointA.moving = true;
                } else if (mouseCol == this.endpointB.c && mouseRow == this.endpointB.r) {
                    this.endpointB.moving = true;
                }
                break;
            default:
                break;
        }
    };

    this.mouseupHandler = function (evt) {
        switch (evt.which) {
            case 1:
                // No matter where the click was, we are no longer moving.
                this.endpointA.moving = false;
                this.endpointB.moving = false;
                break;
            default:
                break;
        }
    };
}
Wall.prototype = Drawable;
Wall.prototype.constructor = Wall;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Instance variables...
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Position - where is the viewport looking in absolute coordinates?
var worldX = 0;
var worldY = 0;

// Mouse position - x and y in viewport terms.
var mouseViewX = 0;
var mouseViewY = 0;

// Mouse row/col - in absolute coordinates.
var mouseCol = 0;
var mouseRow = 0;

// Mouse button states - true for down, false for up.
var mouse1 = false;
var mouse2 = false;
var mouse3 = false;

// All of the objects in the world.
var worldObjects = [];

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Canvas initialization...
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
var canvas = document.getElementById('floorplanCanvas');
var c = canvas.getContext('2d');

/**
 * Draw canvas elements.
 */
function redraw() {
    var width = canvas.clientWidth;
    var height = canvas.clientHeight;

    c.fillStyle = BACKGROUND_COLOR;
    c.fillRect(0, 0, width, height);

    // Draw a border around the canvas to make it look nice...
    c.strokeStyle = BORDER_COLOR;
    c.lineWidth = BORDER_WIDTH;
    c.strokeRect(0, 0, width, height);

    // Draw gridlines
    c.strokeStyle = GRID_COLOR;
    c.lineWidth = GRID_WIDTH;

    for (var i = 0; i < height; i += GRID_SPACING) {
        c.strokeRect(0, i - (worldY % GRID_SPACING), width, GRID_WIDTH);
    }

    for (var i = 0; i < width; i += GRID_SPACING) {
        c.strokeRect(i - (worldX % GRID_SPACING), 0, GRID_WIDTH, height);
    }

    // Draw all of the drawable objects.
    for (var i = 0; i < worldObjects.length; i++) {
        worldObjects[i].draw(c, worldX, worldY);
    }
}

/**
 * Resolve the mouse position into row/col.
 */
function resolveMouse() {
    return {
        row: Math.floor((mouseViewY + worldY) / GRID_SPACING),
        col: Math.floor((mouseViewX + worldX) / GRID_SPACING)
    };
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Event listeners and initialization...
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Keep canvas coordinate system syncrhonized with CSS coordinates on window resize.
 */
(function () {
    var canvas = $('#floorplanCanvas');

    initCanvas();
    function initCanvas() {
        window.addEventListener('resize', resizeCanvasWithWindow, false);
        resizeCanvasWithWindow();
    }

    function resizeCanvasWithWindow() {
        var w = $('#floorplanCanvasContainer').width();
        var h = $('#floorplanCanvasContainer').height();
        canvas.attr("width", w);
        canvas.attr("height", h);
        redraw();
    }
})();

/**
 * Want to track where the mouse moved to update, also implements scroll-dragging.
 */
function mouseMoveListener(e) {
    var offset = $('#floorplanCanvas')[0].getBoundingClientRect();

    // Calculate current mouse position
    var newX = e.clientX - offset.left;
    var newY = e.clientY - offset.top;

    // Calculate deltas
    var dX = newX - mouseViewX;
    var dY = newY - mouseViewY;

    // Update global mouse position
    mouseViewX = newX;
    mouseViewY = newY;

    // Move viewport if scrolling
    if (mouse3) {
        worldX -= dX;
        worldY -= dY;
    }

    // Calculate and update column and row locations
    var cr = resolveMouse();
    mouseCol = cr.col;
    mouseRow = cr.row;

    // Propogate mouse movement events to all world objects...
    for (var i = 0; i < worldObjects.length; i++) {
        worldObjects[i].mousemoveHandler();
    }

    redraw();
}

/**
 * Watch for mousedown events and set global flags.
 */
function mouseDownListener(e) {
    switch (e.which) {
        case 1:
            mouse1 = true;
            break;
        case 2:
            mouse2 = true;
            break;
        case 3:
            mouse3 = true;
            break;
    }

    // Propogate mousedown events to all world objects...
    for (var i = 0; i < worldObjects.length; i++) {
        worldObjects[i].mousedownHandler(e);
    }
}

/**
 * Watch for mouseup events and set global flags.
 */
function mouseUpListener(e) {
    switch (e.which) {
        case 1:
            mouse1 = false;
            break;
        case 2:
            mouse2 = false;
            break;
        case 3:
            mouse3 = false;
            break;
    }

    // Propogate mouseup events to all world objects...
    for (var i = 0; i < worldObjects.length; i++) {
        worldObjects[i].mouseupHandler(e);
    }
}

// Register listeners
$('#floorplanCanvas').on('mousemove', mouseMoveListener);
$('#floorplanCanvas').on('mousedown', mouseDownListener);
$('#floorplanCanvas').on('mouseup', mouseUpListener);
$('#floorplanCanvas').on('contextmenu', function () {
    return false; // Disable context menu on canvas for RMB dragging
});

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Utility functions
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Sets the cursor to a grabby cursor on the canvas.
 */
function setCursorGrab() {
    $('#floorplanCanvas').css('cursor', 'move');
}

/**
 * Sets the cursor to the default cursor on the canvas.
 */
function setCursorDefault() {
    $('#floorplanCanvas').css('cursor', 'default');
}

//
// Debug functions
//

function addWall() {

    var w = new Wall(1, 1, 5, 1);

    worldObjects.push(w);
}<commit_msg>fix cursor bug when multiple walls are trying to set defualt cursor<commit_after>////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Configuration...
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const BACKGROUND_COLOR = '#eaeaea';
const BORDER_COLOR = '#e4e4e4';
const HIGHLIGHT_COLOR = '#f1f1f1';
const BORDER_WIDTH = 4;

const WALL_COLOR_DARK = '#333333';
const WALL_COLOR_MEDIUM = '#555555';
const WALL_COLOR_LIGHT = '#777777';
const WALL_THICKNESS = 3;

const GRID_COLOR = '#';
const GRID_WIDTH = 2;
const GRID_SPACING = 24;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Object definitions...
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Something in the world is drawable, so everything should inherit from this.
 */
function Drawable() {

}

Drawable.prototype = {
    draw: function (ctx, offX, offY) {
        alert("Inherit the draw function...");
    },
    mousemoveHandler: function () {
        alert("Inherit the mousemove function...");
    },
    mousedownHandler: function (evt) {
        alert("Inherit the mousedown function...");
    },
    mouseupHandler: function (evt) {
        alert("Inherit the mouseup function...")
    }
};

/**
 * A room is a container/"layer" for walls and other household objects.
 */
function Room() {
    this.walls = [];
}
Room.prototype = Drawable;
Room.prototype.constructor = Room;

/**
 * A wall has a start and endpoint, and fill in-between.
 */
function Wall(colA, rowA, colB, rowB) {
    this.endpointA = {c: colA, r: rowA, moving: false};
    this.endpointB = {c: colB, r: rowB, moving: false};
    this.draw = function (ctx, offX, offY) {
        // Upper-left corners of each endpoint.
        var aX = this.endpointA.c * GRID_SPACING - offX;
        var aY = this.endpointA.r * GRID_SPACING - offY;
        var bX = this.endpointB.c * GRID_SPACING - offX;
        var bY = this.endpointB.r * GRID_SPACING - offY;

        ctx.lineWidth = WALL_THICKNESS;

        // Draw lines connecting the two endpoints.
        ctx.strokeStyle = WALL_COLOR_MEDIUM;
        ctx.beginPath();
        ctx.moveTo(aX, aY);
        ctx.lineTo(bX, bY);
        ctx.lineTo(bX + GRID_SPACING, bY);
        ctx.lineTo(aX + GRID_SPACING, aY);
        ctx.lineTo(aX + GRID_SPACING, aY + GRID_SPACING);
        ctx.lineTo(bX + GRID_SPACING, bY + GRID_SPACING);
        ctx.lineTo(bX, bY + GRID_SPACING);
        ctx.lineTo(aX, aY + GRID_SPACING);
        ctx.stroke();

        // Draw handles on each endpoint. Fill in with a color if they're being dragged.
        ctx.fillStyle = WALL_COLOR_LIGHT;
        //TODO

        ctx.strokeStyle = WALL_COLOR_DARK;
        ctx.strokeRect(aX, aY, GRID_SPACING, GRID_SPACING);
        ctx.strokeRect(bX, bY, GRID_SPACING, GRID_SPACING);

    };

    this.mousemoveHandler = function () {
        // Turn cursor if we're over a handle.
        if (mouseCol == this.endpointA.c && mouseRow == this.endpointA.r) {
            setCursorGrab();
        } else if (mouseCol == this.endpointB.c && mouseRow == this.endpointB.r) {
            setCursorGrab();
        }

        // If we're moving, keep the endpoint locations updated.
        if (this.endpointA.moving) {
            this.endpointA.r = mouseRow;
            this.endpointA.c = mouseCol;
        }
        if (this.endpointB.moving) {
            this.endpointB.r = mouseRow;
            this.endpointB.c = mouseCol;
        }
    };

    this.mousedownHandler = function (evt) {

        switch (evt.which) {
            case 1:
                // Check if there was a click in a handle - if so, set its moving property.
                if (mouseCol == this.endpointA.c && mouseRow == this.endpointA.r) {

                    this.endpointA.moving = true;
                } else if (mouseCol == this.endpointB.c && mouseRow == this.endpointB.r) {
                    this.endpointB.moving = true;
                }
                break;
            default:
                break;
        }
    };

    this.mouseupHandler = function (evt) {
        switch (evt.which) {
            case 1:
                // No matter where the click was, we are no longer moving.
                this.endpointA.moving = false;
                this.endpointB.moving = false;
                break;
            default:
                break;
        }
    };
}
Wall.prototype = Drawable;
Wall.prototype.constructor = Wall;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Instance variables...
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Position - where is the viewport looking in absolute coordinates?
var worldX = 0;
var worldY = 0;

// Mouse position - x and y in viewport terms.
var mouseViewX = 0;
var mouseViewY = 0;

// Mouse row/col - in absolute coordinates.
var mouseCol = 0;
var mouseRow = 0;

// Mouse button states - true for down, false for up.
var mouse1 = false;
var mouse2 = false;
var mouse3 = false;

// All of the objects in the world.
var worldObjects = [];

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Canvas initialization...
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
var canvas = document.getElementById('floorplanCanvas');
var c = canvas.getContext('2d');

/**
 * Draw canvas elements.
 */
function redraw() {
    var width = canvas.clientWidth;
    var height = canvas.clientHeight;

    c.fillStyle = BACKGROUND_COLOR;
    c.fillRect(0, 0, width, height);

    // Draw a border around the canvas to make it look nice...
    c.strokeStyle = BORDER_COLOR;
    c.lineWidth = BORDER_WIDTH;
    c.strokeRect(0, 0, width, height);

    // Draw gridlines
    c.strokeStyle = GRID_COLOR;
    c.lineWidth = GRID_WIDTH;

    for (var i = 0; i < height; i += GRID_SPACING) {
        c.strokeRect(0, i - (worldY % GRID_SPACING), width, GRID_WIDTH);
    }

    for (var i = 0; i < width; i += GRID_SPACING) {
        c.strokeRect(i - (worldX % GRID_SPACING), 0, GRID_WIDTH, height);
    }

    // Draw all of the drawable objects.
    for (var i = 0; i < worldObjects.length; i++) {
        worldObjects[i].draw(c, worldX, worldY);
    }
}

/**
 * Resolve the mouse position into row/col.
 */
function resolveMouse() {
    return {
        row: Math.floor((mouseViewY + worldY) / GRID_SPACING),
        col: Math.floor((mouseViewX + worldX) / GRID_SPACING)
    };
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Event listeners and initialization...
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Keep canvas coordinate system syncrhonized with CSS coordinates on window resize.
 */
(function () {
    var canvas = $('#floorplanCanvas');

    initCanvas();
    function initCanvas() {
        window.addEventListener('resize', resizeCanvasWithWindow, false);
        resizeCanvasWithWindow();
    }

    function resizeCanvasWithWindow() {
        var w = $('#floorplanCanvasContainer').width();
        var h = $('#floorplanCanvasContainer').height();
        canvas.attr("width", w);
        canvas.attr("height", h);
        redraw();
    }
})();

/**
 * Want to track where the mouse moved to update, also implements scroll-dragging.
 */
function mouseMoveListener(e) {
    var offset = $('#floorplanCanvas')[0].getBoundingClientRect();

    // Calculate current mouse position
    var newX = e.clientX - offset.left;
    var newY = e.clientY - offset.top;

    // Calculate deltas
    var dX = newX - mouseViewX;
    var dY = newY - mouseViewY;

    // Update global mouse position
    mouseViewX = newX;
    mouseViewY = newY;

    // Move viewport if scrolling
    if (mouse3) {
        worldX -= dX;
        worldY -= dY;
    }

    // Calculate and update column and row locations
    var cr = resolveMouse();
    mouseCol = cr.col;
    mouseRow = cr.row;

    // Reset the cursor before letting objects change it.
    setCursorDefault();

    // Propogate mouse movement events to all world objects...
    for (var i = 0; i < worldObjects.length; i++) {
        worldObjects[i].mousemoveHandler();
    }

    redraw();
}

/**
 * Watch for mousedown events and set global flags.
 */
function mouseDownListener(e) {
    switch (e.which) {
        case 1:
            mouse1 = true;
            break;
        case 2:
            mouse2 = true;
            break;
        case 3:
            mouse3 = true;
            break;
    }

    // Propogate mousedown events to all world objects...
    for (var i = 0; i < worldObjects.length; i++) {
        worldObjects[i].mousedownHandler(e);
    }
}

/**
 * Watch for mouseup events and set global flags.
 */
function mouseUpListener(e) {
    switch (e.which) {
        case 1:
            mouse1 = false;
            break;
        case 2:
            mouse2 = false;
            break;
        case 3:
            mouse3 = false;
            break;
    }

    // Propogate mouseup events to all world objects...
    for (var i = 0; i < worldObjects.length; i++) {
        worldObjects[i].mouseupHandler(e);
    }
}

// Register listeners
$('#floorplanCanvas').on('mousemove', mouseMoveListener);
$('#floorplanCanvas').on('mousedown', mouseDownListener);
$('#floorplanCanvas').on('mouseup', mouseUpListener);
$('#floorplanCanvas').on('contextmenu', function () {
    return false; // Disable context menu on canvas for RMB dragging
});

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Utility functions
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Sets the cursor to a grabby cursor on the canvas.
 */
function setCursorGrab() {
    $('#floorplanCanvas').css('cursor', 'move');
}

/**
 * Sets the cursor to the default cursor on the canvas.
 */
function setCursorDefault() {
    $('#floorplanCanvas').css('cursor', 'default');
}

//
// Debug functions
//

function addWall() {

    var w = new Wall(1, 1, 5, 1);

    worldObjects.push(w);
}<|endoftext|>


<commit_before>// localhost, IP or domain name
SERVER = document.location.hostname;

//Port (the same one as the server, default is 8000)
PORT = 8000;

var socket = io.connect('http://'+SERVER+':'+PORT);

/*
 * Scrolling to the bottom every posts
 */
function scrollBottom()
  {
    var objDiv = document.getElementById("tchat");
    objDiv.scrollTop = objDiv.scrollHeight;
  }
  //setInterval(scrollBottom, 10)
/*
 * Escaping a string, basically...
 */
function htmlEscape(text) {
     return text.replace(/&/g, '&').
     replace(/</g, '<').
     replace(/"/g, '"').
     replace(/'/g, ''');
}

/*
 * Asking username
 */

function askLogin(){
    $('#modal1').trigger('openModal');
  }
function dismissLogin(){
  var nb = Math.floor(Math.random() * 1000);
  pseudo = $('#usernamelogin').val() || "Guest" + nb;
  console.log(pseudo);
  $('#modal1').trigger('closeModal');
  return false;
  return pseudo;
}

/*
 * To send a message to the server
 * after sumitting the form with "enter"
 */
function sendMessage(mess) {
          var message = document.getElementById('message').value;
          var message = htmlEscape(message);
          socket.emit('newPost', { 'hour' : '', 'pseudo' : pseudo, 'message' : message, rank: 4});
          scrollBottom();
          $('#message').val('');
          return false;
    }
<commit_msg>Update functions.js<commit_after>/* For the automatic client
 * This allows any person to create his
 * own chat on your server.
 */
h = document.location.hostname;
h = h.split('.');
c = h[0]; //->"IP-PORT"
c = c.split('-');
SERVER = c[0];
PORT = c[1];

/*
 * If you want to install your own client,
 * please uncomment this part and remove all lines
 * beyond
 *-------------------.
 * IP = yourPort;
 * SERVER = yourHostname;
 */
var socket = io.connect('http://'+SERVER+':'+PORT);

/*
 * Scrolling to the bottom every posts
 */
function scrollBottom()
  {
    var objDiv = document.getElementById("tchat");
    objDiv.scrollTop = objDiv.scrollHeight;
  }
  //setInterval(scrollBottom, 10)
/*
 * Escaping a string, basically...
 */
function htmlEscape(text) {
     return text.replace(/&/g, '&').
     replace(/</g, '<').
     replace(/"/g, '"').
     replace(/'/g, ''');
}

/*
 * Asking username
 */

function askLogin(){
    $('#modal1').trigger('openModal');
  }
function dismissLogin(){
  var nb = Math.floor(Math.random() * 1000);
  pseudo = $('#usernamelogin').val() || "Guest" + nb;
  console.log(pseudo);
  $('#modal1').trigger('closeModal');
  return false;
  return pseudo;
}

/*
 * To send a message to the server
 * after sumitting the form with "enter"
 */
function sendMessage(mess) {
          var message = document.getElementById('message').value;
          var message = htmlEscape(message);
          socket.emit('newPost', { 'hour' : '', 'pseudo' : pseudo, 'message' : message, rank: 4});
          scrollBottom();
          $('#message').val('');
          return false;
    }
<|endoftext|>


<commit_before>/*
  Event Handlers
*/
$('document').ready(function() {

  /*
    Window Close Confirmation
  */

  /*
    Navigation Buttons
  */
  $('a#save').click(function() {
    saveWeek(getAssignmentValues());
  });
  $('a#back').click(function() {
    // animation
    $('#sidebar').slide($(window).width(), 200);
    $("#planner").slide($(window).width(), 200, function() {
      saveWeek(getAssignmentValues()); // save the current state
      ref.monday = new Date(ref.monday.getFullYear(), ref.monday.getMonth(), ref.monday.getDate() - 7); // decrement by 1 week
      getWeek(setAssignmentValues);
      drawDates();
    });
  });
  $('a#next').click(function() {
    $('#sidebar').slide(-$(window).width(), 200);
    $("#planner").slide(-$(window).width(), 200, function() {
      saveWeek(getAssignmentValues());
      ref.monday = new Date(ref.monday.getFullYear(), ref.monday.getMonth(), ref.monday.getDate() + 7);
      getWeek(setAssignmentValues);
      drawDates();
    });
  });

  // add subject
  $('button#add').click(function() {
    r = ref.settings.rows;
    // r.push(["Class", r[r.length-1][1]+1]);
    // add row to subjects
    r.push("Class");
    ref.settings.rows = r;
    // save
    db.put(ref.settings, function(err, response) {
      if (err) {
        alert("there's been an error. try again.");
        console.log(err);
      } else {
        db.get("settings").then(function(s) {
          ref.settings = s;
          renderRows(s.rows);
          // select the new row
          $('.subj#'+String(s.rows.length)).children('.subjectspan').trigger('dblclick');
        });
      }
    });
  });

  /*
    Form buttons for AJAX
  */
  $("form#login").submit(function(e) {
    e.preventDefault();
    login($('#loginUsername').val().toLowerCase(), $('#loginPassword').val(), function(data) {
      $('.stuff').show();
      $('.navbar').show();
      $('.mobile').show();

      $('.loginModal').modal('hide');
      $('li#username').children('a').text(data.user);
      $('.loggedIn').show();
      $('.loggedOut').hide();
      $('#403').hide();
      $('textarea').each(function(index, element) {
        element.removeAttribute('disabled');
      });
    }, function(data) {
      $('li#username').children('a').text('');
      $('#403').text('The username and password entered does not match.');
      $('#403').show();
    });
  });

  $("form#signup").submit(function(e) {
    e.preventDefault();
    if ($('#signupPasswordVerify').val() == $('#signupPassword').val()) {
      signup($('#signupUsername').val().toLowerCase(), $('#signupPassword').val(), function(data) {
        $('.stuff').show();
        $('.navbar').show();
        $('.mobile').show();

        $('.signupModal').modal('hide');
        $('li#username').children('a').text(data.user);
        $('.loggedIn').show();
        $('.loggedOut').hide();
        $('#403').hide();
        $('textarea').each(function(index, element) {
          element.removeAttribute('disabled');
        });
      }, function(data) {
        $('li#username').children('a').text('');
        $('#403-1').text('This user already exists');
        $('#403-1').show();
      });
    } else {
      $('#403-1').text('The password you entered must match.');
      $('#403-1').show();
    }
  });

  $('#goToLogin').click(function() {
    $('.choiceModal').modal('hide');
    $('.loginModal').modal('show');
  });

  $('#goToSignup').click(function() {
    $('.choiceModal').modal('hide');
    $('.signupModal').modal('show');
  });

  $('.signupModal').on('hidden.bs.modal', function() {
    if ($('li#username').children('a').text() == "")
      $('.choiceModal').modal('show');
  });

  $('.loginModal').on('hidden.bs.modal', function() {
    if ($('li#username').children('a').text() == "")
      $('.choiceModal').modal('show');
  });
  taListen();
  subjectListen();
});

function taListen() {
  $("textarea").unbind();
  /*
    Keypress listener, for parsing and using inputs to different textareas.
    Will get quite large as features such as lab requests are added.
  */
  $("textarea").blur(function() {
    saveWeek(getAssignmentValues());
  });
  $("textarea").keydown(function(e) {
    if (e.which == 13) {
      saveWeek(getAssignmentValues());
      var value = $(this).val().toLowerCase();
      if (value.indexOf("test") != -1) {
        var d = new Date(ref.monday.getFullYear(), ref.monday.getMonth(), ref.monday.getDate() + (this.id[1]-1));
        var today = new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate()).toISOString();
        console.log(((d.getMonth()+1) + '/' + d.getDate() + '/' + d.getYear() % 100) + " " + ref.settings.rows[this.id[0]-1]);
      }
    }
  });

  /*
  Setting assignment as done
  */
  $('textarea').parent().mouseenter(function() {
    $(this).children("button").show();
  });
  $('textarea').parent().mouseleave(function() {
     $(this).children("button").hide();
  });
  $('button.done').unbind();
  $('button.done').click(function() {
    var t = $(this).parent().children("textarea");
    if ($(t).css("text-decoration") == "none")
        $(t).css("text-decoration", "line-through");
    else
      $(t).css("text-decoration", "none");

  });

  /*
    Double tap/Double click for setting assignments as completed.
  */
  var isiOS = false;
  var agent = navigator.userAgent.toLowerCase();
  if(agent.indexOf('iphone') >= 0 || agent.indexOf('ipad') >= 0) {
    isiOS = true;
  }

  if (!isiOS){
    $('textarea').dblclick(function() { // toggle between strikethrough and no styling on textareas
      if ($(this).css("text-decoration") == "none")
        $(this).css("text-decoration", "line-through");
      else {
        $(this).css("text-decoration", "none");
      }
    });
  } else {
    var action;
    $('textarea').bind('touchend', function(event){
      var now = new Date().getTime();
      var lastTouch = $(this).data('lastTouch') || now + 1 /** the first time this will make delta a negative number */;
      var delta = now - lastTouch;
      clearTimeout(action);
      if (delta<500 && delta>0){
        if ($(this).css("text-decoration") == "none") {
          $(this).css("text-decoration", "line-through");
        }
        else {
          $(this).css("text-decoration", "none");
        }
      } else {
        $(this).data('lastTouch', now);
        action = setTimeout(function(e){
         // If this runs you can invoke your 'click/touchend' code
         clearTimeout(action);   // clear the timeout
        }, 500, [event]);
      }
      $(this).data('lastTouch', now);
    });
  }
}

function subjectListen() {
  $('.subj').unbind(); // When you add a subject, need to re-add all the listeners

  $('.subj').on('dblclick', '.subjectspan', function () {
    var input = $('<input />', {
      'type': 'text',
      'name': 'unique',
      'value': $(this).html()
    });
    $(this).parent().prepend(input);
    $(this).remove();
    input.focus();
    input.select();

    input.keydown(function(e) {
      // console.log(e);
      // console.log(e);
      if (e.keyCode == 13) {
        e.preventDefault();
        // console.log(e);
        this.blur();
      }
    });
  });

 $('.subj').on('blur', 'input', function () {
    $(this).parent().prepend($('<span />', {'class':'subjectspan'}).html($(this).val()));
    var id = $(this).parent().get(0).id;
    var subj = $(this).val();
    $(this).unbind();
    $(this).remove();
    if (id != 0) {
      $(this).prop('contenteditable', false); // make it not editable
      ref.settings.rows[id-1] = subj; // actually change the name
      // Save the new settings
      db.put(ref.settings, function(err, response) {
        if (err) {
          alert("there's been an error. try again.");
          console.log(err);
        } else {
          db.get("settings").then(function(s) {
            ref.settings = s;
          });
        }
      });
    }
  });

  $('input').keydown(function(e) {
  console.log(e);
  if (e.keycode == 13) {
    e.preventDefault();
    this.blur();
  }
  });

  // mouseover logic
  $('.subj').mouseenter(function() {
    $(this).children(".subjbtns").show();
  });
  $('.subj').mouseleave(function() {
     $(this).children(".subjbtns").hide();
  });

  $('button.delete').unbind();
  // delete subject
  $('button.delete').click(function() {
    var id = $(this).parent().parent()[0].id;
    if (confirm("Are you sure you want to delete " + ref.settings.rows[id-1] + "?")){
      ref.settings.rows.splice(id-1, 1); // splice out the row from settings
      // save
      db.put(ref.settings, function(err, response) {
        if (err) {
          alert("there's been an error. try again.");
          console.log(err);
        } else {
          db.get("settings").then(function(s) {
            ref.settings = s;
            renderRows(s.rows);
          });
        }
      });
    }
  });
  $('button.edit').unbind();
  $('button.edit').click(function() {
      $(this).parent().parent().children('.subjectspan').trigger('dblclick');
  });
}<commit_msg>removed doubleclick to cross out<commit_after>/*
  Event Handlers
*/
$('document').ready(function() {

  /*
    Window Close Confirmation
  */

  /*
    Navigation Buttons
  */
  $('a#save').click(function() {
    saveWeek(getAssignmentValues());
  });
  $('a#back').click(function() {
    // animation
    $('#sidebar').slide($(window).width(), 200);
    $("#planner").slide($(window).width(), 200, function() {
      saveWeek(getAssignmentValues()); // save the current state
      ref.monday = new Date(ref.monday.getFullYear(), ref.monday.getMonth(), ref.monday.getDate() - 7); // decrement by 1 week
      getWeek(setAssignmentValues);
      drawDates();
    });
  });
  $('a#next').click(function() {
    $('#sidebar').slide(-$(window).width(), 200);
    $("#planner").slide(-$(window).width(), 200, function() {
      saveWeek(getAssignmentValues());
      ref.monday = new Date(ref.monday.getFullYear(), ref.monday.getMonth(), ref.monday.getDate() + 7);
      getWeek(setAssignmentValues);
      drawDates();
    });
  });

  // add subject
  $('button#add').click(function() {
    r = ref.settings.rows;
    // r.push(["Class", r[r.length-1][1]+1]);
    // add row to subjects
    r.push("Class");
    ref.settings.rows = r;
    // save
    db.put(ref.settings, function(err, response) {
      if (err) {
        alert("there's been an error. try again.");
        console.log(err);
      } else {
        db.get("settings").then(function(s) {
          ref.settings = s;
          renderRows(s.rows);
          // select the new row
          $('.subj#'+String(s.rows.length)).children('.subjectspan').trigger('dblclick');
        });
      }
    });
  });

  /*
    Form buttons for AJAX
  */
  $("form#login").submit(function(e) {
    e.preventDefault();
    login($('#loginUsername').val().toLowerCase(), $('#loginPassword').val(), function(data) {
      $('.stuff').show();
      $('.navbar').show();
      $('.mobile').show();

      $('.loginModal').modal('hide');
      $('li#username').children('a').text(data.user);
      $('.loggedIn').show();
      $('.loggedOut').hide();
      $('#403').hide();
      $('textarea').each(function(index, element) {
        element.removeAttribute('disabled');
      });
    }, function(data) {
      $('li#username').children('a').text('');
      $('#403').text('The username and password entered does not match.');
      $('#403').show();
    });
  });

  $("form#signup").submit(function(e) {
    e.preventDefault();
    if ($('#signupPasswordVerify').val() == $('#signupPassword').val()) {
      signup($('#signupUsername').val().toLowerCase(), $('#signupPassword').val(), function(data) {
        $('.stuff').show();
        $('.navbar').show();
        $('.mobile').show();

        $('.signupModal').modal('hide');
        $('li#username').children('a').text(data.user);
        $('.loggedIn').show();
        $('.loggedOut').hide();
        $('#403').hide();
        $('textarea').each(function(index, element) {
          element.removeAttribute('disabled');
        });
      }, function(data) {
        $('li#username').children('a').text('');
        $('#403-1').text('This user already exists');
        $('#403-1').show();
      });
    } else {
      $('#403-1').text('The password you entered must match.');
      $('#403-1').show();
    }
  });

  $('#goToLogin').click(function() {
    $('.choiceModal').modal('hide');
    $('.loginModal').modal('show');
  });

  $('#goToSignup').click(function() {
    $('.choiceModal').modal('hide');
    $('.signupModal').modal('show');
  });

  $('.signupModal').on('hidden.bs.modal', function() {
    if ($('li#username').children('a').text() == "")
      $('.choiceModal').modal('show');
  });

  $('.loginModal').on('hidden.bs.modal', function() {
    if ($('li#username').children('a').text() == "")
      $('.choiceModal').modal('show');
  });
  taListen();
  subjectListen();
});

function taListen() {
  $("textarea").unbind();
  /*
    Keypress listener, for parsing and using inputs to different textareas.
    Will get quite large as features such as lab requests are added.
  */
  $("textarea").blur(function() {
    saveWeek(getAssignmentValues());
  });
  $("textarea").keydown(function(e) {
    if (e.which == 13) {
      saveWeek(getAssignmentValues());
      var value = $(this).val().toLowerCase();
      if (value.indexOf("test") != -1) {
        var d = new Date(ref.monday.getFullYear(), ref.monday.getMonth(), ref.monday.getDate() + (this.id[1]-1));
        var today = new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate()).toISOString();
        console.log(((d.getMonth()+1) + '/' + d.getDate() + '/' + d.getYear() % 100) + " " + ref.settings.rows[this.id[0]-1]);
      }
    }
  });

  /*
  Setting assignment as done
  */
  $('textarea').parent().mouseenter(function() {
    $(this).children("button").show();
  });
  $('textarea').parent().mouseleave(function() {
     $(this).children("button").hide();
  });
  $('button.done').unbind();
  $('button.done').click(function() {
    var t = $(this).parent().children("textarea");
    if ($(t).css("text-decoration") == "none")
        $(t).css("text-decoration", "line-through");
    else
      $(t).css("text-decoration", "none");

  });

  /*
    Double tap/Double click for setting assignments as completed.
  */
  var isiOS = false;
  var agent = navigator.userAgent.toLowerCase();
  if(agent.indexOf('iphone') >= 0 || agent.indexOf('ipad') >= 0) {
    isiOS = true;
  }

  if (!isiOS){/*
    $('textarea').dblclick(function() { // toggle between strikethrough and no styling on textareas
      if ($(this).css("text-decoration") == "none")
        $(this).css("text-decoration", "line-through");
      else {
        $(this).css("text-decoration", "none");
      }
    });*/
  } else {
    var action;
    $('textarea').bind('touchend', function(event){
      var now = new Date().getTime();
      var lastTouch = $(this).data('lastTouch') || now + 1 /** the first time this will make delta a negative number */;
      var delta = now - lastTouch;
      clearTimeout(action);
      if (delta<500 && delta>0){
        if ($(this).css("text-decoration") == "none") {
          $(this).css("text-decoration", "line-through");
        }
        else {
          $(this).css("text-decoration", "none");
        }
      } else {
        $(this).data('lastTouch', now);
        action = setTimeout(function(e){
         // If this runs you can invoke your 'click/touchend' code
         clearTimeout(action);   // clear the timeout
        }, 500, [event]);
      }
      $(this).data('lastTouch', now);
    });
  }
}

function subjectListen() {
  $('.subj').unbind(); // When you add a subject, need to re-add all the listeners

  $('.subj').on('dblclick', '.subjectspan', function () {
    var input = $('<input />', {
      'type': 'text',
      'name': 'unique',
      'value': $(this).html()
    });
    $(this).parent().prepend(input);
    $(this).remove();
    input.focus();
    input.select();

    input.keydown(function(e) {
      // console.log(e);
      // console.log(e);
      if (e.keyCode == 13) {
        e.preventDefault();
        // console.log(e);
        this.blur();
      }
    });
  });

 $('.subj').on('blur', 'input', function () {
    $(this).parent().prepend($('<span />', {'class':'subjectspan'}).html($(this).val()));
    var id = $(this).parent().get(0).id;
    var subj = $(this).val();
    $(this).unbind();
    $(this).remove();
    if (id != 0) {
      $(this).prop('contenteditable', false); // make it not editable
      ref.settings.rows[id-1] = subj; // actually change the name
      // Save the new settings
      db.put(ref.settings, function(err, response) {
        if (err) {
          alert("there's been an error. try again.");
          console.log(err);
        } else {
          db.get("settings").then(function(s) {
            ref.settings = s;
          });
        }
      });
    }
  });

  $('input').keydown(function(e) {
  console.log(e);
  if (e.keycode == 13) {
    e.preventDefault();
    this.blur();
  }
  });

  // mouseover logic
  $('.subj').mouseenter(function() {
    $(this).children(".subjbtns").show();
  });
  $('.subj').mouseleave(function() {
     $(this).children(".subjbtns").hide();
  });

  $('button.delete').unbind();
  // delete subject
  $('button.delete').click(function() {
    var id = $(this).parent().parent()[0].id;
    if (confirm("Are you sure you want to delete " + ref.settings.rows[id-1] + "?")){
      ref.settings.rows.splice(id-1, 1); // splice out the row from settings
      // save
      db.put(ref.settings, function(err, response) {
        if (err) {
          alert("there's been an error. try again.");
          console.log(err);
        } else {
          db.get("settings").then(function(s) {
            ref.settings = s;
            renderRows(s.rows);
          });
        }
      });
    }
  });
  $('button.edit').unbind();
  $('button.edit').click(function() {
      $(this).parent().parent().children('.subjectspan').trigger('dblclick');
  });
}<|endoftext|>


<commit_before>// Copyright 2014 The Cayley Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

function Network() {
  var height = 800;
  var width = 800;

  // Things in the first force graph.
  var nodesG = null;
  var linksG = null;
  var linkNodesG = null;

  var node = null;
  var linknode = null;
  var link = null;

  var curLinksData = null;
  var curNodesData = null;

  // Things in the second force graph
  var tag_nodesG = null;
  var tag_linksG = null;

  var tag_node = null;
  var tag_link = null;

  var curTagLinksData = null;
  var curTagNodesData = null;

  var allData = null;

  var dragstart = function(d) {
    d3.select(this).classed("fixed", d.fixed = true);
  }

  //our force directed layout
  var force = d3.layout.force()
  var force_drag = force.drag().on("dragstart", dragstart)
  var tag_force = d3.layout.force()

  //color function used to color nodes
  var baseNodeColors = d3.scale.category20()
  var linkNodeColors = function(d) {
    return d3.rgb("#555").toString()
  }
  var strokeFor = function(d) {
    return d3.rgb("#000").brighter().toString()
  }

  var rotationTransformForLinkNode = function (d) {
    var center_x = (d.link.source.x + d.link.target.x) / 2
    var center_y = (d.link.source.y + d.link.target.y) / 2
    var dx = d.link.target.x - d.link.source.x
    var dy = d.link.target.y - d.link.source.y
    var rotation_radians = Math.atan2(dy,dx)
    var rotation_degrees = rotation_radians * (180 / Math.PI)
    return "rotate(" + rotation_degrees + ", " + center_x + ", " + center_y + ")"

  }

  var updateLink = function() {
    this.attr("x1", function(d) {return d.source.x})
        .attr("y1", function(d) {return d.source.y})
        .attr("x2", function(d) {return d.target.x})
        .attr("y2", function(d) {return d.target.y})
  }

  var forceTick = function(e) {
    tag_force.start()
    node
      .attr("cx", function(d) {return d.x})
      .attr("cy", function(d) {return d.y})

    linknode.each(function(d) {
      d.x = (d.link.source.x + d.link.target.x) / 2
      d.y = (d.link.source.y + d.link.target.y) / 2
    })

    linknode
      .attr("cx", function(d) {return d.x })
      .attr("cy", function(d) {return d.y })
      .attr("transform", rotationTransformForLinkNode)

    link.call(updateLink);

    tagForceTick(e)
  }

  var tagForceTick = function(e) {
    tag_node.each(function(d) {
      if(d.is_tag === false) {
        d.x = d.node.x;
        d.y = d.node.y;
      } else {
        var b = this.childNodes[1].getBBox();
        var diffX = d.x - d.node.x;
        var diffY = d.y - d.node.y;

        var dist = Math.sqrt(diffX * diffX + diffY * diffY);

        var shiftX = b.width * (diffX - dist) / (dist * 2);
        shiftX = Math.max(-b.width, Math.min(0, shiftX));
        var shiftY = 5;
        this.childNodes[1].setAttribute("transform", "translate(" + shiftX + "," + shiftY + ")");
      }
    });
    tag_node
        .attr("transform", function(d) {
                return "translate(" + d.x + "," + d.y + ")";
        });

    tag_link.call(updateLink);
  }

  var setupData = function (data) {
    data.nodes.forEach(function (n) {
      n.x = randomnumber=Math.floor(Math.random()*width)
      n.y = randomnumber=Math.floor(Math.random()*height)
      n.radius = 10
    });

    var nodesMap = mapNodes(data.nodes)

    data.links.forEach(function (l) {
      l.source = nodesMap.get(l.source)
      l.target = nodesMap.get(l.target)
      nodesMap.get(l.link_node).link = l
    })

    data.tag_links = []
    data.tag_nodes = []
    var tag_id_counter = 0

    data.nodes.forEach(function (n) {
      if (n.tags !== undefined) {
        n.tags.forEach( function (tag) {
          var tag_node = {}
          tag_node.id = "tag" + tag_id_counter
          tag_node.tag = tag
          tag_node.x = n.x
          tag_node.y = n.y
          tag_node.is_tag = true
          tag_node.is_value = false
          tag_node.node = n
          tag_node.radius = 0
          tag_id_counter += 1;
          var fake_node = {}
          fake_node.id = "tag" + tag_id_counter
          fake_node.x = n.x
          fake_node.y = n.y
          fake_node.node = n
          fake_node.radius = 0
          fake_node.is_tag = false
          tag_id_counter += 1;
          var tag_link = {}
          tag_link.source = fake_node
          tag_link.target = tag_node
          data.tag_nodes.push(tag_node)
          data.tag_nodes.push(fake_node)
          data.tag_links.push(tag_link)
        })
      }
      if (n.values !== undefined) {
        n.values.forEach( function (value) {
          var tag_node = {}
          tag_node.id = "tag" + tag_id_counter
          tag_node.tag = value
          tag_node.x = n.x
          tag_node.y = n.y
          tag_node.is_tag = true
          tag_node.is_value = true
          tag_node.node = n
          tag_node.radius = 0
          tag_id_counter += 1;
          var fake_node = {}
          fake_node.id = "tag" + tag_id_counter
          fake_node.x = n.x
          fake_node.y = n.y
          fake_node.node = n
          fake_node.radius = 0
          fake_node.is_tag = false
          tag_id_counter += 1;
          var tag_link = {}
          tag_link.source = fake_node
          tag_link.target = tag_node
          data.tag_nodes.push(tag_node)
          data.tag_nodes.push(fake_node)
          data.tag_links.push(tag_link)
        })
      }
    })

    return data;
  }

  var mapNodes = function (nodes) {
    var nodesMap = d3.map()
    nodes.forEach(function (n) {
      nodesMap.set(n.id, n)
    })
    return nodesMap
  }

  var network = function (selection, data) {
    allData = setupData(data)
    var vis = d3.select(selection).append("svg")
       .attr("width", width)
       .attr("height", height)

    vis.append("defs").append("marker")
    .attr("id", "arrowhead")
    .attr("refX", 6 + 3) // shift?
    .attr("refY", 2)
    .attr("markerWidth", 6)
    .attr("markerHeight", 4)
    .attr("orient", "auto")
    .append("path")
    .attr("d", "M 0,0 V 4 L6,2 Z");

    linksG = vis.append("g").attr("id", "links")
    nodesG = vis.append("g").attr("id", "nodes")
    linkNodesG = vis.append("g").attr("id", "link-nodes")

    tagNodesG = vis.append("g").attr("id", "tag_nodes")
    tagLinksG = vis.append("g").attr("id", "tag_links")

    force.size([width, height])
    force.on("tick", forceTick)
      .charge(-200)
      .linkDistance(100);

    tag_force
      .gravity(0)
      .linkDistance(25)
      .linkStrength(20)
      .charge(-100)
      .size([width, height])

    tag_force.start()

    //perform rendering and start force layout
    update()

  }

  var update = function () {
    allNodes = allData.nodes;
    curLinksData = allData.links;
    curNodesData = $.grep(allData.nodes, function(n) { return n.is_link_node === false; })
    curLinkNodesData = $.grep(allData.nodes, function(n) { return n.is_link_node; })

    curTagLinksData = allData.tag_links
    curTagNodesData = allData.tag_nodes

    force.nodes(allNodes);
    node = nodesG.selectAll("circle.node")
      .data(curNodesData, function(d) {return d.id})

    node.enter().append("circle")
      .attr("class", "node")
      .attr("cx", function(d) {return d.x})
      .attr("cy", function(d) {return d.y})
      .attr("r", function(d) {return d.radius;})
      .style("fill", function(d) {return baseNodeColors(d.id);})
      .style("stroke", function(d) {return strokeFor(d);})
      .style("stroke-width", 1.0)
      .call(force_drag)

    node.exit().remove();

    linknode = linkNodesG.selectAll("ellipse.node")
      .data(curLinkNodesData, function(d) { return d.id })

    linknode.enter().append("ellipse")
      .attr("class", "node")
      .attr("cx", function(d) {return d.x})
      .attr("cy", function(d) {return d.y})
      .attr("rx", function(d) {return d.radius;})
      .attr("ry", function(d) {return d.radius / 2;})
      .style("fill", function(d) {return linkNodeColors(d.id);})
      .style("stroke", function(d) {return strokeFor(d);})
      .style("stroke-width", 1.0);

    linknode.exit().remove();

    force.links(curLinksData);

    link = linksG.selectAll("line.link")
      .data(curLinksData, function(d) { return d.source.id + "_" + d.target.id});

    link.enter().append("line")
      .attr("class", "link")
      .attr("stroke", "#222")
      .attr("stroke-opacity", 1.0)
      .attr("marker-end", "url(#arrowhead)")
      .style("stroke-width", 2.0)
      .attr("x1", function(d) {return d.source.x})
      .attr("y1", function(d) {return d.source.y})
      .attr("x2", function(d) {return d.target.x})
      .attr("y2", function(d) {return d.target.y});

    link.exit().remove();
    force.start();

    tag_force.nodes(curTagNodesData);
    tag_node = nodesG.selectAll("g.tag_node")
        .data(curTagNodesData, function(d) { return d.id })
    var tag_g = tag_node.enter().append("g").attr("class", "tag_node")
    tag_g.append("svg:circle").attr("r", 0).style("fill", "#FFF");
    tag_g.append("svg:text")
      .text(function(d) { return d.is_tag ? d.tag : "" })
      .style("fill", "#555")
      .style("font-family", function(d) { return d.is_value ? "Courier" : "Arial"})
      .style("font-size", 12);

    tag_force.links(curTagLinksData);
    tag_link = linksG.selectAll("line.tag_link")
      .data(curTagLinksData, function(d) { return d.source.id + "_" + d.target.id});

    tag_link.enter().append("line")
      .attr("class", "tag_link")
      .attr("stroke", "#ddd")
      .attr("stroke-opacity", 0.5)
      .attr("x1", function(d) {return d.source.x})
      .attr("y1", function(d) {return d.source.y})
      .attr("x2", function(d) {return d.target.x})
      .attr("y2", function(d) {return d.target.y});

    tag_link.exit().remove();
    tag_force.start()
  }

  return network
};

<commit_msg>Fix query shape error when query has no result data links (#641)<commit_after>// Copyright 2014 The Cayley Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

function Network() {
  var height = 800;
  var width = 800;

  // Things in the first force graph.
  var nodesG = null;
  var linksG = null;
  var linkNodesG = null;

  var node = null;
  var linknode = null;
  var link = null;

  var curLinksData = null;
  var curNodesData = null;

  // Things in the second force graph
  var tag_nodesG = null;
  var tag_linksG = null;

  var tag_node = null;
  var tag_link = null;

  var curTagLinksData = null;
  var curTagNodesData = null;

  var allData = null;

  var dragstart = function(d) {
    d3.select(this).classed("fixed", d.fixed = true);
  }

  //our force directed layout
  var force = d3.layout.force()
  var force_drag = force.drag().on("dragstart", dragstart)
  var tag_force = d3.layout.force()

  //color function used to color nodes
  var baseNodeColors = d3.scale.category20()
  var linkNodeColors = function(d) {
    return d3.rgb("#555").toString()
  }
  var strokeFor = function(d) {
    return d3.rgb("#000").brighter().toString()
  }

  var rotationTransformForLinkNode = function (d) {
    if (!d.link) {
      return null
    }
    var center_x = (d.link.source.x + d.link.target.x) / 2
    var center_y = (d.link.source.y + d.link.target.y) / 2
    var dx = d.link.target.x - d.link.source.x
    var dy = d.link.target.y - d.link.source.y
    var rotation_radians = Math.atan2(dy,dx)
    var rotation_degrees = rotation_radians * (180 / Math.PI)
    return "rotate(" + rotation_degrees + ", " + center_x + ", " + center_y + ")"
  }

  var updateLink = function() {
    this.attr("x1", function(d) {return d.source.x})
        .attr("y1", function(d) {return d.source.y})
        .attr("x2", function(d) {return d.target.x})
        .attr("y2", function(d) {return d.target.y})
  }

  var forceTick = function(e) {
    tag_force.start()
    node
      .attr("cx", function(d) {return d.x})
      .attr("cy", function(d) {return d.y})

    linknode.each(function(d) {
      if (d.link) {
        d.x = (d.link.source.x + d.link.target.x) / 2
        d.y = (d.link.source.y + d.link.target.y) / 2
      }
    })

    linknode
      .attr("cx", function(d) {return d.x })
      .attr("cy", function(d) {return d.y })
      .attr("transform", rotationTransformForLinkNode)

    if (link) {
      link.call(updateLink);
    }

    tagForceTick(e)
  }

  var tagForceTick = function(e) {
    tag_node.each(function(d) {
      if(d.is_tag === false) {
        d.x = d.node.x;
        d.y = d.node.y;
      } else {
        var b = this.childNodes[1].getBBox();
        var diffX = d.x - d.node.x;
        var diffY = d.y - d.node.y;

        var dist = Math.sqrt(diffX * diffX + diffY * diffY);

        var shiftX = b.width * (diffX - dist) / (dist * 2);
        shiftX = Math.max(-b.width, Math.min(0, shiftX));
        var shiftY = 5;
        this.childNodes[1].setAttribute("transform", "translate(" + shiftX + "," + shiftY + ")");
      }
    });
    tag_node
        .attr("transform", function(d) {
                return "translate(" + d.x + "," + d.y + ")";
        });

    tag_link.call(updateLink);
  }

  var setupData = function (data) {
    data.nodes.forEach(function (n) {
      n.x = randomnumber=Math.floor(Math.random()*width)
      n.y = randomnumber=Math.floor(Math.random()*height)
      n.radius = 10
    });

    var nodesMap = mapNodes(data.nodes)

    if (data.links) {
      data.links.forEach(function (l) {
        l.source = nodesMap.get(l.source)
        l.target = nodesMap.get(l.target)
        nodesMap.get(l.link_node).link = l
      })
    }

    data.tag_links = []
    data.tag_nodes = []
    var tag_id_counter = 0

    data.nodes.forEach(function (n) {
      if (n.tags !== undefined) {
        n.tags.forEach( function (tag) {
          var tag_node = {}
          tag_node.id = "tag" + tag_id_counter
          tag_node.tag = tag
          tag_node.x = n.x
          tag_node.y = n.y
          tag_node.is_tag = true
          tag_node.is_value = false
          tag_node.node = n
          tag_node.radius = 0
          tag_id_counter += 1;
          var fake_node = {}
          fake_node.id = "tag" + tag_id_counter
          fake_node.x = n.x
          fake_node.y = n.y
          fake_node.node = n
          fake_node.radius = 0
          fake_node.is_tag = false
          tag_id_counter += 1;
          var tag_link = {}
          tag_link.source = fake_node
          tag_link.target = tag_node
          data.tag_nodes.push(tag_node)
          data.tag_nodes.push(fake_node)
          data.tag_links.push(tag_link)
        })
      }
      if (n.values !== undefined) {
        n.values.forEach( function (value) {
          var tag_node = {}
          tag_node.id = "tag" + tag_id_counter
          tag_node.tag = value
          tag_node.x = n.x
          tag_node.y = n.y
          tag_node.is_tag = true
          tag_node.is_value = true
          tag_node.node = n
          tag_node.radius = 0
          tag_id_counter += 1;
          var fake_node = {}
          fake_node.id = "tag" + tag_id_counter
          fake_node.x = n.x
          fake_node.y = n.y
          fake_node.node = n
          fake_node.radius = 0
          fake_node.is_tag = false
          tag_id_counter += 1;
          var tag_link = {}
          tag_link.source = fake_node
          tag_link.target = tag_node
          data.tag_nodes.push(tag_node)
          data.tag_nodes.push(fake_node)
          data.tag_links.push(tag_link)
        })
      }
    })

    return data;
  }

  var mapNodes = function (nodes) {
    var nodesMap = d3.map()
    nodes.forEach(function (n) {
      nodesMap.set(n.id, n)
    })
    return nodesMap
  }

  var network = function (selection, data) {
    allData = setupData(data)
    var vis = d3.select(selection).append("svg")
       .attr("width", width)
       .attr("height", height)

    vis.append("defs").append("marker")
    .attr("id", "arrowhead")
    .attr("refX", 6 + 3) // shift?
    .attr("refY", 2)
    .attr("markerWidth", 6)
    .attr("markerHeight", 4)
    .attr("orient", "auto")
    .append("path")
    .attr("d", "M 0,0 V 4 L6,2 Z");

    linksG = vis.append("g").attr("id", "links")
    nodesG = vis.append("g").attr("id", "nodes")
    linkNodesG = vis.append("g").attr("id", "link-nodes")

    tagNodesG = vis.append("g").attr("id", "tag_nodes")
    tagLinksG = vis.append("g").attr("id", "tag_links")

    force.size([width, height])
    force.on("tick", forceTick)
      .charge(-200)
      .linkDistance(100);

    tag_force
      .gravity(0)
      .linkDistance(25)
      .linkStrength(20)
      .charge(-100)
      .size([width, height])

    tag_force.start()

    //perform rendering and start force layout
    update()

  }

  var update = function () {
    allNodes = allData.nodes;
    curLinksData = allData.links;
    curNodesData = $.grep(allData.nodes, function(n) { return n.is_link_node === false; })
    curLinkNodesData = $.grep(allData.nodes, function(n) { return n.is_link_node; })

    curTagLinksData = allData.tag_links
    curTagNodesData = allData.tag_nodes

    force.nodes(allNodes);
    node = nodesG.selectAll("circle.node")
      .data(curNodesData, function(d) {return d.id})

    node.enter().append("circle")
      .attr("class", "node")
      .attr("cx", function(d) {return d.x})
      .attr("cy", function(d) {return d.y})
      .attr("r", function(d) {return d.radius;})
      .style("fill", function(d) {return baseNodeColors(d.id);})
      .style("stroke", function(d) {return strokeFor(d);})
      .style("stroke-width", 1.0)
      .call(force_drag)

    node.exit().remove();

    linknode = linkNodesG.selectAll("ellipse.node")
      .data(curLinkNodesData, function(d) { return d.id })

    linknode.enter().append("ellipse")
      .attr("class", "node")
      .attr("cx", function(d) {return d.x})
      .attr("cy", function(d) {return d.y})
      .attr("rx", function(d) {return d.radius;})
      .attr("ry", function(d) {return d.radius / 2;})
      .style("fill", function(d) {return linkNodeColors(d.id);})
      .style("stroke", function(d) {return strokeFor(d);})
      .style("stroke-width", 1.0);

    linknode.exit().remove();

    if (curLinksData) {
      force.links(curLinksData);

      link = linksG.selectAll("line.link")
        .data(curLinksData, function(d) { return d.source.id + "_" + d.target.id});

      link.enter().append("line")
        .attr("class", "link")
        .attr("stroke", "#222")
        .attr("stroke-opacity", 1.0)
        .attr("marker-end", "url(#arrowhead)")
        .style("stroke-width", 2.0)
        .attr("x1", function(d) {return d.source.x})
        .attr("y1", function(d) {return d.source.y})
        .attr("x2", function(d) {return d.target.x})
        .attr("y2", function(d) {return d.target.y});

      link.exit().remove();
    }

    force.start();

    tag_force.nodes(curTagNodesData);
    tag_node = nodesG.selectAll("g.tag_node")
        .data(curTagNodesData, function(d) { return d.id })
    var tag_g = tag_node.enter().append("g").attr("class", "tag_node")
    tag_g.append("svg:circle").attr("r", 0).style("fill", "#FFF");
    tag_g.append("svg:text")
      .text(function(d) { return d.is_tag ? d.tag : "" })
      .style("fill", "#555")
      .style("font-family", function(d) { return d.is_value ? "Courier" : "Arial"})
      .style("font-size", 12);

    tag_force.links(curTagLinksData);
    tag_link = linksG.selectAll("line.tag_link")
      .data(curTagLinksData, function(d) { return d.source.id + "_" + d.target.id});

    tag_link.enter().append("line")
      .attr("class", "tag_link")
      .attr("stroke", "#ddd")
      .attr("stroke-opacity", 0.5)
      .attr("x1", function(d) {return d.source.x})
      .attr("y1", function(d) {return d.source.y})
      .attr("x2", function(d) {return d.target.x})
      .attr("y2", function(d) {return d.target.y});

    tag_link.exit().remove();
    tag_force.start()
  }

  return network
};

<|endoftext|>