<commit_before>/*
 * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved.
 */

/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, undef: true, indent: 4, maxerr: 50 */
/*global define: false, $: false, brackets: false */

define(function (require, exports, module) {
    'use strict';

    require("thirdparty/path-utils/path-utils.min");

    // Load dependent modules
    var CommandManager      = require("CommandManager"),
        Commands            = require("Commands"),
        NativeFileSystem    = require("NativeFileSystem").NativeFileSystem,
        ProjectManager      = require("ProjectManager"),
        DocumentManager     = require("DocumentManager"),
        EditorManager       = require("EditorManager"),
        EditorUtils         = require("EditorUtils"),
        Strings             = require("strings");

    /**
     * Handlers for commands related to file handling (opening, saving, etc.)
     */

    /** @type {jQueryObject} */
    var _title;
    /** @type {string} */
    var _currentFilePath;  // TODO: eliminate this and just use getCurrentDocument().file.fullPath
    /** @type {string} */
    var _currentTitlePath;

    function init(title) {
        _title = title;

        // Register global commands
        CommandManager.register(Commands.FILE_OPEN, handleFileOpen);
        CommandManager.register(Commands.FILE_ADD_TO_WORKING_SET, handleFileAddToWorkingSet);
        // TODO: For now, hook up File > New to the "new in project" handler. Eventually
        // File > New should open a new blank tab, and handleFileNewInProject should
        // be called from a "+" button in the project
        CommandManager.register(Commands.FILE_NEW, handleFileNewInProject);
        CommandManager.register(Commands.FILE_SAVE, handleFileSave);
        CommandManager.register(Commands.FILE_CLOSE, handleFileClose);
        CommandManager.register(Commands.FILE_CLOSE_ALL, handleFileCloseAll);
        CommandManager.register(Commands.FILE_QUIT, handleFileQuit);

        $(DocumentManager).on("dirtyFlagChange", handleDirtyChange);
        $(DocumentManager).on("currentDocumentChange", handleCurrentDocumentChange);
    }

    function handleCurrentDocumentChange() {
        var newDocument = DocumentManager.getCurrentDocument();

        if (newDocument) {
            var fullPath = newDocument.file.fullPath;

            _currentFilePath = _currentTitlePath = fullPath;

            // In the main toolbar, show the project-relative path (if the file is inside the current project)
            // or the full absolute path (if it's not in the project).
            _currentTitlePath = ProjectManager.makeProjectRelativeIfPossible(fullPath);

        } else {
            _currentFilePath = _currentTitlePath = null;
        }

        // Update title text & "dirty dot" display
        updateTitle();
    }

    function handleDirtyChange(event, changedDoc) {
        if (changedDoc.file.fullPath === _currentFilePath) {
            updateTitle();
        }
    }

    function updateTitle() {
        var currentDoc = DocumentManager.getCurrentDocument();
        if (currentDoc) {
            _title.text(_currentTitlePath + (currentDoc.isDirty ? " \u2022" : ""));
        } else {
            _title.text("");
        }
    }

    function handleFileAddToWorkingSet(commandData) {
        handleFileOpen(commandData).done(function (doc) {
            DocumentManager.addToWorkingSet(doc);
        });
    }

    function handleFileOpen(commandData) {
        var fullPath = null;
        if (commandData) {
            fullPath = commandData.fullPath;
        }

        var result = doOpenWithOptionalPath(fullPath);
        result.always(function () {
            EditorManager.focusEditor();
        });
        return result;
    }

    /**
     * @private
     * Creates a document and displays an editor for the specified file path.
     * If no path is specified, a file prompt is provided for input.
     * @return {Deferred} a jQuery Deferred that will be resolved with a new
     *  document for the specified file path, or rejected if the file can not be read.
     */
    function doOpenWithOptionalPath(fullPath) {
        var result;
        if (!fullPath) {
            // Prompt the user with a dialog
            // TODO: we're relying on this to not be asynchronous--is that safe?
            NativeFileSystem.showOpenDialog(false, false, Strings.OPEN_FILE, ProjectManager.getProjectRoot().fullPath,
                ["htm", "html", "js", "css"], function (files) {
                    if (files.length > 0) {
                        result = doOpen(files[0]);
                        return;
                    }
                });
        } else {
            result = doOpen(fullPath);
        }
        if (!result) {
            result = (new $.Deferred()).reject();
        }
        return result;
    }

    /**
     * @private
     * Creates a document and displays an editor for the specified file path.
     * @return {Deferred} a jQuery Deferred that will be resolved with a new
     *  document for the specified file path, or rejected if the file can not be read.
     */
    function doOpen(fullPath) {

        var result = new $.Deferred();
        if (!fullPath) {
            console.log("doOpen() called without fullPath");
            return result.reject();
        }

        var doc = DocumentManager.getDocumentForPath(fullPath);
        if (doc) {
            // File already open - don't need to load it, just switch to it in the UI
            DocumentManager.showInEditor(doc);
            result.resolve(doc);

        } else {
            // File wasn't open before, so we must create a new document for it
            var fileEntry = new NativeFileSystem.FileEntry(fullPath);
            var docResult = EditorManager.createDocumentAndEditor(fileEntry);

            docResult.done(function (doc) {
                DocumentManager.showInEditor(doc);
                result.resolve(doc);
            });

            docResult.fail(function (error) {
                EditorUtils.showFileOpenError(error.code, fullPath);
                result.reject();
            });
        }

        return result;
    }

    function handleFileNewInProject() {
        // Determine the directory to put the new file
        // If a file is currently selected, put it next to it.
        // If a directory is currently selected, put it in it.
        // If nothing is selected, put it at the root of the project
        var baseDir,
            selected = ProjectManager.getSelectedItem() || ProjectManager.getProjectRoot();

        baseDir = selected.fullPath;
        if (selected.isFile) {
            baseDir = baseDir.substr(0, baseDir.lastIndexOf("/"));
        }

        // Create the new node. The createNewItem function does all the heavy work
        // of validating file name, creating the new file and selecting.
        var deferred = _getUntitledFileSuggestion(baseDir, "Untitled", ".js");
        var createWithSuggestedName = function (suggestedName) {
            ProjectManager.createNewItem(baseDir, suggestedName, false).pipe(deferred.resolve, deferred.reject, deferred.notify);
        };

        deferred.done(createWithSuggestedName);
        deferred.fail(function createWithDefault() { createWithSuggestedName("Untitled.js"); });
        return deferred;
    }

    function handleFileSave() {
        return doSave(DocumentManager.getCurrentDocument());
    }

    function doSave(docToSave) {
        var result = new $.Deferred();

        if (docToSave && docToSave.isDirty) {
            var fileEntry = docToSave.file;

            //setup our resolve and reject handlers
            result.done(function fileSaved() {
                docToSave.notifySaved();
            });

            result.fail(function fileError(error) {
                showSaveFileError(error.code, fileEntry.fullPath);
            });

            fileEntry.createWriter(
                function (writer) {
                    writer.onwriteend = function () {
                        result.resolve();
                    };
                    writer.onerror = function (error) {
                        result.reject(error);
                    };

                    // TODO (jasonsj): Blob instead of string
                    writer.write(docToSave.getText());
                },
                function (error) {
                    result.reject(error);
                }
            );
        } else {
            result.resolve();
        }
        result.always(function () {
            EditorManager.focusEditor();
        });
        return result;
    }

    /**
     * Saves all unsaved documents. Returns a Promise that will be resolved once ALL the save
     * operations have been completed. If any ONE save operation fails, an error dialog is immediately
     * shown and the promise fails.
     * TODO: But subsequent save operations continue in the background, and if more fail the error
     * dialogs will stack up on top of the old one.
     *
     * @return {$.Promise}
     */
    function saveAll() {
        var saveResults = [];

        DocumentManager.getWorkingSet().forEach(function (doc) {
            saveResults.push(doSave(doc));
        });

        // Aggregate all the file-save Deferreds into one master
        // (p.s., it would be nice if $.when() accepted an array instead of varargs, but oh well...)
        var overallResult = $.when.apply($, saveResults);

        return overallResult;
    }

    /**
     * Closes the specified document. Prompts user about saving file if document is dirty.
     *
     * @param {?{doc: Document}} commandData  Document to close; assumes the current document if null.
     * @param {boolean} promptOnly  If true, only displays the relevant confirmation UI and does NOT
     *          actually close the document. This is useful when chaining file-close together with
     *          other user prompts that may be cancelable.
     * @return {$.Deferred}
     */
    function handleFileClose(commandData) {
        var doc = null;
        if (commandData) {
            doc = commandData.doc;
        }

        // utility function for handleFileClose: closes document & removes from working set
        function doClose(doc) {
            if (!commandData || !commandData.promptOnly) {
                // This selects a different document if the working set has any other options
                DocumentManager.closeDocument(doc);

                EditorManager.focusEditor();
            }
        }

        var result = new $.Deferred();

        // Default to current document if doc is null
        if (!doc) {
            doc = DocumentManager.getCurrentDocument();
        }

        // No-op if called when nothing is open; TODO: should command be grayed out instead?
        if (!doc) {
            return;
        }

        if (doc.isDirty) {
            var filename = PathUtils.parseUrl(doc.file.fullPath).filename;

            brackets.showModalDialog(
                brackets.DIALOG_ID_SAVE_CLOSE,
                Strings.SAVE_CLOSE_TITLE,
                Strings.format(Strings.SAVE_CLOSE_MESSAGE, filename)
            ).done(function (id) {
                if (id === brackets.DIALOG_BTN_CANCEL) {
                    result.reject();
                } else if (id === brackets.DIALOG_BTN_OK) {
                    doSave(doc)
                        .done(function () {
                            doClose(doc);
                            result.resolve();
                        })
                        .fail(function () {
                            result.reject();
                        });
                } else {
                    // This is the "Don't Save" case--we can just go ahead and close the file.
                    doClose(doc);
                    result.resolve();
                }
            });
            result.always(function () {
                EditorManager.focusEditor();
            });
        } else {
            // Doc is not dirty, just close
            doClose(doc);
            EditorManager.focusEditor();
            result.resolve();
        }
        return result;
    }

    /**
     * Closes all open documents; equivalent to calling handleFileClose() for each document, except
     * that unsaved changes are confirmed once, in bulk.
     * @param {?{promptOnly: boolean}}  If true, only displays the relevant confirmation UI and does NOT
     *          actually close any documents. This is useful when chaining close-all together with
     *          other user prompts that may be cancelable.
     * @return {$.Deferred}
     */
    function handleFileCloseAll(commandData) {
        var result = new $.Deferred();

        var unsavedDocs = DocumentManager.getWorkingSet().filter(function (doc) {
            return doc.isDirty;
        });

        if (unsavedDocs.length === 0) {
            // No unsaved changes, so we can proceed without a prompt
            result.resolve();

        } else if (unsavedDocs.length === 1) {
            // Only one unsaved file: show the usual single-file-close confirmation UI
            var fileCloseArgs = { doc: unsavedDocs[0], promptOnly: promptOnly };
            handleFileClose(fileCloseArgs).done(function () {
                // still need to close any other, non-unsaved documents
                result.resolve();
            }).fail(function () {
                result.reject();
            });

        } else {
            // Multiple unsaved files: show a single bulk prompt listing all files
            var message = Strings.SAVE_CLOSE_MULTI_MESSAGE;

            message += "
";
            unsavedDocs.forEach(function (doc) {
                message += "
" + ProjectManager.makeProjectRelativeIfPossible(doc.file.fullPath) + "
";
            });
            message += "
";

            brackets.showModalDialog(
                brackets.DIALOG_ID_SAVE_CLOSE,
                Strings.SAVE_CLOSE_TITLE,
                message
            ).done(function (id) {
                if (id === brackets.DIALOG_BTN_CANCEL) {
                    result.reject();
                } else if (id === brackets.DIALOG_BTN_OK) {
                    // Save all unsaved files, then if that succeeds, close all
                    saveAll().done(function () {
                        result.resolve();
                    }).fail(function () {
                        result.reject();
                    });
                } else {
                    // "Don't Save" case--we can just go ahead and close all  files.
                    result.resolve();
                }
            });
        }

        // If all the unsaved-changes confirmations pan out above, then go ahead & close all editors
        // NOTE: this still happens before any done() handlers added by our caller, because jQ
        // guarantees that handlers run in the order they are added.
        result.done(function () {
            if (!commandData || !commandData.promptOnly) {
                DocumentManager.closeAll();
            }
        });

        return result;
    }

    /** Confirms any unsaved changes, then exits Brackets */
    function handleFileQuit() {
        var closeAllArgs = { promptOnly: false };
        handleFileCloseAll(closeAllArgs)
            .done(function () {
                window.close();  // TODO: call a native API to quit the whole app
            });
        // if fail, don't exit: user canceled (or asked us to save changes first, but we failed to do so)
    }

    /**
     * @private
     * Ensures the suggested file name doesn't already exit.
     * @param {string} dir  The directory to use
     * @param {string} baseFileName  The base to start with, "-n" will get appened to make unique
     * @param {string} fileExt  The file extension
     */
    function _getUntitledFileSuggestion(dir, baseFileName, fileExt) {
        var result = new $.Deferred();
        var suggestedName = baseFileName + fileExt;
        var dirEntry = new NativeFileSystem.DirectoryEntry(dir);

        result.progress(function attemptNewName(suggestedName, nextIndexToUse) {
            if (nextIndexToUse > 99) {
                //we've tried this enough
                result.reject();
                return;
            }

            //check this name
            dirEntry.getFile(
                suggestedName,
                {},
                function successCallback(entry) {
                    //file exists, notify to the next progress
                    result.notify(baseFileName + "-" + nextIndexToUse + fileExt, nextIndexToUse + 1);
                },
                function errorCallback(error) {
                    //most likely error is FNF, user is better equiped to handle the rest
                    result.resolve(suggestedName);
                }
            );
        });

        //kick it off
        result.notify(baseFileName + fileExt, 1);

        return result;
    }

    function showSaveFileError(code, path) {
        return brackets.showModalDialog(
            brackets.DIALOG_ID_ERROR,
            Strings.ERROR_SAVING_FILE_TITLE,
            Strings.format(
                Strings.ERROR_SAVING_FILE,
                path,
                EditorUtils.getFileErrorString(code)
            )
        );
    }

    // Define public API
    exports.init = init;
});

<commit_msg>More jslint cleanup<commit_after>/*
 * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved.
 */

/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, undef: true, indent: 4, maxerr: 50 */
/*global define: false, $: false, brackets: false, PathUtils: false */

define(function (require, exports, module) {
    'use strict';

    require("thirdparty/path-utils/path-utils.min");

    // Load dependent modules
    var CommandManager      = require("CommandManager"),
        Commands            = require("Commands"),
        NativeFileSystem    = require("NativeFileSystem").NativeFileSystem,
        ProjectManager      = require("ProjectManager"),
        DocumentManager     = require("DocumentManager"),
        EditorManager       = require("EditorManager"),
        EditorUtils         = require("EditorUtils"),
        Strings             = require("strings");

    /**
     * Handlers for commands related to file handling (opening, saving, etc.)
     */

    /** @type {jQueryObject} */
    var _title;
    /** @type {string} */
    var _currentFilePath;  // TODO: eliminate this and just use getCurrentDocument().file.fullPath
    /** @type {string} */
    var _currentTitlePath;

    function updateTitle() {
        var currentDoc = DocumentManager.getCurrentDocument();
        if (currentDoc) {
            _title.text(_currentTitlePath + (currentDoc.isDirty ? " \u2022" : ""));
        } else {
            _title.text("");
        }
    }

    function handleCurrentDocumentChange() {
        var newDocument = DocumentManager.getCurrentDocument();

        if (newDocument) {
            var fullPath = newDocument.file.fullPath;

            _currentFilePath = _currentTitlePath = fullPath;

            // In the main toolbar, show the project-relative path (if the file is inside the current project)
            // or the full absolute path (if it's not in the project).
            _currentTitlePath = ProjectManager.makeProjectRelativeIfPossible(fullPath);

        } else {
            _currentFilePath = _currentTitlePath = null;
        }

        // Update title text & "dirty dot" display
        updateTitle();
    }

    function handleDirtyChange(event, changedDoc) {
        if (changedDoc.file.fullPath === _currentFilePath) {
            updateTitle();
        }
    }

    /**
     * @private
     * Creates a document and displays an editor for the specified file path.
     * @return {Deferred} a jQuery Deferred that will be resolved with a new
     *  document for the specified file path, or rejected if the file can not be read.
     */
    function doOpen(fullPath) {

        var result = new $.Deferred();
        if (!fullPath) {
            console.log("doOpen() called without fullPath");
            return result.reject();
        }

        var doc = DocumentManager.getDocumentForPath(fullPath);
        if (doc) {
            // File already open - don't need to load it, just switch to it in the UI
            DocumentManager.showInEditor(doc);
            result.resolve(doc);

        } else {
            // File wasn't open before, so we must create a new document for it
            var fileEntry = new NativeFileSystem.FileEntry(fullPath);
            var docResult = EditorManager.createDocumentAndEditor(fileEntry);

            docResult.done(function (doc) {
                DocumentManager.showInEditor(doc);
                result.resolve(doc);
            });

            docResult.fail(function (error) {
                EditorUtils.showFileOpenError(error.code, fullPath);
                result.reject();
            });
        }

        return result;
    }

    /**
     * @private
     * Creates a document and displays an editor for the specified file path.
     * If no path is specified, a file prompt is provided for input.
     * @return {Deferred} a jQuery Deferred that will be resolved with a new
     *  document for the specified file path, or rejected if the file can not be read.
     */
    function doOpenWithOptionalPath(fullPath) {
        var result;
        if (!fullPath) {
            // Prompt the user with a dialog
            // TODO: we're relying on this to not be asynchronous--is that safe?
            NativeFileSystem.showOpenDialog(false, false, Strings.OPEN_FILE, ProjectManager.getProjectRoot().fullPath,
                ["htm", "html", "js", "css"], function (files) {
                    if (files.length > 0) {
                        result = doOpen(files[0]);
                        return;
                    }
                });
        } else {
            result = doOpen(fullPath);
        }
        if (!result) {
            result = (new $.Deferred()).reject();
        }
        return result;
    }

    function handleFileOpen(commandData) {
        var fullPath = null;
        if (commandData) {
            fullPath = commandData.fullPath;
        }

        var result = doOpenWithOptionalPath(fullPath);
        result.always(function () {
            EditorManager.focusEditor();
        });
        return result;
    }

    function handleFileAddToWorkingSet(commandData) {
        handleFileOpen(commandData).done(function (doc) {
            DocumentManager.addToWorkingSet(doc);
        });
    }

    /**
     * @private
     * Ensures the suggested file name doesn't already exit.
     * @param {string} dir  The directory to use
     * @param {string} baseFileName  The base to start with, "-n" will get appened to make unique
     * @param {string} fileExt  The file extension
     */
    function _getUntitledFileSuggestion(dir, baseFileName, fileExt) {
        var result = new $.Deferred();
        var suggestedName = baseFileName + fileExt;
        var dirEntry = new NativeFileSystem.DirectoryEntry(dir);

        result.progress(function attemptNewName(suggestedName, nextIndexToUse) {
            if (nextIndexToUse > 99) {
                //we've tried this enough
                result.reject();
                return;
            }

            //check this name
            dirEntry.getFile(
                suggestedName,
                {},
                function successCallback(entry) {
                    //file exists, notify to the next progress
                    result.notify(baseFileName + "-" + nextIndexToUse + fileExt, nextIndexToUse + 1);
                },
                function errorCallback(error) {
                    //most likely error is FNF, user is better equiped to handle the rest
                    result.resolve(suggestedName);
                }
            );
        });

        //kick it off
        result.notify(baseFileName + fileExt, 1);

        return result;
    }

    function handleFileNewInProject() {
        // Determine the directory to put the new file
        // If a file is currently selected, put it next to it.
        // If a directory is currently selected, put it in it.
        // If nothing is selected, put it at the root of the project
        var baseDir,
            selected = ProjectManager.getSelectedItem() || ProjectManager.getProjectRoot();

        baseDir = selected.fullPath;
        if (selected.isFile) {
            baseDir = baseDir.substr(0, baseDir.lastIndexOf("/"));
        }

        // Create the new node. The createNewItem function does all the heavy work
        // of validating file name, creating the new file and selecting.
        var deferred = _getUntitledFileSuggestion(baseDir, "Untitled", ".js");
        var createWithSuggestedName = function (suggestedName) {
            ProjectManager.createNewItem(baseDir, suggestedName, false).pipe(deferred.resolve, deferred.reject, deferred.notify);
        };

        deferred.done(createWithSuggestedName);
        deferred.fail(function createWithDefault() { createWithSuggestedName("Untitled.js"); });
        return deferred;
    }

    function showSaveFileError(code, path) {
        return brackets.showModalDialog(
            brackets.DIALOG_ID_ERROR,
            Strings.ERROR_SAVING_FILE_TITLE,
            Strings.format(
                Strings.ERROR_SAVING_FILE,
                path,
                EditorUtils.getFileErrorString(code)
            )
        );
    }

    function doSave(docToSave) {
        var result = new $.Deferred();

        if (docToSave && docToSave.isDirty) {
            var fileEntry = docToSave.file;

            //setup our resolve and reject handlers
            result.done(function fileSaved() {
                docToSave.notifySaved();
            });

            result.fail(function fileError(error) {
                showSaveFileError(error.code, fileEntry.fullPath);
            });

            fileEntry.createWriter(
                function (writer) {
                    writer.onwriteend = function () {
                        result.resolve();
                    };
                    writer.onerror = function (error) {
                        result.reject(error);
                    };

                    // TODO (jasonsj): Blob instead of string
                    writer.write(docToSave.getText());
                },
                function (error) {
                    result.reject(error);
                }
            );
        } else {
            result.resolve();
        }
        result.always(function () {
            EditorManager.focusEditor();
        });
        return result;
    }

    function handleFileSave() {
        return doSave(DocumentManager.getCurrentDocument());
    }

    /**
     * Saves all unsaved documents. Returns a Promise that will be resolved once ALL the save
     * operations have been completed. If any ONE save operation fails, an error dialog is immediately
     * shown and the promise fails.
     * TODO: But subsequent save operations continue in the background, and if more fail the error
     * dialogs will stack up on top of the old one.
     *
     * @return {$.Promise}
     */
    function saveAll() {
        var saveResults = [];

        DocumentManager.getWorkingSet().forEach(function (doc) {
            saveResults.push(doSave(doc));
        });

        // Aggregate all the file-save Deferreds into one master
        // (p.s., it would be nice if $.when() accepted an array instead of varargs, but oh well...)
        var overallResult = $.when.apply($, saveResults);

        return overallResult;
    }

    /**
     * Closes the specified document. Prompts user about saving file if document is dirty.
     *
     * @param {?{doc: Document}} commandData  Document to close; assumes the current document if null.
     * @param {boolean} promptOnly  If true, only displays the relevant confirmation UI and does NOT
     *          actually close the document. This is useful when chaining file-close together with
     *          other user prompts that may be cancelable.
     * @return {$.Deferred}
     */
    function handleFileClose(commandData) {
        var doc = null;
        if (commandData) {
            doc = commandData.doc;
        }

        // utility function for handleFileClose: closes document & removes from working set
        function doClose(doc) {
            if (!commandData || !commandData.promptOnly) {
                // This selects a different document if the working set has any other options
                DocumentManager.closeDocument(doc);

                EditorManager.focusEditor();
            }
        }

        var result = new $.Deferred();

        // Default to current document if doc is null
        if (!doc) {
            doc = DocumentManager.getCurrentDocument();
        }

        // No-op if called when nothing is open; TODO: should command be grayed out instead?
        if (!doc) {
            return;
        }

        if (doc.isDirty) {
            var filename = PathUtils.parseUrl(doc.file.fullPath).filename;

            brackets.showModalDialog(
                brackets.DIALOG_ID_SAVE_CLOSE,
                Strings.SAVE_CLOSE_TITLE,
                Strings.format(Strings.SAVE_CLOSE_MESSAGE, filename)
            ).done(function (id) {
                if (id === brackets.DIALOG_BTN_CANCEL) {
                    result.reject();
                } else if (id === brackets.DIALOG_BTN_OK) {
                    doSave(doc)
                        .done(function () {
                            doClose(doc);
                            result.resolve();
                        })
                        .fail(function () {
                            result.reject();
                        });
                } else {
                    // This is the "Don't Save" case--we can just go ahead and close the file.
                    doClose(doc);
                    result.resolve();
                }
            });
            result.always(function () {
                EditorManager.focusEditor();
            });
        } else {
            // Doc is not dirty, just close
            doClose(doc);
            EditorManager.focusEditor();
            result.resolve();
        }
        return result;
    }

    /**
     * Closes all open documents; equivalent to calling handleFileClose() for each document, except
     * that unsaved changes are confirmed once, in bulk.
     * @param {?{promptOnly: boolean}}  If true, only displays the relevant confirmation UI and does NOT
     *          actually close any documents. This is useful when chaining close-all together with
     *          other user prompts that may be cancelable.
     * @return {$.Deferred}
     */
    function handleFileCloseAll(commandData) {
        var result = new $.Deferred();

        var unsavedDocs = DocumentManager.getWorkingSet().filter(function (doc) {
            return doc.isDirty;
        });

        if (unsavedDocs.length === 0) {
            // No unsaved changes, so we can proceed without a prompt
            result.resolve();

        } else if (unsavedDocs.length === 1) {
            // Only one unsaved file: show the usual single-file-close confirmation UI
            var fileCloseArgs = { doc: unsavedDocs[0], promptOnly: commandData.promptOnly };
            handleFileClose(fileCloseArgs).done(function () {
                // still need to close any other, non-unsaved documents
                result.resolve();
            }).fail(function () {
                result.reject();
            });

        } else {
            // Multiple unsaved files: show a single bulk prompt listing all files
            var message = Strings.SAVE_CLOSE_MULTI_MESSAGE;

            message += "
";
            unsavedDocs.forEach(function (doc) {
                message += "
" + ProjectManager.makeProjectRelativeIfPossible(doc.file.fullPath) + "
";
            });
            message += "
";

            brackets.showModalDialog(
                brackets.DIALOG_ID_SAVE_CLOSE,
                Strings.SAVE_CLOSE_TITLE,
                message
            ).done(function (id) {
                if (id === brackets.DIALOG_BTN_CANCEL) {
                    result.reject();
                } else if (id === brackets.DIALOG_BTN_OK) {
                    // Save all unsaved files, then if that succeeds, close all
                    saveAll().done(function () {
                        result.resolve();
                    }).fail(function () {
                        result.reject();
                    });
                } else {
                    // "Don't Save" case--we can just go ahead and close all  files.
                    result.resolve();
                }
            });
        }

        // If all the unsaved-changes confirmations pan out above, then go ahead & close all editors
        // NOTE: this still happens before any done() handlers added by our caller, because jQ
        // guarantees that handlers run in the order they are added.
        result.done(function () {
            if (!commandData || !commandData.promptOnly) {
                DocumentManager.closeAll();
            }
        });

        return result;
    }

    /** Confirms any unsaved changes, then exits Brackets */
    function handleFileQuit() {
        var closeAllArgs = { promptOnly: false };
        handleFileCloseAll(closeAllArgs)
            .done(function () {
                window.close();  // TODO: call a native API to quit the whole app
            });
        // if fail, don't exit: user canceled (or asked us to save changes first, but we failed to do so)
    }

    function init(title) {
        _title = title;

        // Register global commands
        CommandManager.register(Commands.FILE_OPEN, handleFileOpen);
        CommandManager.register(Commands.FILE_ADD_TO_WORKING_SET, handleFileAddToWorkingSet);
        // TODO: For now, hook up File > New to the "new in project" handler. Eventually
        // File > New should open a new blank tab, and handleFileNewInProject should
        // be called from a "+" button in the project
        CommandManager.register(Commands.FILE_NEW, handleFileNewInProject);
        CommandManager.register(Commands.FILE_SAVE, handleFileSave);
        CommandManager.register(Commands.FILE_CLOSE, handleFileClose);
        CommandManager.register(Commands.FILE_CLOSE_ALL, handleFileCloseAll);
        CommandManager.register(Commands.FILE_QUIT, handleFileQuit);

        $(DocumentManager).on("dirtyFlagChange", handleDirtyChange);
        $(DocumentManager).on("currentDocumentChange", handleCurrentDocumentChange);
    }

    // Define public API
    exports.init = init;
});

<|endoftext|>


<commit_before>window.charts = window.charts || {};

charts.graphUrl; // /v1/users/... without query params
charts.dataPoints = [];

var getEventsFor = function (type
                            , typeId
                            , objectTags
                            , actionTags
                            , operation
                            , period
                            , shareToken
                            , readToken
                            , fromDate
                            , toDate) {
    var url = "/v1/"
            + type + "/" + typeId
            + "/events/" + objectTags
            + "/" + actionTags
            + "/" + operation
            + "/" + period + "/" + "type/json"
            + "?"
            + (fromDate ? "from=" + fromDate + "&" : "")
            + (toDate ? "to=" + toDate + "&" : "");
    return $.ajax({
        url: url,
        data: {
            shareToken: shareToken,
            readToken: readToken
        },
        headers: {
            "Accept": "application/json",
            "Authorization": $.cookie("_eun")
        }
    });
};

var plotChart = function (events) {
    if (renderType === "barchart") {
        if (events === null || events.length == 0) {
            $(".no-data").show();
        } else {
            charts.plotBarChart("#chart", events, fromDate, toDate);
            $('.detailsSection').show();
            $('.share-button-container').show();
        }
    }
};

charts.addComment = function () {
    var commentText = $("#commentText").val();

    if ("" == commentText.trim()) return;

    var comment = {
        text: commentText,
        user: username,
        avatarUrl: avatarUrl
    };
    var graph = {
        graphUrl: charts.graphUrl,
        dataPointDate: charts.selectedDate,
        username: graphOwner,
        objectTags: objectTags,
        actionTags: actionTags,
        operation: operation,
        period: period,
        renderType: renderType,
        comment: comment
    };

    //disable further commenting until current one completes
    $('#commentAddButton').attr('disabled', 'disabled');
    $('#addText').hide();
    $('.sending_comment_loader').show();

    $.ajax({
        url: "/v1/comments",
        method: "POST",
        data: graph,
        headers: {
            "Accept": "application/json",
            "Authorization": $.cookie("_eun")
        }
    }).done(function (data) {
        //enable the add button
        $('#commentAddButton').removeAttr('disabled');
        $('#addText').show();
        $('.sending_comment_loader').hide();

        var displayedComment = {text: commentText, avatarUrl: graphOwnerAvatarUrl};
        var selectedDataPoint = _.find(charts.dataPoints, function (dataPoint) {
            return dataPoint.dataPointDate === charts.selectedDate;
        });
        if (_.isEmpty(selectedDataPoint)) {
            var newDataPoint = {
                dataPointDate: charts.selectedDate,
                avatars: [graphOwnerAvatarUrl],
                comments: [displayedComment]
            };
            charts.dataPoints.push(newDataPoint);
        } else {
            selectedDataPoint.comments.push(displayedComment);
        }
        $(".commentList").append("

" +
            "

" + comment.text + "
" +
            "

");
        $("#commentText").val("");
    });
};

$("#addCommentInput").keyup(function (e) {
    if (e.keyCode == 13) {
        charts.addComment();
    }
});

var handleAddComment = function () {
    if (isUserLoggedIn) {
        $("#addCommentInput").show();
    }
    else {
        window.localStorage.selectedDate = charts.selectedDate;
        $("#loginModal").modal({show: true});
    }
};

var handleShareGraph = function () {
    var unregisteredUserOnStreamsPage = function () {
        return !isUserLoggedIn && (window.location.pathname.search("streams") !== -1);
    };

    if (isUserLoggedIn) {
        $.ajax({
            url: "/v1/graph/share",
            data: {
                graphUrl: window.location.pathname,
                bgColor: getBackgroundColor(),
                from: fromDate,
                to: toDate
            },
            success: function (data) {
                $("#shareModal").modal({show: true});
                $("#loadingDiv").hide();
                var link = window.location.origin + data.graphShareUrl;
                var graphShareLink = " " + link + " ";
                $("#graphShareHyperLink").html(graphShareLink);
                $("#graphShareLink").html(link);
                $("#shareModal").modal({show: true});
            },
            error: function () {
                alert("some problem. Please try again later.");
            }
        });
    } else if (unregisteredUserOnStreamsPage()) {
        $("#loginModal").modal({show: true});
    } else {
        $.ajax({
            url: "/v1/graph/share?graphUrl=" + window.location.pathname,
            success: function (data) {
                $("#shareModal").modal({show: true});
                $("#loadingDiv").hide();
                var link = window.location.origin + data.graphShareUrl;
                var graphShareLink = "" + link + "";
                $("#graphShareHyperLink").html(graphShareLink);
                $("#graphShareLink").html(link);
            },
            error: function () {
                alert("some problem. Please try again later.");
            }
        });
    }
};

var showChartTitle = function () {
    $("#chartTitle").html(chartTitle);
    if (isUserLoggedIn) {
        $("#avatar").html("").addClass('avatar');
    }
    if (isUserLoggedIn || (!isUserLoggedIn && !(_.isEmpty(shareToken)))) {
        $.when(getEventsFor("users", graphOwner, objectTags, actionTags, operation, period, shareToken, readToken, fromDate, toDate))
            .done(plotChart)
            .fail();
    } else {
        $.when(getEventsFor("streams", streamId, objectTags, actionTags, operation, period, shareToken, readToken, fromDate, toDate))
            .done(plotChart)
            .fail();
    }
};

var getBackgroundColor = function () {
    var colorFromQueryParam = getParameterByName('bgColor');
    if (colorFromQueryParam && colorFromQueryParam !== 'undefined') {
        return colorFromQueryParam;
    } else {
        return "fdc526";
    }
};

var setBackgroundColor = function () {
    document.body.style.backgroundColor = "#" + getBackgroundColor();
};

var submitShare = function () {
    var emailId = $("#emailId").val();
    var graphShareUrl = $("#graphShareHyperLink a:first-child").attr("href");

    $.ajax({
        url: "/v1/share_graph",
        method: "POST",
        data: { graphShareUrl: graphShareUrl, toEmailId: emailId },
        success: function () {
            $(".shareEmailNoticeMessage").html("Graph link emailed successfully");
        },
        error: function () {
            alert("some problem. Please try again later.");
        }
    });
};

charts.showComments = function () {
    var commentsDiv = $(".commentList");
    commentsDiv.empty();

    charts.dataPoints
        .filter(function (dataPoint) {
            return dataPoint.dataPointDate === charts.selectedDate;
        })
        .forEach(function (dataPoint) {
            dataPoint.comments.forEach(function (comment) {
                commentsDiv.append("

" +
                    "
" + comment.text + "

");
            });
        });
};

var displayCommentsSummary = function () {
    for (var i = 6; i >= 0; i--) {
        var currentDataPointDate = moment(toDate).subtract(1 + i, 'days').format("YYYY-MM-DD"); // "2014-11-14"
        var currentDataPoint = _.findWhere(charts.dataPoints, {"dataPointDate": currentDataPointDate});
        if (!_.isEmpty(currentDataPoint)) {
            var latest3Avatars = currentDataPoint.avatars.slice(0, 3);
            latest3Avatars.forEach(function (avatarUrl, j) {
                $("#group" + i + "-avatar" + j).css({'background-image': 'url(' + avatarUrl + ')'});
            });
            if (currentDataPoint.comments.length > 3) {
                $("#group" + i + "-commentCount").addClass("count").html(currentDataPoint.comments.length);
            }
        }
    }
};

$(document).ready(function () {

    $("#login").click(function () {
        if (window.parent !== window) {
            var parentWindow = window.parent;
            var msg = {
                msgType: 'auth',
                loginUrl: oneselfAppUrl + "/signup",
                oneselfAppUrl: oneselfAppUrl,
                intent: 'chart.comment'
            };
            parentWindow.postMessage(msg, "*");
        } else {
            $("#login").attr('href', '/signup?intent=chart.comment&redirectUrl=' + encodeURIComponent(window.location.href));
        }
    });

    setBackgroundColor();
    showChartTitle();

    var url = "/v1/comments";
    var params = ["from=" + fromDate
                , "to=" + toDate];
    url += "?" + params.join("&");

    $.ajax({
        url: url,
        method: "GET",
        data: {
            username: graphOwner,
            objectTags: objectTags,
            actionTags: actionTags,
            operation: operation,
            period: period,
            renderType: renderType
        },
        headers: {
            "Accept": "application/json",
            "Authorization": $.cookie("_eun")
        }
    }).done(function (comments) {
        charts.dataPoints = comments;
        displayCommentsSummary();
    });
    $("#shareSubmit").click(submitShare);

    var cw = $('.avatar_group').width();
    var ch = $(window).width() * (cw / 100);
    $('.avatar_group').css({'height': ch + 'px'});

    setTimeout(function () {
        charts.showComments();
        if (isUserLoggedIn) {
            if (window.localStorage.selectedDate) {
                delete window.localStorage.selectedDate;
            }
        }
    }, 3000)
});
<commit_msg>fix comment not appearing on correct data point.<commit_after>window.charts = window.charts || {};

charts.graphUrl; // /v1/users/... without query params
charts.dataPoints = [];

var getEventsFor = function (type
                            , typeId
                            , objectTags
                            , actionTags
                            , operation
                            , period
                            , shareToken
                            , readToken
                            , fromDate
                            , toDate) {
    var url = "/v1/"
            + type + "/" + typeId
            + "/events/" + objectTags
            + "/" + actionTags
            + "/" + operation
            + "/" + period + "/" + "type/json"
            + "?"
            + (fromDate ? "from=" + fromDate + "&" : "")
            + (toDate ? "to=" + toDate + "&" : "");
    return $.ajax({
        url: url,
        data: {
            shareToken: shareToken,
            readToken: readToken
        },
        headers: {
            "Accept": "application/json",
            "Authorization": $.cookie("_eun")
        }
    });
};

var plotChart = function (events) {
    if (renderType === "barchart") {
        if (events === null || events.length == 0) {
            $(".no-data").show();
        } else {
            charts.plotBarChart("#chart", events, fromDate, toDate);
            $('.detailsSection').show();
            $('.share-button-container').show();
        }
    }
};

charts.addComment = function () {
    var commentText = $("#commentText").val();

    if ("" == commentText.trim()) return;

    var comment = {
        text: commentText,
        user: username,
        avatarUrl: avatarUrl
    };
    var graph = {
        graphUrl: charts.graphUrl,
        dataPointDate: charts.selectedDate,
        username: graphOwner,
        objectTags: objectTags,
        actionTags: actionTags,
        operation: operation,
        period: period,
        renderType: renderType,
        comment: comment
    };

    //disable further commenting until current one completes
    $('#commentAddButton').attr('disabled', 'disabled');
    $('#addText').hide();
    $('.sending_comment_loader').show();

    $.ajax({
        url: "/v1/comments",
        method: "POST",
        data: graph,
        headers: {
            "Accept": "application/json",
            "Authorization": $.cookie("_eun")
        }
    }).done(function (data) {
        //enable the add button
        $('#commentAddButton').removeAttr('disabled');
        $('#addText').show();
        $('.sending_comment_loader').hide();

        var displayedComment = {text: commentText, avatarUrl: graphOwnerAvatarUrl};
        var selectedDataPoint = _.find(charts.dataPoints, function (dataPoint) {
            return dataPoint.dataPointDate === charts.selectedDate;
        });
        if (_.isEmpty(selectedDataPoint)) {
            var newDataPoint = {
                dataPointDate: charts.selectedDate,
                avatars: [graphOwnerAvatarUrl],
                comments: [displayedComment]
            };
            charts.dataPoints.push(newDataPoint);
        } else {
            selectedDataPoint.comments.push(displayedComment);
        }
        $(".commentList").append("

" +
            "

" + comment.text + "
" +
            "

");
        $("#commentText").val("");
    });
};

$("#addCommentInput").keyup(function (e) {
    if (e.keyCode == 13) {
        charts.addComment();
    }
});

var handleAddComment = function () {
    if (isUserLoggedIn) {
        $("#addCommentInput").show();
    }
    else {
        window.localStorage.selectedDate = charts.selectedDate;
        $("#loginModal").modal({show: true});
    }
};

var handleShareGraph = function () {
    var unregisteredUserOnStreamsPage = function () {
        return !isUserLoggedIn && (window.location.pathname.search("streams") !== -1);
    };

    if (isUserLoggedIn) {
        $.ajax({
            url: "/v1/graph/share",
            data: {
                graphUrl: window.location.pathname,
                bgColor: getBackgroundColor(),
                from: fromDate,
                to: toDate
            },
            success: function (data) {
                $("#shareModal").modal({show: true});
                $("#loadingDiv").hide();
                var link = window.location.origin + data.graphShareUrl;
                var graphShareLink = " " + link + " ";
                $("#graphShareHyperLink").html(graphShareLink);
                $("#graphShareLink").html(link);
                $("#shareModal").modal({show: true});
            },
            error: function () {
                alert("some problem. Please try again later.");
            }
        });
    } else if (unregisteredUserOnStreamsPage()) {
        $("#loginModal").modal({show: true});
    } else {
        $.ajax({
            url: "/v1/graph/share?graphUrl=" + window.location.pathname,
            success: function (data) {
                $("#shareModal").modal({show: true});
                $("#loadingDiv").hide();
                var link = window.location.origin + data.graphShareUrl;
                var graphShareLink = "" + link + "";
                $("#graphShareHyperLink").html(graphShareLink);
                $("#graphShareLink").html(link);
            },
            error: function () {
                alert("some problem. Please try again later.");
            }
        });
    }
};

var showChartTitle = function () {
    $("#chartTitle").html(chartTitle);
    if (isUserLoggedIn) {
        $("#avatar").html("").addClass('avatar');
    }
    if (isUserLoggedIn || (!isUserLoggedIn && !(_.isEmpty(shareToken)))) {
        $.when(getEventsFor("users", graphOwner, objectTags, actionTags, operation, period, shareToken, readToken, fromDate, toDate))
            .done(plotChart)
            .fail();
    } else {
        $.when(getEventsFor("streams", streamId, objectTags, actionTags, operation, period, shareToken, readToken, fromDate, toDate))
            .done(plotChart)
            .fail();
    }
};

var getBackgroundColor = function () {
    var colorFromQueryParam = getParameterByName('bgColor');
    if (colorFromQueryParam && colorFromQueryParam !== 'undefined') {
        return colorFromQueryParam;
    } else {
        return "fdc526";
    }
};

var setBackgroundColor = function () {
    document.body.style.backgroundColor = "#" + getBackgroundColor();
};

var submitShare = function () {
    var emailId = $("#emailId").val();
    var graphShareUrl = $("#graphShareHyperLink a:first-child").attr("href");

    $.ajax({
        url: "/v1/share_graph",
        method: "POST",
        data: { graphShareUrl: graphShareUrl, toEmailId: emailId },
        success: function () {
            $(".shareEmailNoticeMessage").html("Graph link emailed successfully");
        },
        error: function () {
            alert("some problem. Please try again later.");
        }
    });
};

charts.showComments = function () {
    var commentsDiv = $(".commentList");
    commentsDiv.empty();

    charts.dataPoints
        .filter(function (dataPoint) {
            return dataPoint.dataPointDate === charts.selectedDate;
        })
        .forEach(function (dataPoint) {
            dataPoint.comments.forEach(function (comment) {
                commentsDiv.append("

" +
                    "
" + comment.text + "

");
            });
        });
};

var displayCommentsSummary = function () {
    for (var i = 6; i >= 0; i--) {
        var currentDataPointDate = moment.utc(toDate).subtract(i, 'days').format("YYYY-MM-DD"); // "2014-11-14"
        var currentDataPoint = _.findWhere(charts.dataPoints, {"dataPointDate": currentDataPointDate});
        if (!_.isEmpty(currentDataPoint)) {
            var latest3Avatars = currentDataPoint.avatars.slice(0, 3);
            latest3Avatars.forEach(function (avatarUrl, j) {
                $("#group" + i + "-avatar" + j).css({'background-image': 'url(' + avatarUrl + ')'});
            });
            if (currentDataPoint.comments.length > 3) {
                $("#group" + i + "-commentCount").addClass("count").html(currentDataPoint.comments.length);
            }
        }
    }
};

$(document).ready(function () {

    $("#login").click(function () {
        if (window.parent !== window) {
            var parentWindow = window.parent;
            var msg = {
                msgType: 'auth',
                loginUrl: oneselfAppUrl + "/signup",
                oneselfAppUrl: oneselfAppUrl,
                intent: 'chart.comment'
            };
            parentWindow.postMessage(msg, "*");
        } else {
            $("#login").attr('href', '/signup?intent=chart.comment&redirectUrl=' + encodeURIComponent(window.location.href));
        }
    });

    setBackgroundColor();
    showChartTitle();

    var url = "/v1/comments";
    var params = ["from=" + fromDate
                , "to=" + toDate];
    url += "?" + params.join("&");

    $.ajax({
        url: url,
        method: "GET",
        data: {
            username: graphOwner,
            objectTags: objectTags,
            actionTags: actionTags,
            operation: operation,
            period: period,
            renderType: renderType
        },
        headers: {
            "Accept": "application/json",
            "Authorization": $.cookie("_eun")
        }
    }).done(function (comments) {
        charts.dataPoints = comments;
        displayCommentsSummary();
    });
    $("#shareSubmit").click(submitShare);

    var cw = $('.avatar_group').width();
    var ch = $(window).width() * (cw / 100);
    $('.avatar_group').css({'height': ch + 'px'});

    setTimeout(function () {
        charts.showComments();
        if (isUserLoggedIn) {
            if (window.localStorage.selectedDate) {
                delete window.localStorage.selectedDate;
            }
        }
    }, 3000)
});
<|endoftext|>


<commit_before>'use strict';

var app = angular.module('directory', ['ngRoute', 'infinite-scroll', 'ui.bootstrap', 'directoryControllers']);
app.config([
  '$routeProvider',
  function ($routeProvider) {
    $routeProvider.
      when('/recent', {
        templateUrl: 'browser/js/partials/badge-list.html',
        controller: 'RecentController'
      }).
      when('/search', {
        templateUrl: 'browser/js/partials/badge-list.html',
        controller: 'SearchController'
      }).
      when('/get', {
        templateUrl: 'browser/js/partials/badge-list.html',
        controller: 'GetController'
      }).
      when('/badge-class/:id', {
        templateUrl: 'browser/js/partials/badge-class.html',
        controller: 'GetController'
      }).
      otherwise({
        redirectTo: '/recent'
      })
  }
]);
app.directive('cancelClick', function () {
  return function(scope, element, attrs) {
    element.bind('click', function (e) {
      e.preventDefault && e.preventDefault();
      e.stopPropagation();
    });
  };
});
app.directive('ngEnter', function () {
  return function (scope, element, attrs) {
    element.bind("keydown keypress", function (event) {
      if(event.which === 13) {
        scope.$apply(function (){
          scope.$eval(attrs.ngEnter);
        });

        event.preventDefault();
      }
    });
  };
});<commit_msg>server<commit_after>'use strict';

var app = angular.module('directory', ['ngRoute', 'infinite-scroll', 'ui.bootstrap', 'directoryControllers']);
app.config([
  '$routeProvider',
  function ($routeProvider) {
    $routeProvider.
      when('/recent', {
        templateUrl: 'js/partials/badge-list.html',
        controller: 'RecentController'
      }).
      when('/search', {
        templateUrl: 'js/partials/badge-list.html',
        controller: 'SearchController'
      }).
      when('/get', {
        templateUrl: 'js/partials/badge-list.html',
        controller: 'GetController'
      }).
      when('/badge-class/:id', {
        templateUrl: 'js/partials/badge-class.html',
        controller: 'GetController'
      }).
      otherwise({
        redirectTo: '/recent'
      })
  }
]);
app.directive('cancelClick', function () {
  return function(scope, element, attrs) {
    element.bind('click', function (e) {
      e.preventDefault && e.preventDefault();
      e.stopPropagation();
    });
  };
});
app.directive('ngEnter', function () {
  return function (scope, element, attrs) {
    element.bind("keydown keypress", function (event) {
      if(event.which === 13) {
        scope.$apply(function (){
          scope.$eval(attrs.ngEnter);
        });

        event.preventDefault();
      }
    });
  };
});<|endoftext|>


<commit_before>(function () {
	var currentDirection,
		currentYOffset,
		currentXOffset,
		previousYDirection,
		previousXDirection,
		previousYOffset = window.pageYOffset,
		previousXOffset = window.pageXOffset,
		scrollDownEvent,
		scrollUpEvent,
		scrollLeftEvent,
		scrollRightEvent,
		scrollDownStartEvent,
		scrollUpStartEvent,
		scrollLeftStartEvent,
		scrollRightStartEvent;

	// Initialize events
	try {
		scrollDownEvent = new Event('scrolldown');
		scrollUpEvent = new Event('scrollup');
		scrollLeftEvent = new Event('scrollleft');
		scrollRightEvent = new Event('scrollright');
		scrollDownStartEvent = new Event('scrolldownstart');
		scrollUpStartEvent = new Event('scrollupstart');
		scrollLeftStartEvent = new Event('scrollleftstart');
		scrollRightStartEvent = new Event('scrollrightstart');
	} catch (e) {
		// No browser support for Event constructor, use
		// the old-fashioned way :(

		scrollDownEvent = document.createEvent('Event');
		scrollUpEvent = document.createEvent('Event');
		scrollLeftEvent = document.createEvent('Event');
		scrollRightEvent = document.createEvent('Event');
		scrollDownStartEvent = document.createEvent('Event');
		scrollUpStartEvent = document.createEvent('Event');
		scrollLeftStartEvent = document.createEvent('Event');
		scrollRightStartEvent = document.createEvent('Event');

		scrollDownEvent.initEvent('scrolldown', true, true);
		scrollUpEvent.initEvent('scrollup', true, true);
		scrollLeftEvent.initEvent('scrollleft', true, true);
		scrollRightEvent.initEvent('scrollright', true, true);
		scrollDownStartEvent.initEvent('scrolldownstart', true, true);
		scrollUpStartEvent.initEvent('scrollupstart', true, true);
		scrollLeftStartEvent.initEvent('scrollleftstart', true, true);
		scrollRightStartEvent.initEvent('scrollrightstart', true, true);
	}

	/**
	 * Trigger additional scroll events.
	 *
	 * @param Event  event  The original scroll event
	 */
	function onScroll(event) {
		currentYOffset = window.pageYOffset;
		currentXOffset = window.pageXOffset;

		// Determine the current scroll direction (Y-axis)
		if (currentYOffset < previousYOffset) {
			currentYDirection = 'up';
		} else if (currentYOffset > previousYOffset) {
			currentYDirection = 'down';
		} else {
			currentYDirection = undefined;
		}

		// Determine the current scroll direction (X-axis)
		if (currentXOffset < previousXOffset) {
			currentXDirection = 'left';
		} else if (currentXOffset > previousXOffset) {
			currentXDirection = 'right';
		} else {
			currentXDirection = undefined;
		}

		// Has the scroll direction changed since the last scroll? (Y-axis)
		if (currentYDirection !== previousYDirection) {
			if (currentYDirection === 'up') {
				window.dispatchEvent(scrollUpStartEvent);
			} else if (currentYDirection === 'down') {
				window.dispatchEvent(scrollDownStartEvent);
			}
		}

		// Has the scroll direction changed since the last scroll? (X-axis)
		if (currentXDirection !== previousXDirection) {
			if (currentXDirection === 'left') {
				window.dispatchEvent(scrollLeftStartEvent);
			} else if (currentXDirection === 'right') {
				window.dispatchEvent(scrollRightStartEvent);
			}
		}

		if (currentYDirection === 'up') {
			window.dispatchEvent(scrollUpEvent);
		} else if (currentYDirection === 'down') {
			window.dispatchEvent(scrollDownEvent);
		}

		if (currentXDirection === 'left') {
			window.dispatchEvent(scrollLeftEvent);
		} else if (currentXDirection === 'down') {
			window.dispatchEvent(scrollRightEvent);
		}

		previousYDirection = currentYDirection;
		previousXDirection = currentXDirection;
		previousYOffset = currentYOffset;
		previousXOffset = currentXOffset;
	}

	window.addEventListener('scroll', onScroll, false);
})();
<commit_msg>Fix direction variables.<commit_after>(function () {
	var currentYDirection,
		currentXDirection,
		currentYOffset,
		currentXOffset,
		previousYDirection,
		previousXDirection,
		previousYOffset = window.pageYOffset,
		previousXOffset = window.pageXOffset,
		scrollDownEvent,
		scrollUpEvent,
		scrollLeftEvent,
		scrollRightEvent,
		scrollDownStartEvent,
		scrollUpStartEvent,
		scrollLeftStartEvent,
		scrollRightStartEvent;

	// Initialize events
	try {
		scrollDownEvent = new Event('scrolldown');
		scrollUpEvent = new Event('scrollup');
		scrollLeftEvent = new Event('scrollleft');
		scrollRightEvent = new Event('scrollright');
		scrollDownStartEvent = new Event('scrolldownstart');
		scrollUpStartEvent = new Event('scrollupstart');
		scrollLeftStartEvent = new Event('scrollleftstart');
		scrollRightStartEvent = new Event('scrollrightstart');
	} catch (e) {
		// No browser support for Event constructor, use
		// the old-fashioned way :(

		scrollDownEvent = document.createEvent('Event');
		scrollUpEvent = document.createEvent('Event');
		scrollLeftEvent = document.createEvent('Event');
		scrollRightEvent = document.createEvent('Event');
		scrollDownStartEvent = document.createEvent('Event');
		scrollUpStartEvent = document.createEvent('Event');
		scrollLeftStartEvent = document.createEvent('Event');
		scrollRightStartEvent = document.createEvent('Event');

		scrollDownEvent.initEvent('scrolldown', true, true);
		scrollUpEvent.initEvent('scrollup', true, true);
		scrollLeftEvent.initEvent('scrollleft', true, true);
		scrollRightEvent.initEvent('scrollright', true, true);
		scrollDownStartEvent.initEvent('scrolldownstart', true, true);
		scrollUpStartEvent.initEvent('scrollupstart', true, true);
		scrollLeftStartEvent.initEvent('scrollleftstart', true, true);
		scrollRightStartEvent.initEvent('scrollrightstart', true, true);
	}

	/**
	 * Trigger additional scroll events.
	 *
	 * @param Event  event  The original scroll event
	 */
	function onScroll(event) {
		currentYOffset = window.pageYOffset;
		currentXOffset = window.pageXOffset;

		// Determine the current scroll direction (Y-axis)
		if (currentYOffset < previousYOffset) {
			currentYDirection = 'up';
		} else if (currentYOffset > previousYOffset) {
			currentYDirection = 'down';
		} else {
			currentYDirection = undefined;
		}

		// Determine the current scroll direction (X-axis)
		if (currentXOffset < previousXOffset) {
			currentXDirection = 'left';
		} else if (currentXOffset > previousXOffset) {
			currentXDirection = 'right';
		} else {
			currentXDirection = undefined;
		}

		// Has the scroll direction changed since the last scroll? (Y-axis)
		if (currentYDirection !== previousYDirection) {
			if (currentYDirection === 'up') {
				window.dispatchEvent(scrollUpStartEvent);
			} else if (currentYDirection === 'down') {
				window.dispatchEvent(scrollDownStartEvent);
			}
		}

		// Has the scroll direction changed since the last scroll? (X-axis)
		if (currentXDirection !== previousXDirection) {
			if (currentXDirection === 'left') {
				window.dispatchEvent(scrollLeftStartEvent);
			} else if (currentXDirection === 'right') {
				window.dispatchEvent(scrollRightStartEvent);
			}
		}

		if (currentYDirection === 'up') {
			window.dispatchEvent(scrollUpEvent);
		} else if (currentYDirection === 'down') {
			window.dispatchEvent(scrollDownEvent);
		}

		if (currentXDirection === 'left') {
			window.dispatchEvent(scrollLeftEvent);
		} else if (currentXDirection === 'down') {
			window.dispatchEvent(scrollRightEvent);
		}

		previousYDirection = currentYDirection;
		previousXDirection = currentXDirection;
		previousYOffset = currentYOffset;
		previousXOffset = currentXOffset;
	}

	window.addEventListener('scroll', onScroll, false);
})();
<|endoftext|>


<commit_before>import {isArray} from '@grid/core/utility';
import {Command} from '@grid/core/infrastructure';
import {SelectionService} from '@grid/core/selection';

ReferenceEdit.$inject = ['$scope', 'qgrid', 'qGridPopupService'];
export default function ReferenceEdit($scope, qgrid, popupService) {
	this.cell = () => $scope.$editor || $scope.$view.edit.cell;

	const id = 'q-grid-reference-popup';
	const close = () => {
		if ($scope.$popup && popupService.isOpened(id)) {
			$scope.$popup.close();
		}
	};

	const options = this.cell().options;
	this.gridModel = (options
		&& options.modelFactory
		&& options.modelFactory($scope.$view ? $scope.$view.model.navigation() : {}))
		|| qgrid.model();

	const dataChangedOff = this.gridModel.dataChanged.watch(e => {
		if (e.hasChanges('rows') && e.state.rows.length > 0) {
			const cell = this.cell();
			this.gridModel.selection({
				items: isArray(cell.value) ? cell.value : [cell.value]
			});

			dataChangedOff();
		}
	});

	const commands = {
		commit: new Command({
			shortcut: 'ctrl+s',
			execute: ($cell, $event) => {
				const model = this.gridModel;
				const selectionItems = model.selection().items;
				const entries = new SelectionService(model).lookup(selectionItems);

				const cell = this.cell();
				cell.value = model.selection().items;
				cell.tag = {
					entries: entries,
					columns: model.data().columns
				};
				cell.commit.execute($cell, $event);

				close();
			}
		}),
		cancel: new Command({
			shortcut: 'Escape',
			execute: ($cell, $event) => {
				this.cell().cancel.execute($cell, $event);
				close();
			}
		})
	};

	this.commit = commands.commit;

	this.cancel = commands.cancel;

	const shortcutOff = $scope.$popupBody.shortcut.register('referenceEditManagement', new Map(
		Object.entries(commands)
	));

	$scope.$on('$destroy', () => {
		shortcutOff();
		close();
	});
}<commit_msg>watch selection in reference editor<commit_after>import {isArray, noop} from '@grid/core/utility';
import {Command} from '@grid/core/infrastructure';
import {SelectionService} from '@grid/core/selection';

ReferenceEdit.$inject = ['$scope', 'qgrid', 'qGridPopupService'];
export default function ReferenceEdit($scope, qgrid, popupService) {
	this.cell = () => $scope.$editor || $scope.$view.edit.cell;

	const id = 'q-grid-reference-popup';
	const close = () => {
		if ($scope.$popup && popupService.isOpened(id)) {
			$scope.$popup.close();
		}
	};

	const options = this.cell().options;
	this.gridModel = (options
		&& options.modelFactory
		&& options.modelFactory($scope.$view ? $scope.$view.model.navigation() : {}))
		|| qgrid.model();

	const watchSelection = e => {
		if (e.hasChanges('items')) {
			const model = this.gridModel;
			const selectionItems = model.selection().items;
			const entries = new SelectionService(model).lookup(selectionItems);

			const cell = this.cell();
			cell.value = selectionItems;
			cell.tag = {
				entries: entries,
				columns: model.data().columns
			};
		}
	};

	const dataChangedOff = this.gridModel.dataChanged.watch(e => {
		if (e.hasChanges('rows') && e.state.rows.length > 0) {
			const cell = this.cell();
			this.gridModel.selection({
				items: isArray(cell.value) ? cell.value : [cell.value]
			});

			this.gridModel.selectionChanged.watch(watchSelection);

			dataChangedOff();
		}
	});

	const commands = {
		commit: new Command({
			shortcut: 'ctrl+s',
			execute: ($cell, $event) => {
				this.cell().commit.execute($cell, $event);
				close();
			}
		}),
		cancel: new Command({
			shortcut: 'Escape',
			execute: ($cell, $event) => {
				this.cell().cancel.execute($cell, $event);
				close();
			}
		})
	};

	this.commit = commands.commit;

	this.cancel = commands.cancel;

	const shortcutOff = popupService.isOpened(id)
		? $scope.$popupBody.shortcut.register('referenceEditManagement', new Map(
			Object.entries(commands)
		))
		: noop;

	$scope.$on('$destroy', () => {
		shortcutOff();
		close();
	});
}<|endoftext|>


<commit_before>import "../src/overrides.css";
import axios from "axios";
import Cookie from "js-cookie";

document.addEventListener("DOMContentLoaded", () => {
  (function checkVersion() {
    var topLevel = window.location.hostname.split(".")[2];

    axios
      .get(
        `${window.location.protocol}//api.comeals.${topLevel}/api/v1/version`
      )
      .then(function(response) {
        if (response.status === 200) {
          var clientVersion = response.data.version;
          var serverVersion = Cookie.get("version");

          if (typeof serverVersion === "undefined") {
            Cookie.set("version", clientVersion, {
              expires: 7300,
              domain: `.comeals.${topLevel}`
            });

            // update the ui
            var element = document.getElementById("version");
            element.innerHTML = `v${clientVersion}`;
          } else if (String(clientVersion) !== String(serverVersion)) {
            window.location.reload(true);
          }
        }
      })
      .catch(function(error) {
        if (error.response) {
          // The request was made and the server responded with a status code
          // that falls out of the range of 2xx
          const data = error.response.data;
          const status = error.response.status;
          const headers = error.response.headers;

          console.error("Unable to load version.");
        } else if (error.request) {
          // The request was made but no response was received
          // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
          // http.ClientRequest in node.js
          const request = error.request;
        } else {
          // Something happened in setting up the request that triggered an Error
          const message = error.message;
        }
        const config = error.config;
      });

    window.setTimeout(checkVersion, 1800000);
  })();
});
<commit_msg>Change where version is put in DOM<commit_after>import "../src/overrides.css";
import axios from "axios";
import Cookie from "js-cookie";

document.addEventListener("DOMContentLoaded", () => {
  (function checkVersion() {
    var topLevel = window.location.hostname.split(".")[2];

    axios
      .get(
        `${window.location.protocol}//api.comeals.${topLevel}/api/v1/version`
      )
      .then(function(response) {
        if (response.status === 200) {
          var clientVersion = response.data.version;
          var serverVersion = Cookie.get("version");

          // update the ui
          var element = document.getElementById("version");
          element.innerHTML = `v${clientVersion}`;

          if (typeof serverVersion === "undefined") {
            Cookie.set("version", clientVersion, {
              expires: 7300,
              domain: `.comeals.${topLevel}`
            });
          } else if (String(clientVersion) !== String(serverVersion)) {
            window.location.reload(true);
          }
        }
      })
      .catch(function(error) {
        if (error.response) {
          // The request was made and the server responded with a status code
          // that falls out of the range of 2xx
          const data = error.response.data;
          const status = error.response.status;
          const headers = error.response.headers;

          console.error("Unable to load version.");
        } else if (error.request) {
          // The request was made but no response was received
          // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
          // http.ClientRequest in node.js
          const request = error.request;
        } else {
          // Something happened in setting up the request that triggered an Error
          const message = error.message;
        }
        const config = error.config;
      });

    window.setTimeout(checkVersion, 1800000);
  })();
});
<|endoftext|>


<commit_before>define(["mathjax"], function() {

	// Allow labels and numbers to be reset:
	// https://groups.google.com/forum/#!msg/mathjax-users/kzOOFw1qtxw/YdAEPJfCEXUJ

	MathJax.resetLabels = function() {
		//var AMS = MathJax.Extension["TeX/AMSmath"];
		//AMS.startNumber = 0;
		//AMS.labels = {};
	}

	// Allow inline maths with single $s

	MathJax.Hub.Config({
		tex2jax: {
		inlineMath: [ ['$','$'], ["\\(","\\)"] ],
		displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
		processEscapes: true,
		},
		TeX: {
			Macros: {
				// See http://docs.mathjax.org/en/latest/tex.html#defining-tex-macros
				"quantity": ["{#1}\\,{\\rm{#2}}",2],
				"valuedef": ["{#1}={\\quantity{#2}{#3}}",3],
				"vtr": ["{\\underline{\\boldsymbol{#1}}}",1],
				"d": "\\operatorname{d}",
				"vari": ["#1",1],
				"s": ["_{\\sf{#1}}", 1],
				"half": ["\\frac{1}{2}",0],
				"third": ["\\frac{1}{3}",0],
				"quarter": ["\\frac{1}{4}",0],
				"eighth": ["\\frac{1}{8}",0],
				"e": ["\\textrm{e}",0],
			}
		},
	});

	// Fix font issues in Chrome 32
	// https://groups.google.com/forum/#!msg/mathjax-users/S5x-RQDPJrI/p4nmRXJvoskJ

	MathJax.Hub.Config({
		extensions: ["MatchWebFonts.js"]
	});

	if (MathJax.Hub.Browser.isChrome) {
		MathJax.Hub.Register.StartupHook(
			"HTML-CSS Jax Config",
			function () {MathJax.OutputJax["HTML-CSS"].FontFaceBug = true}
		);
	}

});

// Here is a very useful page:

// http://meta.math.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference<commit_msg>Add \units MathJax definition.<commit_after>define(["mathjax"], function() {

	// Allow labels and numbers to be reset:
	// https://groups.google.com/forum/#!msg/mathjax-users/kzOOFw1qtxw/YdAEPJfCEXUJ

	MathJax.resetLabels = function() {
		//var AMS = MathJax.Extension["TeX/AMSmath"];
		//AMS.startNumber = 0;
		//AMS.labels = {};
	}

	// Allow inline maths with single $s

	MathJax.Hub.Config({
		tex2jax: {
		inlineMath: [ ['$','$'], ["\\(","\\)"] ],
		displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
		processEscapes: true,
		},
		TeX: {
			Macros: {
				// See http://docs.mathjax.org/en/latest/tex.html#defining-tex-macros
				"quantity": ["{#1}\\,{\\rm{#2}}",2],
				"valuedef": ["{#1}={\\quantity{#2}{#3}}",3],
				"vtr": ["{\\underline{\\boldsymbol{#1}}}",1],
				"d": "\\operatorname{d}",
				"vari": ["#1",1],
				"s": ["_{\\sf{#1}}", 1],
				"half": ["\\frac{1}{2}",0],
				"third": ["\\frac{1}{3}",0],
				"quarter": ["\\frac{1}{4}",0],
				"eighth": ["\\frac{1}{8}",0],
				"e": ["\\textrm{e}",0],
				"units": ["\\rm{#1}",1],
			}
		},
	});

	// Fix font issues in Chrome 32
	// https://groups.google.com/forum/#!msg/mathjax-users/S5x-RQDPJrI/p4nmRXJvoskJ

	MathJax.Hub.Config({
		extensions: ["MatchWebFonts.js"]
	});

	if (MathJax.Hub.Browser.isChrome) {
		MathJax.Hub.Register.StartupHook(
			"HTML-CSS Jax Config",
			function () {MathJax.OutputJax["HTML-CSS"].FontFaceBug = true}
		);
	}

});

// Here is a very useful page:

// http://meta.math.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference<|endoftext|>


<commit_before>declare module "path-to-regexp" {
  declare export type Key = {
    name: string | number;
    prefix: string;
    delimiter: string;
    optional: boolean;
    repeat: boolean;
    pattern: string;
    partial: boolean;
  }

  declare export type RegExpOptions = {
    sensitive?: boolean;
    strict?: boolean;
    end?: boolean;
    start?: boolean;
    delimiter?: string;
    endsWith?: string | string[];
  }

  declare export type ParseOptions = {
    delimiter?: string;
    delimiters?: string | string[];
  }

  declare type PathFunctionOptions = {
    encode?: (value: string, token: Key) => string;
  }

  declare export type Token = string | Key;

  declare export type PathFunction = (
    data?: {},
    options?: PathFunctionOptions
  ) => string;

  declare export var parse: (path: string, options?: ParseOptions) => Token[];

  declare export var compile: (path: string, options?: {}) => PathFunction;

  declare export var tokensToFunction: (tokens: Token[]) => PathFunction;

  declare export var tokensToRegExp: (
    tokens: Token[],
    keys?: Key[],
    options?: RegExpOptions
  ) => RegExp;
}
<commit_msg>add missing default export to path-to-regexp (#2806)<commit_after>declare module "path-to-regexp" {
  declare export type Key = {
    name: string | number;
    prefix: string;
    delimiter: string;
    optional: boolean;
    repeat: boolean;
    pattern: string;
    partial: boolean;
  }

  declare export type RegExpOptions = {
    sensitive?: boolean;
    strict?: boolean;
    end?: boolean;
    start?: boolean;
    delimiter?: string;
    endsWith?: string | string[];
  }

  declare export type ParseOptions = {
    delimiter?: string;
    delimiters?: string | string[];
  }

  declare type PathFunctionOptions = {
    encode?: (value: string, token: Key) => string;
  }

  declare export type Token = string | Key;

  declare export type Path = string | RegExp | Array<string | RegExp>;

  declare export type PathFunction = (
    data?: {},
    options?: PathFunctionOptions
  ) => string;

  declare export var parse: (path: string, options?: ParseOptions) => Token[];

  declare export var compile: (path: string, options?: {}) => PathFunction;

  declare export var tokensToFunction: (tokens: Token[]) => PathFunction;

  declare export var tokensToRegExp: (
    tokens: Token[],
    keys?: Key[],
    options?: RegExpOptions
  ) => RegExp;

  declare export default (
    path: Path,
    keys?: Key[],
    options?: RegExpOptions & ParseOptions
  ) => RegExp;
}
<|endoftext|>


<commit_before>'use strict';

angular.module('ddsApp').controller('FoyerCtrl', function($scope, $state, $modal, $filter, nationalites, logementTypes, locationTypes, SituationService, IndividuService) {
    var situation = $scope.situation = SituationService.restoreLocal();
    $scope.statutsSpecifiques = IndividuService.formatStatutsSpecifiques;
    $scope.nationalite = IndividuService.nationaliteLabel;

    var buildRecapLogement = function() {
        var logementLabel = _.find(logementTypes, { id: situation.logement.type }).label;
        logementLabel = $filter('uppercaseFirst')(logementLabel);
        $scope.recapLogement = '' + logementLabel + '';
        if ('locataire' === situation.logement.type) {
            $scope.recapLogement += ' d’un logement ';
            $scope.recapLogement += _.find(locationTypes, { id: situation.logement.locationType }).label;
            $scope.recapLogement += '';
            $scope.loyerLabel = 'Loyer';
        } else {
            $scope.loyerLabel = 'Mensualité d’emprunt';
        }
    };

    if (situation.logement) {
        buildRecapLogement();
    }

    $scope.$on('individu.demandeur', function(e, demandeur) {
        if (_.find(situation.individus, { role: 'demandeur' })) {
            situation.individus[0] = demandeur;
        } else {
            situation.individus.push(demandeur);
        }
        $state.go('foyer.conjoint');
    });

    $scope.$on('individu.conjoint', function(e, conjoint) {
        if (conjoint) {
            situation.individus.push(conjoint);
        }
        $state.go('foyer.enfants');
    });

    $scope.$on('enfants', function(e, enfants) {
        situation.individus.push.apply(situation.individus, enfants);
        $state.go('foyer.personnesACharge');
    });

    $scope.$on('personnesACharge', function(e, personnesACharge) {
        situation.individus.push.apply(situation.individus, personnesACharge);
        $state.go('foyer.logement');
    });

    $scope.$on('logement', function(e, logement) {
        situation.logement = logement;
        buildRecapLogement();
        $state.go('foyer.ressources');
    });

    $scope.$on('ressources', function() {
        $scope.ressourcesCaptured = true;
        $state.go('foyer.patrimoine');
    });

    $scope.$on('patrimoine', function(e, patrimoine) {
        situation.patrimoine = patrimoine;
        SituationService.create(situation).then(function(result) {
            $state.go('foyer.simulation', { 'situationId': result._id });
        });
    });
});
<commit_msg>bouton précedent pour la page conjoint<commit_after>'use strict';

angular.module('ddsApp').controller('FoyerCtrl', function($scope, $state, $modal, $filter, nationalites, logementTypes, locationTypes, SituationService, IndividuService) {
    var situation = $scope.situation = SituationService.restoreLocal();
    $scope.statutsSpecifiques = IndividuService.formatStatutsSpecifiques;
    $scope.nationalite = IndividuService.nationaliteLabel;

    var buildRecapLogement = function() {
        var logementLabel = _.find(logementTypes, { id: situation.logement.type }).label;
        logementLabel = $filter('uppercaseFirst')(logementLabel);
        $scope.recapLogement = '' + logementLabel + '';
        if ('locataire' === situation.logement.type) {
            $scope.recapLogement += ' d’un logement ';
            $scope.recapLogement += _.find(locationTypes, { id: situation.logement.locationType }).label;
            $scope.recapLogement += '';
            $scope.loyerLabel = 'Loyer';
        } else {
            $scope.loyerLabel = 'Mensualité d’emprunt';
        }
    };

    if (situation.logement) {
        buildRecapLogement();
    }

    $scope.$on('individu.demandeur', function(e, demandeur) {
        if (_.find(situation.individus, { role: 'demandeur' })) {
            situation.individus[0] = demandeur;
        } else {
            situation.individus.push(demandeur);
        }
        $state.go('foyer.conjoint');
    });

    $scope.$on('individu.conjoint', function(e, conjoint) {
        if (conjoint) {
            if (_.find(situation.individus, { role: 'conjoint' })) {
                situation.individus[1] = conjoint;
            } else {
                situation.individus.splice(1, 0, conjoint);
            }
        }
        $state.go('foyer.enfants');
    });

    $scope.$on('enfants', function(e, enfants) {
        situation.individus.push.apply(situation.individus, enfants);
        $state.go('foyer.personnesACharge');
    });

    $scope.$on('personnesACharge', function(e, personnesACharge) {
        situation.individus.push.apply(situation.individus, personnesACharge);
        $state.go('foyer.logement');
    });

    $scope.$on('logement', function(e, logement) {
        situation.logement = logement;
        buildRecapLogement();
        $state.go('foyer.ressources');
    });

    $scope.$on('ressources', function() {
        $scope.ressourcesCaptured = true;
        $state.go('foyer.patrimoine');
    });

    $scope.$on('patrimoine', function(e, patrimoine) {
        situation.patrimoine = patrimoine;
        SituationService.create(situation).then(function(result) {
            $state.go('foyer.simulation', { 'situationId': result._id });
        });
    });
});
<|endoftext|>


<commit_before>mol.modules.map.dashboard = function(mol) {

    mol.map.dashboard = {};

    mol.map.dashboard.DashboardEngine = mol.mvp.Engine.extend(
        {
            init: function(proxy, bus) {
                this.proxy = proxy;
                this.bus = bus;
                this.sql = '';
//Here is the sql to use for polygon dash requests.
/*SELECT s.provider as provider, s.type as type, num_species, num_records, s.class FROM
    (SELECT provider, type, count(*) as num_species, class
        FROM
        (SELECT DISTINCT scientificname, provider, type from gbif_import) p,
        (SELECT DISTINCT scientific, class from master_taxonomy) t
    WHERE p.scientificname = t.scientific
    GROUP BY provider, type, class
        ) s,
    (SELECT provider, type, count(*) as num_records, class
    FROM
        (SELECT scientificname, provider, type from gbif_import) pr,
        (SELECT DISTINCT scientific, class from master_taxonomy) tr
    WHERE pr.scientificname = tr.scientific
    GROUP BY provider, type, class
        ) r
 WHERE
    r.provider = s.provider and r.type = s.type and r.class = s.class;
*/            },

            /**
             * Starts the MenuEngine. Note that the container parameter is
             * ignored.
             */
            start: function() {
                this.display = new mol.map.dashboard.DashboardDisplay();
                this.initDialog();
                this.addEventHandlers();
            },

            /**
             * Adds a handler for the 'search-display-toggle' event which
             * controls display visibility. Also adds UI event handlers for the
             * display.
             */
            addEventHandlers: function() {
                var self = this;

                /**
                 * Callback that toggles the dashboard display visibility.
                 *
                 * @param event mol.bus.Event
                 */
                this.bus.addHandler(
                    'taxonomy-dashboard-toggle',
                    function(event) {
                        var params = null,
                            e = null;

                        if (event.state === undefined) {
                            self.display.dialog('open');
                        } else {
                            self.display.dialog(event.state);
                        }
                    }
                );

                _.each(
                    this.display.providers,
                    function(tr) {
                        var provider = $(tr).attr('class').replace('provider','').trim(),
                            type = $(tr).find('.type').attr('class').replace('type','').trim();
                        _.each(
                            $(tr).find('.class'),
                            function(td) {
                                $(td).click (
                                    function(event) {
                                        var _class = $(td).attr('class').replace('class','').trim();
                                        self.bus.fireEvent(new mol.bus.Event('metadata-toggle',{ params :{provider: provider, type: type, _class: _class, text: $(this).text()}}));
                                    }
                                )
                            }
                        )

                    }
                );
                _.each(
                    this.display.types,
                    function(td) {
                         var type = $(td).attr('class').replace('type','').trim();
                         $(td).click (
                                    function(event) {
                                        var _class = $(this).attr('class').replace('class','').trim();
                                        self.bus.fireEvent(new mol.bus.Event('metadata-toggle',{ params :{type: type}}));
                                    }
                         );
                    }
                )
            },

            /**
             * Fires the 'add-map-control' event. The mol.map.MapEngine handles
             * this event and adds the display to the map.
             */
            initDialog: function() {
                this.display.dialog(
                    {
                        autoOpen: false,
					    width: 1000,
					    dialogClass: "mol-Dashboard"
                    }
                );
            }
        }
    );

    mol.map.dashboard.DashboardDisplay = mol.mvp.View.extend(
        {
            init: function() {
                var html = '' +
                    '
' +
                    '
' +
                    '
Dashboard
' +
                    '
Statistics for data served by the Map of Life
' +
                    '
' +
                    '
' +
                    '
' +
                    '      Type	' +
                    '      Source	' +
                    '      Amphibians	' +
                    '      Birds	' +
                    '      Mammals	' +
                    '      Reptiles	' +
                    '      Fish	' +
                    '
' +
                    '
' +
                    '
' +
                    '
' +
                    '      Points	' +
                    '      GBIF	' +
                    '      5,662 species names with 1,794,441 records	' +
                    '      13,000 species names with 132,412,174 records	' +
                    '      14,095 species names with 4,351,065 records	' +
                    '      11,445 species names with 1,695,170 records	' +
                    '      	' +
                    '
' +
                    '
' +
                    '       Expert maps	' +
                    '       User-uploaded	' +
                    '       	' +
                    '

Jetz et al. 2012: 9,869 species with 28,019 records
	' +
                    '       	' +
                    '       	' +
                    '

Page and Burr, 2011: 723 species with 9,755 records
	' +
                    '
' +
                    '
' +
                    '       Expert maps	' +
                    '       IUCN	' +
                    '       5,966 species with 18,852 records	' +
                    '       	' +
                    '       4,081 species with 38,673 records	' +
                    '       	' +
                    '       	' +
                    '
' +
                    '
' +
                    '       Local Inventories	' +
                    '       Misc. sources	' +
                    '       727 species with 1,820 records	' +
                    '       4,042 species with 48,000 records	' +
                    '       1,411 species with 9,895 records	' +
                    '       	' +
                    '       	' +
                    '
' +
                    '
' +
                    '       Regional checklists	' +
                    '       WWF	' +
                    '       3,081 species with 12,296 records	' +
                    '       8,755 species with 201,418 records	' +
                    '       4,224 species with 67,533 records	' +
                    '       6,830 species with 67,533 records	' +
                    '       	' +
                    '
' +
                    '
' +
                    '
' +
                    '
  ';

                this._super(html);
                this.providers = $(this).find('.provider');
                this.types = $(this).find('.type');

            }
        }
    );
};

<commit_msg>Modified code so that the "Dashboard" button toggles the Dashboard (open if closed, close if open).<commit_after>mol.modules.map.dashboard = function(mol) {

    mol.map.dashboard = {};

    mol.map.dashboard.DashboardEngine = mol.mvp.Engine.extend(
        {
            init: function(proxy, bus) {
                this.proxy = proxy;
                this.bus = bus;
                this.sql = '';
//Here is the sql to use for polygon dash requests.
/*SELECT s.provider as provider, s.type as type, num_species, num_records, s.class FROM
    (SELECT provider, type, count(*) as num_species, class
        FROM
        (SELECT DISTINCT scientificname, provider, type from gbif_import) p,
        (SELECT DISTINCT scientific, class from master_taxonomy) t
    WHERE p.scientificname = t.scientific
    GROUP BY provider, type, class
        ) s,
    (SELECT provider, type, count(*) as num_records, class
    FROM
        (SELECT scientificname, provider, type from gbif_import) pr,
        (SELECT DISTINCT scientific, class from master_taxonomy) tr
    WHERE pr.scientificname = tr.scientific
    GROUP BY provider, type, class
        ) r
 WHERE
    r.provider = s.provider and r.type = s.type and r.class = s.class;
*/            },

            /**
             * Starts the MenuEngine. Note that the container parameter is
             * ignored.
             */
            start: function() {
                this.display = new mol.map.dashboard.DashboardDisplay();
                this.initDialog();
                this.addEventHandlers();
            },

            /**
             * Adds a handler for the 'search-display-toggle' event which
             * controls display visibility. Also adds UI event handlers for the
             * display.
             */
            addEventHandlers: function() {
                var self = this;

                /**
                 * Callback that toggles the dashboard display visibility.
                 *
                 * @param event mol.bus.Event
                 */
                this.bus.addHandler(
                    'taxonomy-dashboard-toggle',
                    function(event) {
                        var params = null,
                            e = null;

                        if (event.state === undefined) {
                            if(self.display.dialog('isOpen')) {
                                self.display.dialog('close');
                            } else {
                                self.display.dialog('open');
                            }
                        } else {
                            self.display.dialog(event.state);
                        }
                    }
                );

                _.each(
                    this.display.providers,
                    function(tr) {
                        var provider = $(tr).attr('class').replace('provider','').trim(),
                            type = $(tr).find('.type').attr('class').replace('type','').trim();
                        _.each(
                            $(tr).find('.class'),
                            function(td) {
                                $(td).click (
                                    function(event) {
                                        var _class = $(td).attr('class').replace('class','').trim();
                                        self.bus.fireEvent(new mol.bus.Event('metadata-toggle',{ params :{provider: provider, type: type, _class: _class, text: $(this).text()}}));
                                    }
                                )
                            }
                        )

                    }
                );
                _.each(
                    this.display.types,
                    function(td) {
                         var type = $(td).attr('class').replace('type','').trim();
                         $(td).click (
                                    function(event) {
                                        var _class = $(this).attr('class').replace('class','').trim();
                                        self.bus.fireEvent(new mol.bus.Event('metadata-toggle',{ params :{type: type}}));
                                    }
                         );
                    }
                )
            },

            /**
             * Fires the 'add-map-control' event. The mol.map.MapEngine handles
             * this event and adds the display to the map.
             */
            initDialog: function() {
                this.display.dialog(
                    {
                        autoOpen: false,
					    width: 1000,
					    dialogClass: "mol-Dashboard"
                    }
                );
            }
        }
    );

    mol.map.dashboard.DashboardDisplay = mol.mvp.View.extend(
        {
            init: function() {
                var html = '' +
                    '
' +
                    '
' +
                    '
Dashboard
' +
                    '
Statistics for data served by the Map of Life
' +
                    '
' +
                    '
' +
                    '
' +
                    '      Type	' +
                    '      Source	' +
                    '      Amphibians	' +
                    '      Birds	' +
                    '      Mammals	' +
                    '      Reptiles	' +
                    '      Fish	' +
                    '
' +
                    '
' +
                    '
' +
                    '
' +
                    '      Points	' +
                    '      GBIF	' +
                    '      5,662 species names with 1,794,441 records	' +
                    '      13,000 species names with 132,412,174 records	' +
                    '      14,095 species names with 4,351,065 records	' +
                    '      11,445 species names with 1,695,170 records	' +
                    '      	' +
                    '
' +
                    '
' +
                    '       Expert maps	' +
                    '       User-uploaded	' +
                    '       	' +
                    '

Jetz et al. 2012: 9,869 species with 28,019 records
	' +
                    '       	' +
                    '       	' +
                    '

Page and Burr, 2011: 723 species with 9,755 records
	' +
                    '
' +
                    '
' +
                    '       Expert maps	' +
                    '       IUCN	' +
                    '       5,966 species with 18,852 records	' +
                    '       	' +
                    '       4,081 species with 38,673 records	' +
                    '       	' +
                    '       	' +
                    '
' +
                    '
' +
                    '       Local Inventories	' +
                    '       Misc. sources	' +
                    '       727 species with 1,820 records	' +
                    '       4,042 species with 48,000 records	' +
                    '       1,411 species with 9,895 records	' +
                    '       	' +
                    '       	' +
                    '
' +
                    '
' +
                    '       Regional checklists	' +
                    '       WWF	' +
                    '       3,081 species with 12,296 records	' +
                    '       8,755 species with 201,418 records	' +
                    '       4,224 species with 67,533 records	' +
                    '       6,830 species with 67,533 records	' +
                    '       	' +
                    '
' +
                    '
' +
                    '
' +
                    '
  ';

                this._super(html);
                this.providers = $(this).find('.provider');
                this.types = $(this).find('.type');

            }
        }
    );
};

<|endoftext|>