<commit_before>/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true, newcap: true */
/*global window, $, Backbone, document, arangoCollectionModel*/
/*global arangoHelper,dashboardView,arangoDatabase*/

(function () {
    "use strict";

    window.Router = Backbone.Router.extend({
        routes: {
            "": "dashboard",
            "dashboard": "dashboard",
            "collection/:colid": "collection",
            "collections": "collections",
            "collectionInfo/:colid": "collectionInfo",
            "new": "newCollection",
            "login": "login",
            "collection/:colid/documents/:pageid": "documents",
            "collection/:colid/:docid": "document",
            "shell": "shell",
            "query": "query",
            "logs": "logs",
            "api": "api",
            "databases": "databases",
            "application/installed/:key": "applicationEdit",
            "application/available/:key": "applicationInstall",
            "applications": "applications",
            "application/documentation/:key": "appDocumentation",
            "graph": "graph",
            "graphManagement": "graphManagement",
            "graphManagement/add": "graphAddNew",
            "graphManagement/delete/:name": "graphDelete",
            "userManagement": "userManagement",
            "userProfile": "userProfile",
            "testing": "testview",
            "testModalView": "testmodalview"
        },

        testmodalview: function() {
          this.testModalView = new window.testModalView();
          this.testModalView.render();
        },

        testview: function () {
            this.testView = new window.testView();
            this.testView.render();
        },

        initialize: function () {
          // This should be the only global object
          window.modalView = new window.ModalView();
            var self = this;
            this.bind('all', function (trigger, args) {
                if (trigger === "route") {
                    if (self.currentRoute === "dashboard" && self.dashboardView) {
                        self.dashboardView.stopUpdating();
                    } else if (args === "dashboard") {
                        delete self.dashboardView;
                    }
                    self.currentRoute = args;
                }
            });
            this.graphs = new window.GraphCollection();
            this.notificationList = new window.NotificationCollection();

            window.currentDB = new window.CurrentDatabase();
            window.currentDB.fetch({
                async: false
            });

            window.userCollection = new window.ArangoUsers();

            window.arangoDatabase = new window.ArangoDatabase();

            window.arangoCollectionsStore = new window.arangoCollections();
            window.arangoDocumentsStore = new window.arangoDocuments();
            window.arangoDocumentStore = new window.arangoDocument();

            window.collectionsView = new window.CollectionsView({
                collection: window.arangoCollectionsStore
            });
            window.arangoCollectionsStore.fetch();
            window.documentsView = new window.DocumentsView();
            window.documentView = new window.DocumentView({
                collection: window.arangoDocumentStore
            });
            window.arangoLogsStore = new window.ArangoLogs();
            window.arangoLogsStore.fetch({
                success: function () {
                    window.logsView = new window.LogsView({
                        collection: window.arangoLogsStore
                    });
                }
            });

            this.foxxList = new window.FoxxCollection();

            this.footerView = new window.FooterView();
            this.naviView = new window.NavigationView({
                notificationCollection: this.notificationList,
                userCollection: window.userCollection
            });
            this.footerView.render();
            this.naviView.render();
            this.graphView = new window.GraphView({
                graphs: this.graphs,
                collection: window.arangoCollectionsStore
            });

            this.initVersionCheck();

            $(window).resize(function () {
                self.handleResize();
            });
            //this.handleResize();
        },

        initVersionCheck: function () {
            // this checks for version updates

            var self = this;
            var versionCheck = function () {
                $.ajax({
                    async: true,
                    crossDomain: true,
                    dataType: "jsonp",
                    url: "https://www.arangodb.org/repositories/versions.php" +
                        "?callback=parseVersions",
                    success: function (json) {
                        if (typeof json !== 'object') {
                            return;
                        }

                        // turn our own version string into a version object
                        var currentVersion =
                            window.versionHelper.fromString(self.footerView.system.version);

                        // get our mainline version
                        var mainLine = window.versionHelper.toStringMainLine(currentVersion);

                        var mainLines = Object.keys(json).
                            sort(window.versionHelper.compareVersionStrings);
                        var latestMainLine;
                        mainLines.forEach(function (l) {
                            if (json[l].stable) {
                                if (window.versionHelper.compareVersionStrings(l, mainLine) > 0) {
                                    latestMainLine = json[l];
                                }
                            }
                        });

                        var update;
                        var mainLineVersions;
                        var latest;
                        if (latestMainLine !== undefined &&
                            Object.keys(latestMainLine.versions).length > 0) {
                            mainLineVersions = Object.keys(latestMainLine.versions);
                            mainLineVersions = mainLineVersions.
                                sort(window.versionHelper.compareVersionStrings);
                            latest = mainLineVersions[mainLineVersions.length - 1];

                            update = {
                                type: "major",
                                version: latest,
                                changes: latestMainLine.versions[latest].changes
                            };
                        }

                        // check which stable mainline versions are available remotely
                        if (update === undefined &&
                            json.hasOwnProperty(mainLine) &&
                            json[mainLine].stable &&
                            json[mainLine].hasOwnProperty("versions") &&
                            Object.keys(json[mainLine].versions).length > 0) {
                            // sort by version numbers
                            mainLineVersions = Object.keys(json[mainLine].versions);
                            mainLineVersions = mainLineVersions.
                                sort(window.versionHelper.compareVersionStrings);
                            latest = mainLineVersions[mainLineVersions.length - 1];

                            var result = window.versionHelper.compareVersions(
                                currentVersion,
                                window.versionHelper.fromString(latest)
                            );
                            if (result < 0) {
                                update = {
                                    type: "minor",
                                    version: latest,
                                    changes: json[mainLine].versions[latest].changes
                                };
                            }
                        }

                        if (update !== undefined) {
                            var msg = "A newer version of ArangoDB (" + update.version +
                                ") has become available. You may want to check the " +
                                "changelog at " +
                                update.changes + "";
                            arangoHelper.arangoNotification(msg, 15000);

                        }
                    },
                    error: function () {
                        // re-schedule the version check
                        window.setTimeout(versionCheck, 60000);
                    }
                });
            };

            window.setTimeout(versionCheck, 5000);
        },

        logsAllowed: function () {
            return (window.currentDB.get('name') === '_system');
        },

        checkUser: function () {
            if (window.userCollection.models.length === 0) {
                this.navigate("login", {trigger: true});
                return false;
            }
            return true;
        },

        login: function () {
            if (!this.loginView) {
                this.loginView = new window.loginView({
                    collection: window.userCollection
                });
            }
            this.loginView.render();
            this.naviView.selectMenuItem('');
        },

        collections: function () {
            var naviView = this.naviView;
            window.arangoCollectionsStore.fetch({
                success: function () {
                    window.collectionsView.render();
                    naviView.selectMenuItem('collections-menu');
                }
            });
        },

        collection: function (colid) {
            if (!this.collectionView) {
                this.collectionView = new window.CollectionView();
            }
            this.collectionView.setColId(colid);
            this.collectionView.render();
            this.naviView.selectMenuItem('collections-menu');
        },
        collectionInfo: function (colid) {
            if (!this.collectionInfoView) {
                this.collectionInfoView = new window.CollectionInfoView();
            }
            this.collectionInfoView.setColId(colid);
            this.collectionInfoView.render();
            this.naviView.selectMenuItem('collections-menu');
        },
        newCollection: function () {
            if (!this.newCollectionView) {
                this.newCollectionView = new window.newCollectionView({});
            }
            this.newCollectionView.render();
            this.naviView.selectMenuItem('collections-menu');
        },

        documents: function (colid, pageid) {
            if (!window.documentsView) {
                window.documentsView.initTable(colid, pageid);
            }
            window.documentsView.collectionID = colid;
            var type = arangoHelper.collectionApiType(colid);
            window.documentsView.colid = colid;
            window.documentsView.pageid = pageid;
            window.documentsView.type = type;
            window.documentsView.render();
            window.arangoDocumentsStore.getDocuments(colid, pageid);
        },

        document: function (colid, docid) {
            window.documentView.colid = colid;
            window.documentView.docid = docid;
            window.documentView.render();
            var type = arangoHelper.collectionApiType(colid);
            window.documentView.type = type;
            window.documentView.typeCheck(type);
        },

        shell: function () {
            if (!this.shellView) {
                this.shellView = new window.shellView();
            }
            this.shellView.render();
            this.naviView.selectMenuItem('tools-menu');
        },

        query: function () {
            if (!this.queryView) {
                this.queryView = new window.queryView();
            }
            this.queryView.render();
            this.naviView.selectMenuItem('query-menu');
        },

        api: function () {
            if (!this.apiView) {
                this.apiView = new window.apiView();
            }
            this.apiView.render();
            this.naviView.selectMenuItem('tools-menu');
        },

        databases: function () {
            if (arangoHelper.databaseAllowed() === true) {
                if (!this.databaseView) {
                    this.databaseView = new window.databaseView({
                        collection: arangoDatabase
                    });
                }
                this.databaseView.render();
                this.naviView.selectMenuItem('databases-menu');
            }
            else {
                this.navigate("#", {trigger: true});
                this.naviView.selectMenuItem('dashboard-menu');
                $('#databaseNavi').css('display', 'none');
                $('#databaseNaviSelect').css('display', 'none');
            }
        },

        logs: function () {
            if (!this.logsAllowed()) {
                this.navigate('', { trigger: true });
                return;
            }

            window.arangoLogsStore.fetch({
                success: function () {
                    window.logsView.render();
                    $('#logNav a[href="#all"]').tab('show');
                    window.logsView.initLogTables();
                    window.logsView.drawTable();
                    $('#all-switch').click();
                }
            });
            this.naviView.selectMenuItem('tools-menu');
        },

        dashboard: function () {
            this.naviView.selectMenuItem('dashboard-menu');
            if (this.statisticsDescriptionCollection === undefined) {
                this.statisticsDescriptionCollection = new window.StatisticsDescriptionCollection();
                this.statisticsDescriptionCollection.fetch({
                    async: false
                });
            }
            if (this.statistics === undefined) {
                this.statisticsCollection = new window.StatisticsCollection();
            }
            if (this.dashboardView === undefined) {
                this.dashboardView = new dashboardView({
                    collection: this.statisticsCollection,
                    description: this.statisticsDescriptionCollection,
                    documentStore: window.arangoDocumentsStore,
                    dygraphConfig: window.dygraphConfig
                });
            }
            this.dashboardView.render();
        },

        graph: function () {
            var self = this;
            window.arangoCollectionsStore.fetch({
                success: function () {
                    self.graphView.render();
                    self.naviView.selectMenuItem('graphviewer-menu');
                }
            });
        },

        graphManagement: function () {
            if (!this.graphManagementView) {
                this.graphManagementView =
                    new window.GraphManagementView({collection: this.graphs});
            }
            this.graphManagementView.render();
            this.naviView.selectMenuItem('graphviewer-menu');
        },

        graphAddNew: function () {
            if (!this.addNewGraphView) {
                this.addNewGraphView = new window.AddNewGraphView({
                    collection: window.arangoCollectionsStore,
                    graphs: this.graphs
                });
            }
            this.addNewGraphView.render();
            this.naviView.selectMenuItem('graphviewer-menu');
        },

        graphDelete: function (name) {
            if (!this.deleteGraphView) {
                this.deleteGraphView = new window.DeleteGraphView({
                    collection: this.graphs
                });
            }
            this.deleteGraphView.render(name);
            this.naviView.selectMenuItem('graphviewer-menu');
        },

        applications: function () {
            if (this.applicationsView === undefined) {
                this.applicationsView = new window.ApplicationsView({
                    collection: this.foxxList
                });
            }
            this.applicationsView.reload();
            this.naviView.selectMenuItem('applications-menu');
        },

        applicationEdit: function (appkey) {
            this.foxxList.fetch({
                async: false
            });
            var editAppView = new window.foxxEditView(
                {model: this.foxxList.findWhere({_key: appkey})}
            );
            editAppView.render();
        },

        applicationInstall: function (appkey) {
            this.foxxList.fetch({
                async: false
            });
            if (!this.installAppView) {
                this.installAppView = new window.foxxMountView({
                    collection: this.foxxList
                });
            }
            this.installAppView.render(appkey);
        },

        appDocumentation: function (key) {
            var docuView = new window.AppDocumentationView({key: key});
            docuView.render();
            this.naviView.selectMenuItem('applications-menu');
        },

        handleSelectDatabase: function () {
            this.naviView.handleSelectDatabase();
        },

        handleResize: function () {
            if (this.dashboardView) {
                this.dashboardView.resize();
            }
            var oldWidth = $('#content').width();
            var containerWidth = $(window).width() - 70;
            /*var spanWidth = 242;*/
            var spanWidth = 243;
            var divider = containerWidth / spanWidth;
            var roundDiv = parseInt(divider, 10);
            var newWidth = roundDiv * spanWidth - 2;
            var marginWidth = ((containerWidth + 30) - newWidth) / 2;
            /*
             $('#content').width(newWidth)
             .css('margin-left', marginWidth)
             .css('margin-right', marginWidth);
             */
            // $('.footer-right p').css('margin-right', marginWidth + 20);
            // $('.footer-left p').css('margin-left', marginWidth + 20);
            if (newWidth !== oldWidth) {
                this.graphView.handleResize(newWidth);
            }
        },

        userManagement: function () {
            if (!this.userManagementView) {
                this.userManagementView = new window.userManagementView({
                    collection: window.userCollection
                });
            }
            this.userManagementView.render();
            this.naviView.selectMenuItem('tools-menu');
        },

        userProfile: function () {
          if (!this.userManagementView) {
            this.userManagementView = new window.userManagementView({
                    collection: window.userCollection
                });
            }
          this.userManagementView.render(true);
          this.naviView.selectMenuItem('tools-menu');
        }
    });

}());
<commit_msg>removed test view<commit_after>/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true, newcap: true */
/*global window, $, Backbone, document, arangoCollectionModel*/
/*global arangoHelper,dashboardView,arangoDatabase*/

(function () {
    "use strict";

    window.Router = Backbone.Router.extend({
        routes: {
            "": "dashboard",
            "dashboard": "dashboard",
            "collection/:colid": "collection",
            "collections": "collections",
            "collectionInfo/:colid": "collectionInfo",
            "new": "newCollection",
            "login": "login",
            "collection/:colid/documents/:pageid": "documents",
            "collection/:colid/:docid": "document",
            "shell": "shell",
            "query": "query",
            "logs": "logs",
            "api": "api",
            "databases": "databases",
            "application/installed/:key": "applicationEdit",
            "application/available/:key": "applicationInstall",
            "applications": "applications",
            "application/documentation/:key": "appDocumentation",
            "graph": "graph",
            "graphManagement": "graphManagement",
            "graphManagement/add": "graphAddNew",
            "graphManagement/delete/:name": "graphDelete",
            "userManagement": "userManagement",
            "userProfile": "userProfile",
            "testing": "testview"
        },

        testview: function () {
            this.testView = new window.testView();
            this.testView.render();
        },

        initialize: function () {
          // This should be the only global object
          window.modalView = new window.ModalView();
            var self = this;
            this.bind('all', function (trigger, args) {
                if (trigger === "route") {
                    if (self.currentRoute === "dashboard" && self.dashboardView) {
                        self.dashboardView.stopUpdating();
                    } else if (args === "dashboard") {
                        delete self.dashboardView;
                    }
                    self.currentRoute = args;
                }
            });
            this.graphs = new window.GraphCollection();
            this.notificationList = new window.NotificationCollection();

            window.currentDB = new window.CurrentDatabase();
            window.currentDB.fetch({
                async: false
            });

            window.userCollection = new window.ArangoUsers();

            window.arangoDatabase = new window.ArangoDatabase();

            window.arangoCollectionsStore = new window.arangoCollections();
            window.arangoDocumentsStore = new window.arangoDocuments();
            window.arangoDocumentStore = new window.arangoDocument();

            window.collectionsView = new window.CollectionsView({
                collection: window.arangoCollectionsStore
            });
            window.arangoCollectionsStore.fetch();
            window.documentsView = new window.DocumentsView();
            window.documentView = new window.DocumentView({
                collection: window.arangoDocumentStore
            });
            window.arangoLogsStore = new window.ArangoLogs();
            window.arangoLogsStore.fetch({
                success: function () {
                    window.logsView = new window.LogsView({
                        collection: window.arangoLogsStore
                    });
                }
            });

            this.foxxList = new window.FoxxCollection();

            this.footerView = new window.FooterView();
            this.naviView = new window.NavigationView({
                notificationCollection: this.notificationList,
                userCollection: window.userCollection
            });
            this.footerView.render();
            this.naviView.render();
            this.graphView = new window.GraphView({
                graphs: this.graphs,
                collection: window.arangoCollectionsStore
            });

            this.initVersionCheck();

            $(window).resize(function () {
                self.handleResize();
            });
            //this.handleResize();
        },

        initVersionCheck: function () {
            // this checks for version updates

            var self = this;
            var versionCheck = function () {
                $.ajax({
                    async: true,
                    crossDomain: true,
                    dataType: "jsonp",
                    url: "https://www.arangodb.org/repositories/versions.php" +
                        "?callback=parseVersions",
                    success: function (json) {
                        if (typeof json !== 'object') {
                            return;
                        }

                        // turn our own version string into a version object
                        var currentVersion =
                            window.versionHelper.fromString(self.footerView.system.version);

                        // get our mainline version
                        var mainLine = window.versionHelper.toStringMainLine(currentVersion);

                        var mainLines = Object.keys(json).
                            sort(window.versionHelper.compareVersionStrings);
                        var latestMainLine;
                        mainLines.forEach(function (l) {
                            if (json[l].stable) {
                                if (window.versionHelper.compareVersionStrings(l, mainLine) > 0) {
                                    latestMainLine = json[l];
                                }
                            }
                        });

                        var update;
                        var mainLineVersions;
                        var latest;
                        if (latestMainLine !== undefined &&
                            Object.keys(latestMainLine.versions).length > 0) {
                            mainLineVersions = Object.keys(latestMainLine.versions);
                            mainLineVersions = mainLineVersions.
                                sort(window.versionHelper.compareVersionStrings);
                            latest = mainLineVersions[mainLineVersions.length - 1];

                            update = {
                                type: "major",
                                version: latest,
                                changes: latestMainLine.versions[latest].changes
                            };
                        }

                        // check which stable mainline versions are available remotely
                        if (update === undefined &&
                            json.hasOwnProperty(mainLine) &&
                            json[mainLine].stable &&
                            json[mainLine].hasOwnProperty("versions") &&
                            Object.keys(json[mainLine].versions).length > 0) {
                            // sort by version numbers
                            mainLineVersions = Object.keys(json[mainLine].versions);
                            mainLineVersions = mainLineVersions.
                                sort(window.versionHelper.compareVersionStrings);
                            latest = mainLineVersions[mainLineVersions.length - 1];

                            var result = window.versionHelper.compareVersions(
                                currentVersion,
                                window.versionHelper.fromString(latest)
                            );
                            if (result < 0) {
                                update = {
                                    type: "minor",
                                    version: latest,
                                    changes: json[mainLine].versions[latest].changes
                                };
                            }
                        }

                        if (update !== undefined) {
                            var msg = "A newer version of ArangoDB (" + update.version +
                                ") has become available. You may want to check the " +
                                "changelog at " +
                                update.changes + "";
                            arangoHelper.arangoNotification(msg, 15000);

                        }
                    },
                    error: function () {
                        // re-schedule the version check
                        window.setTimeout(versionCheck, 60000);
                    }
                });
            };

            window.setTimeout(versionCheck, 5000);
        },

        logsAllowed: function () {
            return (window.currentDB.get('name') === '_system');
        },

        checkUser: function () {
            if (window.userCollection.models.length === 0) {
                this.navigate("login", {trigger: true});
                return false;
            }
            return true;
        },

        login: function () {
            if (!this.loginView) {
                this.loginView = new window.loginView({
                    collection: window.userCollection
                });
            }
            this.loginView.render();
            this.naviView.selectMenuItem('');
        },

        collections: function () {
            var naviView = this.naviView;
            window.arangoCollectionsStore.fetch({
                success: function () {
                    window.collectionsView.render();
                    naviView.selectMenuItem('collections-menu');
                }
            });
        },

        collection: function (colid) {
            if (!this.collectionView) {
                this.collectionView = new window.CollectionView();
            }
            this.collectionView.setColId(colid);
            this.collectionView.render();
            this.naviView.selectMenuItem('collections-menu');
        },
        collectionInfo: function (colid) {
            if (!this.collectionInfoView) {
                this.collectionInfoView = new window.CollectionInfoView();
            }
            this.collectionInfoView.setColId(colid);
            this.collectionInfoView.render();
            this.naviView.selectMenuItem('collections-menu');
        },
        newCollection: function () {
            if (!this.newCollectionView) {
                this.newCollectionView = new window.newCollectionView({});
            }
            this.newCollectionView.render();
            this.naviView.selectMenuItem('collections-menu');
        },

        documents: function (colid, pageid) {
            if (!window.documentsView) {
                window.documentsView.initTable(colid, pageid);
            }
            window.documentsView.collectionID = colid;
            var type = arangoHelper.collectionApiType(colid);
            window.documentsView.colid = colid;
            window.documentsView.pageid = pageid;
            window.documentsView.type = type;
            window.documentsView.render();
            window.arangoDocumentsStore.getDocuments(colid, pageid);
        },

        document: function (colid, docid) {
            window.documentView.colid = colid;
            window.documentView.docid = docid;
            window.documentView.render();
            var type = arangoHelper.collectionApiType(colid);
            window.documentView.type = type;
            window.documentView.typeCheck(type);
        },

        shell: function () {
            if (!this.shellView) {
                this.shellView = new window.shellView();
            }
            this.shellView.render();
            this.naviView.selectMenuItem('tools-menu');
        },

        query: function () {
            if (!this.queryView) {
                this.queryView = new window.queryView();
            }
            this.queryView.render();
            this.naviView.selectMenuItem('query-menu');
        },

        api: function () {
            if (!this.apiView) {
                this.apiView = new window.apiView();
            }
            this.apiView.render();
            this.naviView.selectMenuItem('tools-menu');
        },

        databases: function () {
            if (arangoHelper.databaseAllowed() === true) {
                if (!this.databaseView) {
                    this.databaseView = new window.databaseView({
                        collection: arangoDatabase
                    });
                }
                this.databaseView.render();
                this.naviView.selectMenuItem('databases-menu');
            }
            else {
                this.navigate("#", {trigger: true});
                this.naviView.selectMenuItem('dashboard-menu');
                $('#databaseNavi').css('display', 'none');
                $('#databaseNaviSelect').css('display', 'none');
            }
        },

        logs: function () {
            if (!this.logsAllowed()) {
                this.navigate('', { trigger: true });
                return;
            }

            window.arangoLogsStore.fetch({
                success: function () {
                    window.logsView.render();
                    $('#logNav a[href="#all"]').tab('show');
                    window.logsView.initLogTables();
                    window.logsView.drawTable();
                    $('#all-switch').click();
                }
            });
            this.naviView.selectMenuItem('tools-menu');
        },

        dashboard: function () {
            this.naviView.selectMenuItem('dashboard-menu');
            if (this.statisticsDescriptionCollection === undefined) {
                this.statisticsDescriptionCollection = new window.StatisticsDescriptionCollection();
                this.statisticsDescriptionCollection.fetch({
                    async: false
                });
            }
            if (this.statistics === undefined) {
                this.statisticsCollection = new window.StatisticsCollection();
            }
            if (this.dashboardView === undefined) {
                this.dashboardView = new dashboardView({
                    collection: this.statisticsCollection,
                    description: this.statisticsDescriptionCollection,
                    documentStore: window.arangoDocumentsStore,
                    dygraphConfig: window.dygraphConfig
                });
            }
            this.dashboardView.render();
        },

        graph: function () {
            var self = this;
            window.arangoCollectionsStore.fetch({
                success: function () {
                    self.graphView.render();
                    self.naviView.selectMenuItem('graphviewer-menu');
                }
            });
        },

        graphManagement: function () {
            if (!this.graphManagementView) {
                this.graphManagementView =
                    new window.GraphManagementView({collection: this.graphs});
            }
            this.graphManagementView.render();
            this.naviView.selectMenuItem('graphviewer-menu');
        },

        graphAddNew: function () {
            if (!this.addNewGraphView) {
                this.addNewGraphView = new window.AddNewGraphView({
                    collection: window.arangoCollectionsStore,
                    graphs: this.graphs
                });
            }
            this.addNewGraphView.render();
            this.naviView.selectMenuItem('graphviewer-menu');
        },

        graphDelete: function (name) {
            if (!this.deleteGraphView) {
                this.deleteGraphView = new window.DeleteGraphView({
                    collection: this.graphs
                });
            }
            this.deleteGraphView.render(name);
            this.naviView.selectMenuItem('graphviewer-menu');
        },

        applications: function () {
            if (this.applicationsView === undefined) {
                this.applicationsView = new window.ApplicationsView({
                    collection: this.foxxList
                });
            }
            this.applicationsView.reload();
            this.naviView.selectMenuItem('applications-menu');
        },

        applicationEdit: function (appkey) {
            this.foxxList.fetch({
                async: false
            });
            var editAppView = new window.foxxEditView(
                {model: this.foxxList.findWhere({_key: appkey})}
            );
            editAppView.render();
        },

        applicationInstall: function (appkey) {
            this.foxxList.fetch({
                async: false
            });
            if (!this.installAppView) {
                this.installAppView = new window.foxxMountView({
                    collection: this.foxxList
                });
            }
            this.installAppView.render(appkey);
        },

        appDocumentation: function (key) {
            var docuView = new window.AppDocumentationView({key: key});
            docuView.render();
            this.naviView.selectMenuItem('applications-menu');
        },

        handleSelectDatabase: function () {
            this.naviView.handleSelectDatabase();
        },

        handleResize: function () {
            if (this.dashboardView) {
                this.dashboardView.resize();
            }
            var oldWidth = $('#content').width();
            var containerWidth = $(window).width() - 70;
            /*var spanWidth = 242;*/
            var spanWidth = 243;
            var divider = containerWidth / spanWidth;
            var roundDiv = parseInt(divider, 10);
            var newWidth = roundDiv * spanWidth - 2;
            var marginWidth = ((containerWidth + 30) - newWidth) / 2;
            /*
             $('#content').width(newWidth)
             .css('margin-left', marginWidth)
             .css('margin-right', marginWidth);
             */
            // $('.footer-right p').css('margin-right', marginWidth + 20);
            // $('.footer-left p').css('margin-left', marginWidth + 20);
            if (newWidth !== oldWidth) {
                this.graphView.handleResize(newWidth);
            }
        },

        userManagement: function () {
            if (!this.userManagementView) {
                this.userManagementView = new window.userManagementView({
                    collection: window.userCollection
                });
            }
            this.userManagementView.render();
            this.naviView.selectMenuItem('tools-menu');
        },

        userProfile: function () {
          if (!this.userManagementView) {
            this.userManagementView = new window.userManagementView({
                    collection: window.userCollection
                });
            }
          this.userManagementView.render(true);
          this.naviView.selectMenuItem('tools-menu');
        }
    });

}());
<|endoftext|>


<commit_before>/**
 * Created by Jackey Li on 2016/5/7.
 */
(function (global, factory) {

    if (typeof module === 'object' && typeof module.exports === 'object') {
        //var jQuery = require("jquery")(window);
        module.exports = glbal.document ? factory(global, true) : function (w) {
            if (!w.document) {
                throw new Error('');
            }
            return factory(w);
        };
    } else {
        factory(global);
    }

})(typeof window !== 'undefined' ? window : this, function (window, noGlobal) {

    }
);<commit_msg>refactor<commit_after>/**
 * Created by Jackey Li on 2016/5/7.
 */
(function (global, factory) {

    if (typeof module === 'object' && typeof module.exports === 'object') {
        //var jQuery = require("jquery")(window);
        module.exports = global.document ?
            factory(global, true) :
            function (w) {
                if (!w.document) {
                    throw new Error('jQuery requires a window with a document');
                }
                return factory(w);
            };
    } else {
        factory(global);
    }

})(typeof window !== 'undefined' ? window : this, function (window, noGlobal) {

    }
);<|endoftext|>


<commit_before>var dbm = global.dbm || require('db-migrate');
var type = dbm.dataType;

exports.up = function(db, callback) {
  db.createTable("early_vote_sites", {
    columns: {id: {type: 'uuid', primaryKey: true},
              election_id: {type: 'uuid',
                            notNull: true},
              county_fips: {type: 'string', notNull: true},
              type : {type: 'early_vote_site_type', notNull: true},
              name: {type: 'string', notNull: true},
              address_1: {type: 'string'},
              address_2: {type: 'string'},
              address_3: {type: 'string'},
              city: {type: 'string'},
              state: {type: 'string', notNull: true},
              zip: {type: 'string'},
              directions: {type: 'string'},
              voter_services: {type: 'string'}},
    ifNotExists: true
  }, callback);
};

exports.down = function(db, callback) {
  db.dropTable("early_vote_sites", {ifExists: true}, callback);
};
<commit_msg>city is also supposed to be a required field<commit_after>var dbm = global.dbm || require('db-migrate');
var type = dbm.dataType;

exports.up = function(db, callback) {
  db.createTable("early_vote_sites", {
    columns: {id: {type: 'uuid', primaryKey: true},
              election_id: {type: 'uuid',
                            notNull: true},
              county_fips: {type: 'string', notNull: true},
              type : {type: 'early_vote_site_type', notNull: true},
              name: {type: 'string', notNull: true},
              address_1: {type: 'string'},
              address_2: {type: 'string'},
              address_3: {type: 'string'},
              city: {type: 'string', notNull: true},
              state: {type: 'string', notNull: true},
              zip: {type: 'string'},
              directions: {type: 'string'},
              voter_services: {type: 'string'}},
    ifNotExists: true
  }, callback);
};

exports.down = function(db, callback) {
  db.dropTable("early_vote_sites", {ifExists: true}, callback);
};
<|endoftext|>


<commit_before>require('../support/helper');

var path = require("path")
  , expect = require("expect.js")
  , fs = require("fs")
  , Backbone = require("backbone")
  , Model = Backbone.Model
  , Collection = Backbone.Collection
  , generateTemplate = require("../support/generate_template")

describe("When I initialize a template with a model", function() {

  beforeEach(function() {
    this.model = new Model({ ohHi: "Hello There" })
    this.template = generateTemplate(this.model, '

')
  })

  it("should bind to the values", function () {
    expect($(".ohHi-").html()).to.be("Hello There")
  })

  it("should watch for changes to models", function() {
    expect($(".ohHi-").html()).to.be("Hello There")
    this.model.set("ohHi", "Good bye")
    expect($(".ohHi-").html()).to.be("Good bye")
  })
})

describe("when I initialize a collection", function() {

  beforeEach(function() {
    this.models = new Collection([new Model({ name: "Hawg" })])
    this.markup = '

'
    this.template = generateTemplate({ peeps: this.models }, this.markup)
  })

  it("should bind to a collection", function () {
    this.models.add(new Model({ name: "Dawg" }))
    expect($(".peeps- li:nth-child(1) .name-").html()).to.be("Hawg")
    expect($(".peeps- li:nth-child(2) .name-").html()).to.be("Dawg")
  })

  it("should bind to a collection's changes", function () {
    expect($(".peeps- li:nth-child(1) .name-").html()).to.be("Hawg")
    expect($(".peeps- li:nth-child(2) .name-").html()).to.be(undefined)

    this.models.add(new Model({ name: "Dawg" }))
    expect($(".peeps- li:nth-child(1) .name-").html()).to.be("Hawg")
    expect($(".peeps- li:nth-child(2) .name-").html()).to.be("Dawg")

    this.models.shift()
    expect($(".peeps- li:nth-child(1) .name-").html()).to.be("Dawg")
    expect($(".peeps- li:nth-child(2) .name-").html()).to.be(undefined)
  })
})
<commit_msg>test/deprecated/bind<commit_after>require('../support/helper');

var path = require("path"),
    expect = require("expect.js"),
    fs = require("fs"),
    Backbone = require("backbone"),
    Model = Backbone.Model,
    Collection = Backbone.Collection,
    generateTemplate = require("../support/generate_template");

describe("When I initialize a template with a model", function() {

  beforeEach(function() {
    this.model = new Model({ ohHi: "Hello There" });
    this.template = generateTemplate(this.model, '

');
  });

  it("should bind to the values", function () {
    expect($(".ohHi-").html()).to.be("Hello There");
  });

  it("should watch for changes to models", function() {
    expect($(".ohHi-").html()).to.be("Hello There");
    this.model.set("ohHi", "Good bye");
    expect($(".ohHi-").html()).to.be("Good bye");
  });
});

describe("when I initialize a collection", function() {

  beforeEach(function() {
    this.models = new Collection([new Model({ name: "Hawg" })]);
    this.markup = '

';
    this.template = generateTemplate({ peeps: this.models }, this.markup);
  });

  it("should bind to a collection", function () {
    this.models.add(new Model({ name: "Dawg" }));
    expect($(".peeps- li:nth-child(1) .name-").html()).to.be("Hawg");
    expect($(".peeps- li:nth-child(2) .name-").html()).to.be("Dawg");
  });

  it("should bind to a collection's changes", function () {
    expect($(".peeps- li:nth-child(1) .name-").html()).to.be("Hawg");
    expect($(".peeps- li:nth-child(2) .name-").html()).to.be(undefined);

    this.models.add(new Model({ name: "Dawg" }));
    expect($(".peeps- li:nth-child(1) .name-").html()).to.be("Hawg");
    expect($(".peeps- li:nth-child(2) .name-").html()).to.be("Dawg");

    this.models.shift();
    expect($(".peeps- li:nth-child(1) .name-").html()).to.be("Dawg");
    expect($(".peeps- li:nth-child(2) .name-").html()).to.be(undefined);
  });
});
<|endoftext|>


<commit_before>import {expect, testInjectMatch} from 'singpath-core/tools/chai.js';

import * as firebase from './firebase.js';

describe('firebase service', function() {

  describe('cleanObj', function() {

    it('should remove invalid key', function() {
      expect(firebase.cleanObj({$foo: 1, foo: 2})).to.eql({foo: 2});
    });

    it('should convert undefined value to null', function() {
      expect(firebase.cleanObj(undefined)).to.be.null();
    });

    it('should leave literal values unchanged', function() {
      expect(firebase.cleanObj(1)).to.equal(1);
      expect(firebase.cleanObj('foo')).to.equal('foo');
    });

    it('should leave date values unchanged', function() {
      const value = new Date();

      expect(firebase.cleanObj(value)).to.equal(value);
    });

    it('should clean array members', function() {
      const value = [1, 2, undefined, {$foo: 1, foo: 2}];

      expect(firebase.cleanObj(value)).to.eql([1, 2, null, {foo: 2}]);
    });

    it('should clean object properties', function() {
      const value = {foo: 1, bar: 2, baz: undefined, fooz: {$foo: 1, foo: 2}};

      expect(firebase.cleanObj(value)).to.eql({foo: 1, bar: 2, baz: null, fooz: {foo: 2}});
    });

  });

  describe('run', function() {

    testInjectMatch(firebase.run);

    it('should throw if one of the app is not set', function() {
      expect(() => firebase.run({}, null, {})).to.throw(Error);
      expect(() => firebase.run(null, {}, {})).to.throw(Error);
    });

    it('should throw if the provider is not set', function() {
      expect(() => firebase.run({}, {}, null)).to.throw(Error);
    });

    it('should not throw if both app and provider are set', function() {
      expect(() => firebase.run({}, {}, {})).not.to.throw(Error);
    });

  });

});
<commit_msg>Fix firebase helpers tests<commit_after>import {expect, testInjectMatch, sinon} from 'singpath-core/tools/chai.js';

import * as firebase from './firebase.js';

describe('firebase service', function() {

  describe('cleanObj', function() {

    it('should remove invalid key', function() {
      expect(firebase.cleanObj({$foo: 1, foo: 2})).to.eql({foo: 2});
    });

    it('should convert undefined value to null', function() {
      expect(firebase.cleanObj(undefined)).to.be.null();
    });

    it('should leave literal values unchanged', function() {
      expect(firebase.cleanObj(1)).to.equal(1);
      expect(firebase.cleanObj('foo')).to.equal('foo');
    });

    it('should leave date values unchanged', function() {
      const value = new Date();

      expect(firebase.cleanObj(value)).to.equal(value);
    });

    it('should clean array members', function() {
      const value = [1, 2, undefined, {$foo: 1, foo: 2}];

      expect(firebase.cleanObj(value)).to.eql([1, 2, null, {foo: 2}]);
    });

    it('should clean object properties', function() {
      const value = {foo: 1, bar: 2, baz: undefined, fooz: {$foo: 1, foo: 2}};

      expect(firebase.cleanObj(value)).to.eql({foo: 1, bar: 2, baz: null, fooz: {foo: 2}});
    });

  });

  describe('run', function() {
    let $log, firebaseApp, authFirebaseApp, authProvider;

    beforeEach(function() {
      $log = {info: sinon.spy()};
      firebaseApp = {options: {authDomain: 'singpath.firebaseio.com'}};
      authFirebaseApp = {options: {authDomain: 'singpath.firebaseio.com'}};
      authProvider = {};
    });

    testInjectMatch(firebase.run);

    it('should throw if firebaseApp is not set', function() {
      firebaseApp = null;
      expect(() => firebase.run($log, firebaseApp, authFirebaseApp, authProvider)).to.throw(Error);
    });

    it('should throw if authFirebaseApp is not set', function() {
      authFirebaseApp = null;
      expect(() => firebase.run($log, firebaseApp, authFirebaseApp, authProvider)).to.throw(Error);
    });

    it('should throw if the provider is not set', function() {
      authProvider = null;
      expect(() => firebase.run($log, firebaseApp, authFirebaseApp, authProvider)).to.throw(Error);
    });

    it('should not throw if both app and provider are set', function() {
      expect(() => firebase.run($log, firebaseApp, authFirebaseApp, authProvider)).to.not.throw(Error);
    });

  });

});
<|endoftext|>


<commit_before>// create a variable to store the products 'database' in
var products;

// use fetch to retrieve it, and report any errors that occur in the fetch operation
// once the products have been successfully loaded and formatted as a JSON object
// using response.json(), run the initialize() function
fetch('products.json').then(function(response) {
  if(response.ok) {
    response.json().then(function(json) {
      products = json;
      initialize();
    });
  } else {
    console.log('Network request for products.json failed with response ' + response.status + ': ' + response.statusText);
  }
});

// sets up the app logic, declares required variables, contains all the other functions
function initialize() {
  // grab the UI elements that we need to manipulate
  var category = document.querySelector('#category');
  var searchTerm = document.querySelector('#searchTerm');
  var searchBtn = document.querySelector('button');
  var main = document.querySelector('main');

  // keep a record of what the last category and search term entered were
  var lastCategory = category.value;
  // no search has been made yet
  var lastSearch = '';

  // these contain the results of filtering by category, and search term
  // finalGroup will contain the products that need to be displayed after
  // the searching has been done. Each will be an array containing objects.
  // Each object will represent a product
  var categoryGroup;
  var finalGroup;

  // To start with, set finalGroup to equal the entire products database
  // then run updateDisplay(), so ALL products are displayed initially.
  finalGroup = products;
  updateDisplay();

  // Set both to equal an empty array, in time for searches to be run
  categoryGroup = [];
  finalGroup = [];

  // when the search button is clicked, invoke selectCategory() to start
  // a search running to select the category of products we want to display
  searchBtn.onclick = selectCategory;

  function selectCategory(e) {
    // Use preventDefault() to stop the form submitting — that would ruin
    // the experience
    e.preventDefault();

    // Set these back to empty arrays, to clear out the previous search
    categoryGroup = [];
    finalGroup = [];

    // if the category and search term are the same as they were the last time a
    // search was run, the results will be the same, so there is no point running
    // it again — just return out of the function
    if(category.value === lastCategory && searchTerm.value === lastSearch) {
      return;
    } else {
      // update the record of last category and search term
      lastCategory = category.value;
      lastSearch = searchTerm.value;
      // In this case we want to select all products, then filter them by the search
      // term, so we just set categoryGroup to the entire JSON object, then run selectProducts()
      if(category.value === 'All') {
        categoryGroup = products;
        selectProducts();
      // If a specific category is chosen, we need to filter out the products not in that
      // category, then put the remaining products inside categoryGroup, before running
      // selectProducts()
      } else {
        // the values in the <option> elements are uppercase, whereas the categories
        // store in the JSON (under "type") are lowercase. We therefore need to convert
        // to lower case before we do a comparison
        var lowerCaseType = category.value.toLowerCase();
        for(var i = 0; i < products.length ; i++) {
          // If a product's type property is the same as the chosen category, we want to
          // dispay it, so we push it onto the categoryGroup array
          if(products[i].type === lowerCaseType) {
            categoryGroup.push(products[i]);
          }
        }

        // Run selectProducts() after the filtering has bene done
        selectProducts();
      }
    }
  }

  // selectProducts() Takes the group of products selected by selectCategory(), and further
  // filters them by the tnered search term (if one has bene entered)
  function selectProducts() {
    // If no search term has been entered, just make the finalGroup array equal to the categoryGroup
    // array — we don't want to filter the products further — then run updateDisplay().
    if(searchTerm.value === '') {
      finalGroup = categoryGroup;
      updateDisplay();
    } else {
      // Make sure the search term is converted to lower case before comparison. We've kept the
      // product names all lower case to keep things simple
      var lowerCaseSearchTerm = searchTerm.value.toLowerCase();
      // For each product in categoryGroup, see if the search term is contained inside the product name
      // (if the indexOf() result doesn't return -1, it means it is) — if it is, then push the product
      // onto the finalGroup array
      for(var i = 0; i < categoryGroup.length ; i++) {
        if(categoryGroup[i].name.indexOf(lowerCaseSearchTerm) !== -1) {
          finalGroup.push(categoryGroup[i]);
        }
      }

      // run updateDisplay() after this second round of filtering has been done
      updateDisplay();
    }

  }

  // start the process of updating the display with the new set of products
  function updateDisplay() {
    // remove the previous contents of the <main> element
    while (main.firstChild) {
      main.removeChild(main.firstChild);
    }

    // if no products match the search term, display a "No results to display" message
    if(finalGroup.length === 0) {
      var para = document.createElement('p');
      para.textContent = 'No results to display!';
      main.appendChild(para);
    // for each product we want to display, pass its product object to fetchBlob()
    } else {
      for(var i = 0; i < finalGroup.length; i++) {
        fetchBlob(finalGroup[i]);
      }
    }
  }

  // fetchBlob uses fetch to retrieve the image for that product, and then sends the
  // resulting image display URL and product object on to showProduct() to finally
  // display it
  function fetchBlob(product) {
    // construct the URL path to the image file from the product.image property
    var url = 'images/' + product.image;
    // Use fetch to fetch the image, and convert the resulting response to a blob
    // Again, if any errors occur we report them in the console.
    fetch(url).then(function(response) {
      if(response.ok) {
        response.blob().then(function(blob) {
          // Convert the blob to an object URL — this is basically an temporary internal URL
          // that points to an object stored inside the browser
          objectURL = URL.createObjectURL(blob);
          // invoke showProduct
          showProduct(objectURL, product);
        });
      } else {
        console.log('Network request for "' + product.name + '" image failed with response ' + response.status + ': ' + response.statusText);
      }
    });
  }

  // Display a product inside the <main> element
  function showProduct(objectURL, product) {
    // create <section>, <h2>, <p>, and <img> elements
    var section = document.createElement('section');
    var heading = document.createElement('h2');
    var para = document.createElement('p');
    var image = document.createElement('img');

    // give the <section> a classname equal to the product "type" property so it will display the correct icon
    section.setAttribute('class', product.type);

    // Give the <h2> textContent equal to the product "name" property, but with the first character
    // replaced with the uppercase version of the first character
    heading.textContent = product.name.replace(product.name.charAt(0), product.name.charAt(0).toUpperCase());

    // Give the <p> textContent equal to the product "price" property, with a $ sign in front
    // toFixed(2) is used to fix the price at 2 decimal places, so for example 1.40 is displayed
    // as 1.40, not 1.4.
    para.textContent = '$' + product.price.toFixed(2);

    // Set the src of the <img> element to the ObjectURL, and the alt to the product "name" property
    image.src = objectURL;
    image.alt = product.name;

    // append the elements to the DOM as appropriate, to add the product to the UI
    main.appendChild(section);
    section.appendChild(heading);
    section.appendChild(para);
    section.appendChild(image);
  }
}
<commit_msg>Removes trailing/leading whitespaces from the search query<commit_after>// create a variable to store the products 'database' in
var products;

// use fetch to retrieve it, and report any errors that occur in the fetch operation
// once the products have been successfully loaded and formatted as a JSON object
// using response.json(), run the initialize() function
fetch('products.json').then(function(response) {
  if(response.ok) {
    response.json().then(function(json) {
      products = json;
      initialize();
    });
  } else {
    console.log('Network request for products.json failed with response ' + response.status + ': ' + response.statusText);
  }
});

// sets up the app logic, declares required variables, contains all the other functions
function initialize() {
  // grab the UI elements that we need to manipulate
  var category = document.querySelector('#category');
  var searchTerm = document.querySelector('#searchTerm');
  var searchBtn = document.querySelector('button');
  var main = document.querySelector('main');

  // keep a record of what the last category and search term entered were
  var lastCategory = category.value;
  // no search has been made yet
  var lastSearch = '';

  // these contain the results of filtering by category, and search term
  // finalGroup will contain the products that need to be displayed after
  // the searching has been done. Each will be an array containing objects.
  // Each object will represent a product
  var categoryGroup;
  var finalGroup;

  // To start with, set finalGroup to equal the entire products database
  // then run updateDisplay(), so ALL products are displayed initially.
  finalGroup = products;
  updateDisplay();

  // Set both to equal an empty array, in time for searches to be run
  categoryGroup = [];
  finalGroup = [];

  // when the search button is clicked, invoke selectCategory() to start
  // a search running to select the category of products we want to display
  searchBtn.onclick = selectCategory;

  function selectCategory(e) {
    // Use preventDefault() to stop the form submitting — that would ruin
    // the experience
    e.preventDefault();

    // Set these back to empty arrays, to clear out the previous search
    categoryGroup = [];
    finalGroup = [];

    // if the category and search term are the same as they were the last time a
    // search was run, the results will be the same, so there is no point running
    // it again — just return out of the function
    if(category.value === lastCategory && searchTerm.value.trim() === lastSearch) {
      return;
    } else {
      // update the record of last category and search term
      lastCategory = category.value;
      lastSearch = searchTerm.value.trim();
      // In this case we want to select all products, then filter them by the search
      // term, so we just set categoryGroup to the entire JSON object, then run selectProducts()
      if(category.value === 'All') {
        categoryGroup = products;
        selectProducts();
      // If a specific category is chosen, we need to filter out the products not in that
      // category, then put the remaining products inside categoryGroup, before running
      // selectProducts()
      } else {
        // the values in the <option> elements are uppercase, whereas the categories
        // store in the JSON (under "type") are lowercase. We therefore need to convert
        // to lower case before we do a comparison
        var lowerCaseType = category.value.toLowerCase();
        for(var i = 0; i < products.length ; i++) {
          // If a product's type property is the same as the chosen category, we want to
          // dispay it, so we push it onto the categoryGroup array
          if(products[i].type === lowerCaseType) {
            categoryGroup.push(products[i]);
          }
        }

        // Run selectProducts() after the filtering has bene done
        selectProducts();
      }
    }
  }

  // selectProducts() Takes the group of products selected by selectCategory(), and further
  // filters them by the tnered search term (if one has bene entered)
  function selectProducts() {
    // If no search term has been entered, just make the finalGroup array equal to the categoryGroup
    // array — we don't want to filter the products further — then run updateDisplay().
    if(searchTerm.value.trim() === '') {
      finalGroup = categoryGroup;
      updateDisplay();
    } else {
      // Make sure the search term is converted to lower case before comparison. We've kept the
      // product names all lower case to keep things simple
      var lowerCaseSearchTerm = searchTerm.value.trim().toLowerCase();
      // For each product in categoryGroup, see if the search term is contained inside the product name
      // (if the indexOf() result doesn't return -1, it means it is) — if it is, then push the product
      // onto the finalGroup array
      for(var i = 0; i < categoryGroup.length ; i++) {
        if(categoryGroup[i].name.indexOf(lowerCaseSearchTerm) !== -1) {
          finalGroup.push(categoryGroup[i]);
        }
      }

      // run updateDisplay() after this second round of filtering has been done
      updateDisplay();
    }

  }

  // start the process of updating the display with the new set of products
  function updateDisplay() {
    // remove the previous contents of the <main> element
    while (main.firstChild) {
      main.removeChild(main.firstChild);
    }

    // if no products match the search term, display a "No results to display" message
    if(finalGroup.length === 0) {
      var para = document.createElement('p');
      para.textContent = 'No results to display!';
      main.appendChild(para);
    // for each product we want to display, pass its product object to fetchBlob()
    } else {
      for(var i = 0; i < finalGroup.length; i++) {
        fetchBlob(finalGroup[i]);
      }
    }
  }

  // fetchBlob uses fetch to retrieve the image for that product, and then sends the
  // resulting image display URL and product object on to showProduct() to finally
  // display it
  function fetchBlob(product) {
    // construct the URL path to the image file from the product.image property
    var url = 'images/' + product.image;
    // Use fetch to fetch the image, and convert the resulting response to a blob
    // Again, if any errors occur we report them in the console.
    fetch(url).then(function(response) {
      if(response.ok) {
        response.blob().then(function(blob) {
          // Convert the blob to an object URL — this is basically an temporary internal URL
          // that points to an object stored inside the browser
          objectURL = URL.createObjectURL(blob);
          // invoke showProduct
          showProduct(objectURL, product);
        });
      } else {
        console.log('Network request for "' + product.name + '" image failed with response ' + response.status + ': ' + response.statusText);
      }
    });
  }

  // Display a product inside the <main> element
  function showProduct(objectURL, product) {
    // create <section>, <h2>, <p>, and <img> elements
    var section = document.createElement('section');
    var heading = document.createElement('h2');
    var para = document.createElement('p');
    var image = document.createElement('img');

    // give the <section> a classname equal to the product "type" property so it will display the correct icon
    section.setAttribute('class', product.type);

    // Give the <h2> textContent equal to the product "name" property, but with the first character
    // replaced with the uppercase version of the first character
    heading.textContent = product.name.replace(product.name.charAt(0), product.name.charAt(0).toUpperCase());

    // Give the <p> textContent equal to the product "price" property, with a $ sign in front
    // toFixed(2) is used to fix the price at 2 decimal places, so for example 1.40 is displayed
    // as 1.40, not 1.4.
    para.textContent = '$' + product.price.toFixed(2);

    // Set the src of the <img> element to the ObjectURL, and the alt to the product "name" property
    image.src = objectURL;
    image.alt = product.name;

    // append the elements to the DOM as appropriate, to add the product to the UI
    main.appendChild(section);
    section.appendChild(heading);
    section.appendChild(para);
    section.appendChild(image);
  }
}
<|endoftext|>


<commit_before>import React from 'react'
import { Global } from '@emotion/core'
import { GlobalStyles } from '../styles/globalStyles.js'
import { motion, AnimatePresence } from 'framer-motion'

import Helmet from './Helmet'
import Menu from '../components/Menu'
import Footer from '../components/Footer'

if (typeof window !== 'undefined') {
  // eslint-disable-next-line global-require
  require('smooth-scroll')('a[href*="#"]')
}

const duration = 0.5

const variants = {
  initial: {
    opacity: 0,
  },
  enter: {
    opacity: 1,
    transition: {
      duration: duration,
      delay: duration,
      when: 'beforeChildren',
    },
  },
  exit: {
    opacity: 0,
    transition: { duration: duration },
  },
}

const Layout = ({ children }) => {
  return (
    <>
      <Helmet />
      <Global styles={GlobalStyles} />

        <Menu />
        <AnimatePresence>
          <motion.main
            key={location.pathname}
            variants={variants}
            initial="initial"
            animate="enter"
            exit="exit"
          >
            {children}
          </motion.main>
        </AnimatePresence>

    </>
  )
}

export default Layout
<commit_msg>Add location<commit_after>import React from 'react'
import { Global } from '@emotion/core'
import { GlobalStyles } from '../styles/globalStyles.js'
import { motion, AnimatePresence } from 'framer-motion'

import Helmet from './Helmet'
import Menu from '../components/Menu'
import Footer from '../components/Footer'

if (typeof window !== 'undefined') {
  // eslint-disable-next-line global-require
  require('smooth-scroll')('a[href*="#"]')
}

const duration = 0.5

const variants = {
  initial: {
    opacity: 0,
  },
  enter: {
    opacity: 1,
    transition: {
      duration: duration,
      delay: duration,
      when: 'beforeChildren',
    },
  },
  exit: {
    opacity: 0,
    transition: { duration: duration },
  },
}

const Layout = ({ children, location }) => {
  return (
    <>
      <Helmet />
      <Global styles={GlobalStyles} />

        <Menu />
        <AnimatePresence>
          <motion.main
            key={location.pathname}
            variants={variants}
            initial="initial"
            animate="enter"
            exit="exit"
          >
            {children}
          </motion.main>
        </AnimatePresence>

    </>
  )
}

export default Layout
<|endoftext|>


<commit_before>var webpack = require('webpack');
var path = require('path');

module.exports = {
  devtool: 'cheap-module-source-map',
  entry: './src/index.js',
  output: {
    path: path.join(__dirname, 'app'),
    filename: 'bundle.js',
    publicPath: '/app/',
  },
  module: {
    loaders: [{
      test: /\.jsx?$/,
      exclude: /node_modules/,
      loader: 'babel'
    }, {
      test: /\.css$/,
      loader: 'style!css'
    }, {
      test: /\.scss$/,
      loaders: ['style', 'css', 'sass']
    }, {
      test: /\.less$/,
      loader: 'style!css!less'
    }, {
      test: /\.json$/,
      loader: 'json-loader'
    },
    {
      test: /\.(png|jpg)$/,
      loader: 'file-loader?name=assets/[name].[ext]',
    },
    {
      test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
      loader: 'url?limit=10000&mimetype=application/font-woff'
    },
    {
      test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
      loader: 'url?limit=10000&mimetype=application/octet-stream'
    },
    {
      test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
      loader: 'file',
    },
    {
      test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
      loader: 'url?limit=10000&mimetype=image/svg+xml'
    }],
  },
  resolve: {
    modulesDirectories: ['./node_modules', './src', './assets'],
    extensions: ['', '.js', '.jsx', '.json', '.scss', '.png']
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify('production'),
      },
      'process.env.PAPERNET_HOST': JSON.stringify('https://bobi.space'),
    }),
  ],
};
<commit_msg>add babel-polyfill to prod config for redux saga<commit_after>var webpack = require('webpack');
var path = require('path');

module.exports = {
  devtool: 'cheap-module-source-map',
  entry: [
    'babel-polyfill',
    './src/index.js'
  ],
  output: {
    path: path.join(__dirname, 'app'),
    filename: 'bundle.js',
    publicPath: '/app/',
  },
  module: {
    loaders: [{
      test: /\.jsx?$/,
      exclude: /node_modules/,
      loader: 'babel'
    }, {
      test: /\.css$/,
      loader: 'style!css'
    }, {
      test: /\.scss$/,
      loaders: ['style', 'css', 'sass']
    }, {
      test: /\.less$/,
      loader: 'style!css!less'
    }, {
      test: /\.json$/,
      loader: 'json-loader'
    },
    {
      test: /\.(png|jpg)$/,
      loader: 'file-loader?name=assets/[name].[ext]',
    },
    {
      test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
      loader: 'url?limit=10000&mimetype=application/font-woff'
    },
    {
      test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
      loader: 'url?limit=10000&mimetype=application/octet-stream'
    },
    {
      test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
      loader: 'file',
    },
    {
      test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
      loader: 'url?limit=10000&mimetype=image/svg+xml'
    }],
  },
  resolve: {
    modulesDirectories: ['./node_modules', './src', './assets'],
    extensions: ['', '.js', '.jsx', '.json', '.scss', '.png']
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify('production'),
      },
      'process.env.PAPERNET_HOST': JSON.stringify('https://bobi.space'),
    }),
  ],
};
<|endoftext|>


<commit_before>angular.module('main').
	factory('recentlyViewed', ['$window', function($window) {
		var recent;

		if( $window.sessionStorage !== undefined ) {
			recent = $window.sessionStorage;
		}
		else {
			recent = {
				setItem: function(key, item) {
					this[key] = item;
				},

				getItem: function(key) {
					return this[key] || null;
				},

				clear: function() {
					for (key in this) {
						delete this[key];
					}
				}
			};
		}

		var recently_viewed = {
			items: JSON.parse(recent.getItem('recentlyViewed')) || [],

			put: function(item) {
				var recent_item = this.items.filter(function(recent_item) {
					return item._id == recent_item._id;
				})[0];
				if (recent_item) {
					var index = this.items.indexOf(recent_item);
					this.items.splice(index, 1);
				}
				this.items.push(item);
				recent.setItem('recentlyViewed', JSON.stringify(this.items));
			},

			clear: function() {
				this.items = [];
			}
		};

		return recently_viewed;
	}]);<commit_msg>limit recently viewed items to 50<commit_after>angular.module('main').
	factory('recentlyViewed', ['$window', function($window) {
		var recent;
		var max_items = 50;

		if( $window.sessionStorage !== undefined ) {
			recent = $window.sessionStorage;
		}
		else {
			recent = {
				setItem: function(key, item) {
					this[key] = item;
				},

				getItem: function(key) {
					return this[key] || null;
				},

				clear: function() {
					for (key in this) {
						delete this[key];
					}
				}
			};
		}

		var recently_viewed = {
			items: JSON.parse(recent.getItem('recentlyViewed')) || [],

			put: function(item) {
				var recent_item = this.items.filter(function(recent_item) {
					return item._id == recent_item._id;
				})[0];
				if (recent_item) {
					var index = this.items.indexOf(recent_item);
					this.items.splice(index, 1);
				}
				else if (this.items.length > max_items) {
					this.items.splice(0, 1);
				}

				this.items.push(item);

				recent.setItem('recentlyViewed', JSON.stringify(this.items));
			},

			clear: function() {
				this.items = [];
			}
		};

		return recently_viewed;
	}]);<|endoftext|>


<commit_before>import analyse from './analyse';
import treePath from './path';
import ground from './ground';
import promotion from './promotion';
import * as util from './util';
import sound from '../../sound';
import { throttle, debounce } from 'lodash/function';
import socket from '../../socket';
import cevalCtrl from './ceval/cevalCtrl';
import gameApi from '../../lichess/game';
import settings from '../../settings';
import { backHistory, handleXhrError, oppositeColor } from '../../utils';
import { getAnalyseData, getCurrentOTBGame, getCurrentAIGame } from '../../utils/offlineGames';
import { game as gameXhr } from '../../xhr';
import makeData, { defaultData } from './data';
import chessLogic from './chessLogic';
import menu from './menu';
import m from 'mithril';

export default function controller() {
  const source = m.route.param('source');
  const gameId = m.route.param('id');
  const orientation = m.route.param('color');

  this.data = null;

  this.menu = menu.controller(this);

  this.vm = {
    path: null,
    pathStr: '',
    initialPathStr: '',
    step: null,
    cgConfig: null,
    comments: true,
    flip: false,
    variationMenu: null
  };

  this.flip = function() {
    this.vm.flip = !this.vm.flip;
    this.chessground.set({
      orientation: this.vm.flip ? this.data.opponent.color : this.data.player.color
    });
  }.bind(this);

  function uciToLastMove(uci) {
    if (!uci) return null;
    if (uci[1] === '@') return [uci.substr(2, 2), uci.substr(2, 2)];
    return [uci.substr(0, 2), uci.substr(2, 2)];
  }

  const startCeval = function() {
    if (this.ceval.enabled() && this.canUseCeval())
      this.ceval.start(this.vm.path, this.analyse.getSteps(this.vm.path));
  }.bind(this);

  const debouncedStartCeval = debounce(startCeval, 500);
  const debouncedDests = debounce(getDests.bind(this), 100);

  const showGround = function() {
    var s;
    try {
      s = this.analyse.getStep(this.vm.path);
    } catch (e) {
      console.log(e);
    }
    if (!s) {
      this.vm.path = treePath.default(this.analyse.firstPly());
      this.vm.pathStr = treePath.write(this.vm.path);
      s = this.analyse.getStep(this.vm.path);
    }
    const color = s.ply % 2 === 0 ? 'white' : 'black';
    const dests = util.readDests(s.dests);
    const drops = util.readDrops(s.drops);
    const config = {
      fen: s.fen,
      turnColor: color,
      orientation: this.data.orientation,
      movable: {
        color: (dests && Object.keys(dests).length > 0) || drops === null || drops.length ? color : null,
        dests: dests || {}
      },
      check: s.check,
      lastMove: uciToLastMove(s.uci)
    };
    this.vm.step = s;
    this.vm.cgConfig = config;
    if (!this.chessground)
      this.chessground = ground.make(this.data, config, userMove.bind(this), userNewPiece.bind(this));
    this.chessground.set(config);
    if (!dests) debouncedDests();
  }.bind(this);

  const throttledScroll = throttle(() => util.autoScroll(document.getElementById('replay')), 300);

  this.jump = function(path) {
    this.vm.path = path;
    this.vm.pathStr = treePath.write(path);
    this.toggleVariationMenu(null);
    showGround();
    if (!this.vm.step.uci) sound.move(); // initial position
    else if (this.vm.justPlayed !== this.vm.step.uci) {
      if (this.vm.step.san.indexOf('x') !== -1) sound.capture();
      else sound.move();
      this.vm.justPlayed = null;
    }
    this.ceval.stop();
    debouncedStartCeval();
    throttledScroll();
    promotion.cancel(this);
  }.bind(this);

  this.userJump = function(path) {
    this.jump(path);
  }.bind(this);

  this.jumpToMain = function(ply) {
    this.userJump([{
      ply: ply,
      variation: null
    }]);
  }.bind(this);

  this.jumpToIndex = function(index) {
    this.jumpToMain(index + 1 + this.data.game.startedAtTurn);
  }.bind(this);

  this.jumpToNag = function(color, nag) {
    var ply = this.analyse.plyOfNextNag(color, nag, this.vm.step.ply);
    if (ply) this.jumpToMain(ply);
    m.redraw();
  }.bind(this);

  function userNewPiece() {
    this.jump(this.vm.path);
  }

  const preparePremoving = function() {
    this.chessground.set({
      turnColor: this.chessground.data.movable.color,
      movable: {
        color: oppositeColor(this.chessground.data.movable.color)
      }
    });
  }.bind(this);

  const sendMove = function(orig, dest, prom) {
    const move = {
      orig: orig,
      dest: dest,
      variant: this.data.game.variant.key,
      fen: this.vm.step.fen,
      path: this.vm.pathStr,
      ply: this.vm.step.ply
    };
    if (prom) move.promotion = prom;
    this.chessLogic.sendMoveRequest(move);
    preparePremoving();
  }.bind(this);

  function userMove(orig, dest, capture) {
    this.vm.justPlayed = orig + dest;
    sound[capture ? 'capture' : 'move']();
    if (!promotion.start(this, orig, dest, sendMove)) sendMove(orig, dest);
  }

  this.addStep = function(step, path) {
    const newPath = this.analyse.addStep(step, treePath.read(path));
    this.jump(newPath);
    m.redraw();
    this.chessground.playPremove();
  }.bind(this);

  this.addDests = function(dests, path) {
    this.analyse.addDests(dests, treePath.read(path));
    if (path === this.vm.pathStr) {
      showGround();
      m.redraw();
      if (dests === '') this.ceval.stop();
    }
    this.chessground.playPremove();
  }.bind(this);

  this.toggleVariationMenu = function(path) {
    if (!path) this.vm.variationMenu = null;
    else {
      var key = treePath.write(path.slice(0, 1));
      this.vm.variationMenu = this.vm.variationMenu === key ? null : key;
    }
  }.bind(this);

  this.deleteVariation = function(path) {
    var ply = path[0].ply;
    var id = path[0].variation;
    this.analyse.deleteVariation(ply, id);
    if (treePath.contains(path, this.vm.path)) this.jumpToMain(ply - 1);
    this.toggleVariationMenu(null);
  }.bind(this);

  this.promoteVariation = function(path) {
    var ply = path[0].ply;
    var id = path[0].variation;
    this.analyse.promoteVariation(ply, id);
    if (treePath.contains(path, this.vm.path))
      this.jump(this.vm.path.splice(1));
    this.toggleVariationMenu(null);
  }.bind(this);

  this.reset = function() {
    this.chessground.set(this.vm.situation);
    m.redraw();
  }.bind(this);

  this.encodeStepFen = function() {
    return this.vm.step.fen.replace(/\s/g, '_');
  }.bind(this);

  this.currentAnyEval = function() {
    return this.vm.step ? (this.vm.step.oEval || this.vm.step.ceval) : null;
  }.bind(this);

  const allowCeval = function() {
    return (
      util.isSynthetic(this.data) || !gameApi.playable(this.data)
    ) && ['standard', 'fromPosition', 'chess960'].indexOf(this.data.game.variant.key) !== -1;
  }.bind(this);

  function onCevalMsg(res) {
    this.analyse.updateAtPath(res.work.path, function(step) {
      if (step.ceval && step.ceval.depth >= res.ceval.depth) return;
      step.ceval = res.ceval;
      if (treePath.write(res.work.path) === this.vm.pathStr) {
        m.redraw();
      }
    }.bind(this));
  }

  this.canUseCeval = function() {
    return this.vm.step.dests !== '' && (!this.vm.step.oEval || !this.analyse.nextStepEvalBest(this.vm.path));
  }.bind(this);

  this.nextStepBest = function() {
    return this.analyse.nextStepEvalBest(this.vm.path);
  }.bind(this);

  this.toggleCeval = function() {
    this.ceval.toggle();
    debouncedStartCeval();
  }.bind(this);

  this.showEvalGauge = function() {
    return this.hasAnyComputerAnalysis() && settings.analyse.showGauge() && this.vm.step.dests !== '';
  }.bind(this);

  this.hasAnyComputerAnalysis = function() {
    return this.data.analysis || this.ceval.enabled();
  };

  this.toggleGauge = function() {
    settings.analyse.showGauge(!settings.analyse.showGauge());
  };

  this.onunload = function() {
    if (this.ceval) this.ceval.stop();
    socket.destroy();
  }.bind(this);

  const init = function(data) {
    this.data = data;
    if (!data.game.moveTimes) this.data.game.moveTimes = [];
    console.log(this.data);
    this.ongoing = !util.isSynthetic(this.data) && gameApi.playable(this.data);
    this.chessLogic = new chessLogic(this);
    this.analyse = new analyse(this.data.steps);
    this.ceval = cevalCtrl(allowCeval(), onCevalMsg.bind(this));

    var initialPath = treePath.default(this.analyse.firstPly());
    if (initialPath[0].ply >= this.data.steps.length) {
      initialPath = treePath.default(this.data.steps.length - 1);
    }

    this.vm.path = initialPath;
    this.vm.pathStr = treePath.write(initialPath);

    showGround();
    startCeval();
  }.bind(this);

  if (source === 'online' && gameId) {
    gameXhr(gameId, orientation, false).then(function(cfg) {
      init(makeData(cfg));
      m.redraw();
    }, err => {
      handleXhrError(err);
      m.route('/');
    });
  } else if (source === 'offline' && gameId === 'otb') {
    const otbData = getAnalyseData(getCurrentOTBGame());
    if (!otbData) backHistory();
    else {
      otbData.orientation = orientation;
      init(otbData);
    }
  } else if (source === 'offline' && gameId === 'ai') {
    const aiData = getAnalyseData(getCurrentAIGame());
    if (!aiData) backHistory();
    else {
      aiData.orientation = orientation;
      init(aiData);
    }
  }
  else {
    init(defaultData);
  }

}

function getDests() {
  if (!this.vm.step.dests) {
    this.chessLogic.sendDestsRequest({
      variant: this.data.game.variant.key,
      fen: this.vm.step.fen,
      path: this.vm.pathStr
    });
  }
}

<commit_msg>Add analytics and prevent sleep<commit_after>import analyse from './analyse';
import treePath from './path';
import ground from './ground';
import promotion from './promotion';
import * as util from './util';
import sound from '../../sound';
import { throttle, debounce } from 'lodash/function';
import socket from '../../socket';
import cevalCtrl from './ceval/cevalCtrl';
import helper from '../helper';
import gameApi from '../../lichess/game';
import settings from '../../settings';
import { backHistory, handleXhrError, oppositeColor } from '../../utils';
import { getAnalyseData, getCurrentOTBGame, getCurrentAIGame } from '../../utils/offlineGames';
import { game as gameXhr } from '../../xhr';
import makeData, { defaultData } from './data';
import chessLogic from './chessLogic';
import menu from './menu';
import m from 'mithril';

export default function controller() {
  const source = m.route.param('source');
  const gameId = m.route.param('id');
  const orientation = m.route.param('color');

  this.data = null;

  this.menu = menu.controller(this);

  this.vm = {
    path: null,
    pathStr: '',
    initialPathStr: '',
    step: null,
    cgConfig: null,
    comments: true,
    flip: false,
    variationMenu: null
  };

  this.flip = function() {
    this.vm.flip = !this.vm.flip;
    this.chessground.set({
      orientation: this.vm.flip ? this.data.opponent.color : this.data.player.color
    });
  }.bind(this);

  function uciToLastMove(uci) {
    if (!uci) return null;
    if (uci[1] === '@') return [uci.substr(2, 2), uci.substr(2, 2)];
    return [uci.substr(0, 2), uci.substr(2, 2)];
  }

  const startCeval = function() {
    if (this.ceval.enabled() && this.canUseCeval())
      this.ceval.start(this.vm.path, this.analyse.getSteps(this.vm.path));
  }.bind(this);

  const debouncedStartCeval = debounce(startCeval, 500);
  const debouncedDests = debounce(getDests.bind(this), 100);

  const showGround = function() {
    var s;
    try {
      s = this.analyse.getStep(this.vm.path);
    } catch (e) {
      console.log(e);
    }
    if (!s) {
      this.vm.path = treePath.default(this.analyse.firstPly());
      this.vm.pathStr = treePath.write(this.vm.path);
      s = this.analyse.getStep(this.vm.path);
    }
    const color = s.ply % 2 === 0 ? 'white' : 'black';
    const dests = util.readDests(s.dests);
    const drops = util.readDrops(s.drops);
    const config = {
      fen: s.fen,
      turnColor: color,
      orientation: this.data.orientation,
      movable: {
        color: (dests && Object.keys(dests).length > 0) || drops === null || drops.length ? color : null,
        dests: dests || {}
      },
      check: s.check,
      lastMove: uciToLastMove(s.uci)
    };
    this.vm.step = s;
    this.vm.cgConfig = config;
    if (!this.chessground)
      this.chessground = ground.make(this.data, config, userMove.bind(this), userNewPiece.bind(this));
    this.chessground.set(config);
    if (!dests) debouncedDests();
  }.bind(this);

  const throttledScroll = throttle(() => util.autoScroll(document.getElementById('replay')), 300);

  this.jump = function(path) {
    this.vm.path = path;
    this.vm.pathStr = treePath.write(path);
    this.toggleVariationMenu(null);
    showGround();
    if (!this.vm.step.uci) sound.move(); // initial position
    else if (this.vm.justPlayed !== this.vm.step.uci) {
      if (this.vm.step.san.indexOf('x') !== -1) sound.capture();
      else sound.move();
      this.vm.justPlayed = null;
    }
    this.ceval.stop();
    debouncedStartCeval();
    throttledScroll();
    promotion.cancel(this);
  }.bind(this);

  this.userJump = function(path) {
    this.jump(path);
  }.bind(this);

  this.jumpToMain = function(ply) {
    this.userJump([{
      ply: ply,
      variation: null
    }]);
  }.bind(this);

  this.jumpToIndex = function(index) {
    this.jumpToMain(index + 1 + this.data.game.startedAtTurn);
  }.bind(this);

  this.jumpToNag = function(color, nag) {
    var ply = this.analyse.plyOfNextNag(color, nag, this.vm.step.ply);
    if (ply) this.jumpToMain(ply);
    m.redraw();
  }.bind(this);

  function userNewPiece() {
    this.jump(this.vm.path);
  }

  const preparePremoving = function() {
    this.chessground.set({
      turnColor: this.chessground.data.movable.color,
      movable: {
        color: oppositeColor(this.chessground.data.movable.color)
      }
    });
  }.bind(this);

  const sendMove = function(orig, dest, prom) {
    const move = {
      orig: orig,
      dest: dest,
      variant: this.data.game.variant.key,
      fen: this.vm.step.fen,
      path: this.vm.pathStr,
      ply: this.vm.step.ply
    };
    if (prom) move.promotion = prom;
    this.chessLogic.sendMoveRequest(move);
    preparePremoving();
  }.bind(this);

  function userMove(orig, dest, capture) {
    this.vm.justPlayed = orig + dest;
    sound[capture ? 'capture' : 'move']();
    if (!promotion.start(this, orig, dest, sendMove)) sendMove(orig, dest);
  }

  this.addStep = function(step, path) {
    const newPath = this.analyse.addStep(step, treePath.read(path));
    this.jump(newPath);
    m.redraw();
    this.chessground.playPremove();
  }.bind(this);

  this.addDests = function(dests, path) {
    this.analyse.addDests(dests, treePath.read(path));
    if (path === this.vm.pathStr) {
      showGround();
      m.redraw();
      if (dests === '') this.ceval.stop();
    }
    this.chessground.playPremove();
  }.bind(this);

  this.toggleVariationMenu = function(path) {
    if (!path) this.vm.variationMenu = null;
    else {
      var key = treePath.write(path.slice(0, 1));
      this.vm.variationMenu = this.vm.variationMenu === key ? null : key;
    }
  }.bind(this);

  this.deleteVariation = function(path) {
    var ply = path[0].ply;
    var id = path[0].variation;
    this.analyse.deleteVariation(ply, id);
    if (treePath.contains(path, this.vm.path)) this.jumpToMain(ply - 1);
    this.toggleVariationMenu(null);
  }.bind(this);

  this.promoteVariation = function(path) {
    var ply = path[0].ply;
    var id = path[0].variation;
    this.analyse.promoteVariation(ply, id);
    if (treePath.contains(path, this.vm.path))
      this.jump(this.vm.path.splice(1));
    this.toggleVariationMenu(null);
  }.bind(this);

  this.reset = function() {
    this.chessground.set(this.vm.situation);
    m.redraw();
  }.bind(this);

  this.encodeStepFen = function() {
    return this.vm.step.fen.replace(/\s/g, '_');
  }.bind(this);

  this.currentAnyEval = function() {
    return this.vm.step ? (this.vm.step.oEval || this.vm.step.ceval) : null;
  }.bind(this);

  const allowCeval = function() {
    return (
      util.isSynthetic(this.data) || !gameApi.playable(this.data)
    ) && ['standard', 'fromPosition', 'chess960'].indexOf(this.data.game.variant.key) !== -1;
  }.bind(this);

  function onCevalMsg(res) {
    this.analyse.updateAtPath(res.work.path, function(step) {
      if (step.ceval && step.ceval.depth >= res.ceval.depth) return;
      step.ceval = res.ceval;
      if (treePath.write(res.work.path) === this.vm.pathStr) {
        m.redraw();
      }
    }.bind(this));
  }

  this.canUseCeval = function() {
    return this.vm.step.dests !== '' && (!this.vm.step.oEval || !this.analyse.nextStepEvalBest(this.vm.path));
  }.bind(this);

  this.nextStepBest = function() {
    return this.analyse.nextStepEvalBest(this.vm.path);
  }.bind(this);

  this.toggleCeval = function() {
    this.ceval.toggle();
    debouncedStartCeval();
  }.bind(this);

  this.showEvalGauge = function() {
    return this.hasAnyComputerAnalysis() && settings.analyse.showGauge() && this.vm.step.dests !== '';
  }.bind(this);

  this.hasAnyComputerAnalysis = function() {
    return this.data.analysis || this.ceval.enabled();
  };

  this.toggleGauge = function() {
    settings.analyse.showGauge(!settings.analyse.showGauge());
  };

  this.onunload = function() {
    window.plugins.insomnia.allowSleepAgain();
    if (this.ceval) this.ceval.stop();
    socket.destroy();
  }.bind(this);

  const init = function(data) {
    this.data = data;
    if (!data.game.moveTimes) this.data.game.moveTimes = [];
    console.log(this.data);
    this.ongoing = !util.isSynthetic(this.data) && gameApi.playable(this.data);
    this.chessLogic = new chessLogic(this);
    this.analyse = new analyse(this.data.steps);
    this.ceval = cevalCtrl(allowCeval(), onCevalMsg.bind(this));

    var initialPath = treePath.default(this.analyse.firstPly());
    if (initialPath[0].ply >= this.data.steps.length) {
      initialPath = treePath.default(this.data.steps.length - 1);
    }

    this.vm.path = initialPath;
    this.vm.pathStr = treePath.write(initialPath);

    showGround();
    startCeval();
  }.bind(this);

  if (source === 'online' && gameId) {
    gameXhr(gameId, orientation, false).then(function(cfg) {
      helper.analyticsTrackView('Analysis (game)');
      init(makeData(cfg));
      m.redraw();
    }, err => {
      handleXhrError(err);
      m.route('/');
    });
  } else if (source === 'offline' && gameId === 'otb') {
    helper.analyticsTrackView('Analysis (offline)');
    const otbData = getAnalyseData(getCurrentOTBGame());
    if (!otbData) backHistory();
    else {
      otbData.orientation = orientation;
      init(otbData);
    }
  } else if (source === 'offline' && gameId === 'ai') {
    helper.analyticsTrackView('Analysis (offline)');
    const aiData = getAnalyseData(getCurrentAIGame());
    if (!aiData) backHistory();
    else {
      aiData.orientation = orientation;
      init(aiData);
    }
  }
  else {
    helper.analyticsTrackView('Analysis (empty)');
    init(defaultData);
  }

  window.plugins.insomnia.keepAwake();

}

function getDests() {
  if (!this.vm.step.dests) {
    this.chessLogic.sendDestsRequest({
      variant: this.data.game.variant.key,
      fen: this.vm.step.fen,
      path: this.vm.pathStr
    });
  }
}

<|endoftext|>