<commit_before>var app = Sammy('#content', function () {

    //////////
    // HOME //
    //////////

    this.get('#/', function () {
        setActiveMenuItem('home');
        var container = this.$element();
        container.load('/_home.html', function () { bindHomeListeners(); });
    });

    this.get('#/home', function () {
        this.redirect('#/');
    });

    //////////////////
    // REPOSITORIES //
    //////////////////

    this.get('#/repository/:owner/:repository', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var owner = this.params['owner'];
        var repository = this.params['repository'];
        container.load('/_repository.html', function () {
            loadRepository(owner, repository);
        });
    });

    this.get('#/repositories', function () {
        this.redirect('#/repositories/page/1');
    });

    this.get('#/repositories/page/:page', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_repositories.html', function () {
            var apiUrl = `/api/repos/page/${page}`;
            loadRepositoryList(apiUrl, page, '/#/repositories/page');
        });
    });

    this.get('#/repositories/order/date/asc/page/:page', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_repositories.html', function () {
            var apiUrl = `/api/repos/order/date/asc/page/${page}`;
            $('#repositories_order_dropdown').dropdown('set selected', 'date_asc');
            loadRepositoryList(apiUrl, page, '/#/repositories/order/date/asc/page');
        });
    });

    this.get('#/repositories/order/date/desc/page/:page', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_repositories.html', function () {
            var apiUrl = `/api/repos/order/date/desc/page/${page}`;
            $('#repositories_order_dropdown').dropdown('set selected', 'date_desc');
            loadRepositoryList(apiUrl, page, '/#/repositories/order/date/desc/page');
        });
    });

    this.get('#/repositories/order/name/asc/page/:page', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_repositories.html', function () {
            var apiUrl = `/api/repos/order/name/asc/page/${page}`;
            $('#repositories_order_dropdown').dropdown('set selected', 'name_asc');
            loadRepositoryList(apiUrl, page, '/#/repositories/order/name/asc/page');
        });
    });

    this.get('#/repositories/order/name/desc/page/:page', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_repositories.html', function () {
            var apiUrl = `/api/repos/order/name/desc/page/${page}`;
            $('#repositories_order_dropdown').dropdown('set selected', 'name_desc');
            loadRepositoryList(apiUrl, page, '/#/repositories/order/name/desc/page');
        });
    });

    this.get('#/repositories/order/reviews/asc/page/:page', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_repositories.html', function () {
            var apiUrl = `/api/repos/order/reviews/asc/page/${page}`;
            $('#repositories_order_dropdown').dropdown('set selected', 'reviews_asc');
            loadRepositoryList(apiUrl, page, '/#/repositories/order/reviews/asc/page');
        });
    });

    this.get('#/repositories/order/reviews/desc/page/:page', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_repositories.html', function () {
            var apiUrl = `/api/repos/order/reviews/desc/page/${page}`;
            $('#repositories_order_dropdown').dropdown('set selected', 'reviews_desc');
            loadRepositoryList(apiUrl, page, '/#/repositories/order/reviews/desc/page');
        });
    });

    this.get('#/repositories/order/pullrequests/asc/page/:page', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_repositories.html', function () {
            var apiUrl = `/api/repos/order/pullrequests/asc/page/${page}`;
            $('#repositories_order_dropdown').dropdown('set selected', 'pulls_asc');
            loadRepositoryList(apiUrl, page, '/#/repositories/order/pullrequests/asc/page');
        });
    });

    this.get('#/repositories/order/pullrequests/desc/page/:page', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_repositories.html', function () {
            var apiUrl = `/api/repos/order/pullrequests/desc/page/${page}`;
            $('#repositories_order_dropdown').dropdown('set selected', 'pulls_desc');
            loadRepositoryList(apiUrl, page, '/#/repositories/order/pullrequests/desc/page');
        });
    });

    ///////////////////
    // PULL REQUESTS //
    ///////////////////

    this.get('#/pullrequests', function () {
        this.redirect('#/pullrequests/page/1');
    });

    this.get('#/pullrequests/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/page/${page}`;
            loadPullrequestsList(apiUrl, page, '/#/pullrequests/page');
        });
    });

    this.get('#/pullrequests/order/date/asc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/order/date/asc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'date_asc');
            loadPullrequestsList(apiUrl, page, '/#/pullrequests/order/date/asc/page');
        });
    });

    this.get('#/pullrequests/order/date/desc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/order/date/desc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'date_desc');
            loadPullrequestsList(apiUrl, page, '/#/pullrequests/order/date/desc/page');
        });
    });

    this.get('#/pullrequests/order/name/asc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/order/name/asc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'name_asc');
            loadPullrequestsList(apiUrl, page, '/#/pullrequests/order/name/asc/page');
        });
    });

    this.get('#/pullrequests/order/name/desc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/order/name/desc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'name_desc');
            loadPullrequestsList(apiUrl, page, '/#/pullrequests/order/name/desc/page');
        });
    });

    this.get('#/pullrequests/order/reviews/asc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/order/reviews/asc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'reviews_asc');
            loadPullrequestsList(apiUrl, page, '/#/pullrequests/order/reviews/asc/page');
        });
    });

    this.get('#/pullrequests/order/reviews/desc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/order/reviews/desc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'reviews_desc');
            loadPullrequestsList(apiUrl, page, '/#/pullrequests/order/reviews/desc/page');
        });
    });

    this.get('#/pullrequests/filter/:owner/:repository/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var owner = this.params['owner'];
        var repository = this.params['repository'];
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/filter/${owner}/${repository}/order/date/asc/page/${page}`;
            loadPullrequestsList(apiUrl, page, `/#/pullrequests/filter/${owner}/${repository}/page`, { owner, name: repository });
        });
    });

    this.get('#/pullrequests/filter/:owner/:repository/order/date/asc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var owner = this.params['owner'];
        var repository = this.params['repository'];
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/filter/${owner}/${repository}/order/date/asc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'date_asc');
            loadPullrequestsList(apiUrl, page, `/#/pullrequests/filter/${owner}/${repository}/order/date/asc/page`, { owner, name: repository });
        });
    });

    this.get('#/pullrequests/filter/:owner/:repository/order/date/desc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var owner = this.params['owner'];
        var repository = this.params['repository'];
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/filter/${owner}/${repository}/order/date/desc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'date_desc');
            loadPullrequestsList(apiUrl, page, `/#/pullrequests/filter/${owner}/${repository}/order/date/desc/page`, { owner, name: repository });
        });
    });

    this.get('#/pullrequests/filter/:owner/:repository/order/name/asc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var owner = this.params['owner'];
        var repository = this.params['repository'];
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/filter/${owner}/${repository}/order/name/asc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'name_asc');
            loadPullrequestsList(apiUrl, page, `/#/pullrequests/filter/${owner}/${repository}/order/name/asc/page`, { owner, name: repository });
        });
    });

    this.get('#/pullrequests/filter/:owner/:repository/order/name/desc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var owner = this.params['owner'];
        var repository = this.params['repository'];
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/filter/${owner}/${repository}/order/name/desc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'name_desc');
            loadPullrequestsList(apiUrl, page, `/#/pullrequests/filter/${owner}/${repository}/order/name/desc/page`, { owner, name: repository });
        });
    });

    this.get('#/pullrequests/filter/:owner/:repository/order/reviews/asc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var owner = this.params['owner'];
        var repository = this.params['repository'];
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/filter/${owner}/${repository}/order/reviews/asc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'reviews_asc');
            loadPullrequestsList(apiUrl, page, `/#/pullrequests/filter/${owner}/${repository}/order/reviews/asc/page`, { owner, name: repository });
        });
    });

    this.get('#/pullrequests/filter/:owner/:repository/order/reviews/desc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var owner = this.params['owner'];
        var repository = this.params['repository'];
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/filter/${owner}/${repository}/order/reviews/desc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'reviews_desc');
            loadPullrequestsList(apiUrl, page, `/#/pullrequests/filter/${owner}/${repository}/order/reviews/desc/page`, { owner, name: repository });
        });
    });

    ///////////////
    // NOT FOUND //
    ///////////////

    this.notFound = function () {
        var container = this.$element();
        container.load('/_error.html');
    }

});<commit_msg>client users basic route #62.<commit_after>var app = Sammy('#content', function () {

    //////////
    // HOME //
    //////////

    this.get('#/', function () {
        setActiveMenuItem('home');
        var container = this.$element();
        container.load('/_home.html', function () { bindHomeListeners(); });
    });

    this.get('#/home', function () {
        this.redirect('#/');
    });

    //////////////////
    // REPOSITORIES //
    //////////////////

    this.get('#/repository/:owner/:repository', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var owner = this.params['owner'];
        var repository = this.params['repository'];
        container.load('/_repository.html', function () {
            loadRepository(owner, repository);
        });
    });

    this.get('#/repositories', function () {
        this.redirect('#/repositories/page/1');
    });

    this.get('#/repositories/page/:page', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_repositories.html', function () {
            var apiUrl = `/api/repos/page/${page}`;
            loadRepositoryList(apiUrl, page, '/#/repositories/page');
        });
    });

    this.get('#/repositories/order/date/asc/page/:page', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_repositories.html', function () {
            var apiUrl = `/api/repos/order/date/asc/page/${page}`;
            $('#repositories_order_dropdown').dropdown('set selected', 'date_asc');
            loadRepositoryList(apiUrl, page, '/#/repositories/order/date/asc/page');
        });
    });

    this.get('#/repositories/order/date/desc/page/:page', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_repositories.html', function () {
            var apiUrl = `/api/repos/order/date/desc/page/${page}`;
            $('#repositories_order_dropdown').dropdown('set selected', 'date_desc');
            loadRepositoryList(apiUrl, page, '/#/repositories/order/date/desc/page');
        });
    });

    this.get('#/repositories/order/name/asc/page/:page', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_repositories.html', function () {
            var apiUrl = `/api/repos/order/name/asc/page/${page}`;
            $('#repositories_order_dropdown').dropdown('set selected', 'name_asc');
            loadRepositoryList(apiUrl, page, '/#/repositories/order/name/asc/page');
        });
    });

    this.get('#/repositories/order/name/desc/page/:page', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_repositories.html', function () {
            var apiUrl = `/api/repos/order/name/desc/page/${page}`;
            $('#repositories_order_dropdown').dropdown('set selected', 'name_desc');
            loadRepositoryList(apiUrl, page, '/#/repositories/order/name/desc/page');
        });
    });

    this.get('#/repositories/order/reviews/asc/page/:page', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_repositories.html', function () {
            var apiUrl = `/api/repos/order/reviews/asc/page/${page}`;
            $('#repositories_order_dropdown').dropdown('set selected', 'reviews_asc');
            loadRepositoryList(apiUrl, page, '/#/repositories/order/reviews/asc/page');
        });
    });

    this.get('#/repositories/order/reviews/desc/page/:page', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_repositories.html', function () {
            var apiUrl = `/api/repos/order/reviews/desc/page/${page}`;
            $('#repositories_order_dropdown').dropdown('set selected', 'reviews_desc');
            loadRepositoryList(apiUrl, page, '/#/repositories/order/reviews/desc/page');
        });
    });

    this.get('#/repositories/order/pullrequests/asc/page/:page', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_repositories.html', function () {
            var apiUrl = `/api/repos/order/pullrequests/asc/page/${page}`;
            $('#repositories_order_dropdown').dropdown('set selected', 'pulls_asc');
            loadRepositoryList(apiUrl, page, '/#/repositories/order/pullrequests/asc/page');
        });
    });

    this.get('#/repositories/order/pullrequests/desc/page/:page', function () {
        setActiveMenuItem('repositories');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_repositories.html', function () {
            var apiUrl = `/api/repos/order/pullrequests/desc/page/${page}`;
            $('#repositories_order_dropdown').dropdown('set selected', 'pulls_desc');
            loadRepositoryList(apiUrl, page, '/#/repositories/order/pullrequests/desc/page');
        });
    });

    ///////////////////
    // PULL REQUESTS //
    ///////////////////

    this.get('#/pullrequests', function () {
        this.redirect('#/pullrequests/page/1');
    });

    this.get('#/pullrequests/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/page/${page}`;
            loadPullrequestsList(apiUrl, page, '/#/pullrequests/page');
        });
    });

    this.get('#/pullrequests/order/date/asc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/order/date/asc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'date_asc');
            loadPullrequestsList(apiUrl, page, '/#/pullrequests/order/date/asc/page');
        });
    });

    this.get('#/pullrequests/order/date/desc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/order/date/desc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'date_desc');
            loadPullrequestsList(apiUrl, page, '/#/pullrequests/order/date/desc/page');
        });
    });

    this.get('#/pullrequests/order/name/asc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/order/name/asc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'name_asc');
            loadPullrequestsList(apiUrl, page, '/#/pullrequests/order/name/asc/page');
        });
    });

    this.get('#/pullrequests/order/name/desc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/order/name/desc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'name_desc');
            loadPullrequestsList(apiUrl, page, '/#/pullrequests/order/name/desc/page');
        });
    });

    this.get('#/pullrequests/order/reviews/asc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/order/reviews/asc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'reviews_asc');
            loadPullrequestsList(apiUrl, page, '/#/pullrequests/order/reviews/asc/page');
        });
    });

    this.get('#/pullrequests/order/reviews/desc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/order/reviews/desc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'reviews_desc');
            loadPullrequestsList(apiUrl, page, '/#/pullrequests/order/reviews/desc/page');
        });
    });

    this.get('#/pullrequests/filter/:owner/:repository/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var owner = this.params['owner'];
        var repository = this.params['repository'];
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/filter/${owner}/${repository}/order/date/asc/page/${page}`;
            loadPullrequestsList(apiUrl, page, `/#/pullrequests/filter/${owner}/${repository}/page`, { owner, name: repository });
        });
    });

    this.get('#/pullrequests/filter/:owner/:repository/order/date/asc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var owner = this.params['owner'];
        var repository = this.params['repository'];
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/filter/${owner}/${repository}/order/date/asc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'date_asc');
            loadPullrequestsList(apiUrl, page, `/#/pullrequests/filter/${owner}/${repository}/order/date/asc/page`, { owner, name: repository });
        });
    });

    this.get('#/pullrequests/filter/:owner/:repository/order/date/desc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var owner = this.params['owner'];
        var repository = this.params['repository'];
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/filter/${owner}/${repository}/order/date/desc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'date_desc');
            loadPullrequestsList(apiUrl, page, `/#/pullrequests/filter/${owner}/${repository}/order/date/desc/page`, { owner, name: repository });
        });
    });

    this.get('#/pullrequests/filter/:owner/:repository/order/name/asc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var owner = this.params['owner'];
        var repository = this.params['repository'];
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/filter/${owner}/${repository}/order/name/asc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'name_asc');
            loadPullrequestsList(apiUrl, page, `/#/pullrequests/filter/${owner}/${repository}/order/name/asc/page`, { owner, name: repository });
        });
    });

    this.get('#/pullrequests/filter/:owner/:repository/order/name/desc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var owner = this.params['owner'];
        var repository = this.params['repository'];
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/filter/${owner}/${repository}/order/name/desc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'name_desc');
            loadPullrequestsList(apiUrl, page, `/#/pullrequests/filter/${owner}/${repository}/order/name/desc/page`, { owner, name: repository });
        });
    });

    this.get('#/pullrequests/filter/:owner/:repository/order/reviews/asc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var owner = this.params['owner'];
        var repository = this.params['repository'];
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/filter/${owner}/${repository}/order/reviews/asc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'reviews_asc');
            loadPullrequestsList(apiUrl, page, `/#/pullrequests/filter/${owner}/${repository}/order/reviews/asc/page`, { owner, name: repository });
        });
    });

    this.get('#/pullrequests/filter/:owner/:repository/order/reviews/desc/page/:page', function () {
        setActiveMenuItem('pullrequests');
        var container = this.$element();
        var owner = this.params['owner'];
        var repository = this.params['repository'];
        var page = this.params['page'];
        container.load('/_pullrequests.html', function () {
            var apiUrl = `/api/pulls/filter/${owner}/${repository}/order/reviews/desc/page/${page}`;
            $('#pullrequests_order_dropdown').dropdown('set selected', 'reviews_desc');
            loadPullrequestsList(apiUrl, page, `/#/pullrequests/filter/${owner}/${repository}/order/reviews/desc/page`, { owner, name: repository });
        });
    });

    ///////////
    // USERS //
    ///////////

    this.get('#/users', function () {
        this.redirect('#/users/page/1');
    });

    this.get('#/users/page/:page', function () {
        setActiveMenuItem('users');
        var container = this.$element();
        var page = this.params['page'];
        container.load('/_users.html', function () {
            var apiUrl = `/api/pulls/page/${page}`;
            loadUsersList(apiUrl, page, '/#/users/page');
        });
    });

    ///////////////
    // NOT FOUND //
    ///////////////

    this.notFound = function () {
        var container = this.$element();
        container.load('/_error.html');
    }

});<|endoftext|>


<commit_before>var $ = require('jquery-browserify');
var chosen = require('chosen-jquery-browserify');
var _ = require('underscore');
_.merge = require('deepmerge');
var jsyaml = require('js-yaml');
var Backbone = require('backbone');
var templates = require('../../dist/templates');
var util = require('.././util');

module.exports = Backbone.View.extend({
  template: templates.metadata,

  events: {
    'change input': 'updateModel',
    'click .create-select': 'createSelect',
    'click .finish': 'exit'
  },

  initialize: function(options) {
    _.bindAll(this);

    this.model = options.model;
    this.titleAsHeading = options.titleAsHeading;
    this.view = options.view;
  },

  render: function() {
    this.$el.empty().append(_.template(this.template));

    var form = this.$el.find('.form');

    var metadata = this.model.get('metadata');
    var lang = metadata && metadata.lang ? metadata.lang : 'en';

    // This renders any fields defined in the metadata entry
    // of a given prose configuration file.
    _.each(this.model.get('defaults'), (function(data, key) {
      var renderTitle = true;

      if (data && data.name === 'title' && this.titleAsHeading) {
        renderTitle = false;
      };

      if (renderTitle) {
        if (data && data.field) {
          switch (data.field.element) {
            case 'button':
              var button = {
                name: data.name,
                label: data.field.label,
                on: data.field.on,
                off: data.field.off
              };

              form.append(_.template(templates.meta.button, button, {
                variable: 'meta'
              }));
              break;
            case 'checkbox':
              var checkbox = {
                name: data.name,
                label: data.field.label,
                value: data.name,
                checked: data.field.value
              };

              form.append(_.template(templates.meta.checkbox, checkbox, {
                variable: 'meta'
              }));
              break;
            case 'text':
              var text = {
                name: data.name,
                label: data.field.label,
                value: data.field.value,
                type: 'text'
              };

              form.append(_.template(templates.meta.text, text, {
                variable: 'meta'
              }));
              break;
            case 'textarea':
              var id = util.stringToUrl(data.name);
              var textarea = {
                name: data.name,
                id: id,
                value: data.field.value,
                label: data.field.label,
                type: 'textarea'
              };

              form.append(_.template(templates.meta.textarea, textarea, {
                variable: 'meta'
              }));

              var textElement = document.getElementById(id);

              this[id] = CodeMirror(function(el) {
                textElement.parentNode.replaceChild(el, textElement);
                el.id = id;
                el.className += ' inner ';
                el.setAttribute('data-name', data.name);
              }, {
                mode: id,
                value: textElement.value,
                lineWrapping: true,
                theme: 'prose-bright'
              });

              break;
            case 'number':
              var number = {
                name: data.name,
                label: data.field.label,
                value: data.field.value,
                type: 'number'
              };

              form.append(_.template(templates.meta.text, number, {
                variable: 'meta'
              }));
              break;
            case 'select':
              var select = {
                name: data.name,
                label: data.field.label,
                placeholder: data.field.placeholder,
                options: data.field.options,
                lang: lang
              };

              form.append(_.template(templates.meta.select, select, {
                variable: 'meta'
              }));
              break;
            case 'multiselect':
              var multiselect = {
                name: data.name,
                label: data.field.label,
                alterable: data.field.alterable,
                placeholder: data.field.placeholder,
                options: data.field.options,
                lang: lang
              };

              form.append(_.template(templates.meta.multiselect, multiselect, {
                variable: 'meta'
              }));

              break;
            case 'hidden':
              var tmpl = {};
              tmpl[data.name] = data.field.value;
              this.model.set('metadata', _.merge(tmpl, this.model.get('metadata') || {}));
              this.model.set('hidden', _.merge(tmpl, this.model.get('hidden') || {}));
              break;
          }
        } else {
          var txt = {
            name: key,
            label: key,
            value: data,
            type: 'text'
          };

          form.append(_.template(templates.meta.text, txt, {
            variable: 'meta'
          }));
        }
      }
    }).bind(this));

    this.$el.find('.chzn-select').chosen().change(this.updateModel);

    this.renderRaw();

    return this;
  },

  updateModel: function(e) {
    var target = e.currentTarget;
    var key = target.name;
    var value = target.value;

    var delta = {};
    delta[key] = value;

    var metadata = this.model.get('metadata');
    this.model.set('metadata', _.extend(metadata, delta));

    this.view.makeDirty();
  },

  rawKeyMap: function() {
    return {
      'Ctrl-S': this.view.updateFile
    };
  },

  renderRaw: function() {
    var selector = this.model.get('lang') === 'yaml' ? 'code' : 'raw';

    if (selector === 'raw') {
      this.$el.find('.form').append(_.template(templates.meta.raw));
    }

    this.raw = CodeMirror(this.$el.find('#' + selector)[0], {
      mode: 'yaml',
      value: '',
      lineWrapping: true,
      extraKeys: this.rawKeyMap(),
      theme: 'prose-bright'
    });

    this.listenTo(this.raw, 'blur', (function(cm) {
      var value = cm.getValue();
      var raw;

      try {
        raw = jsyaml.load(value);
      } catch(err) {
        console.log(err);
      }

      if (raw) {
        var metadata = this.model.get('metadata');
        this.model.set('metadata', _.extend(metadata, raw));

        this.view.makeDirty();
      }
    }).bind(this));

    this.setValue(this.model.get('metadata'));
  },

  getValue: function() {
    var view = this;
    var metadata = this.model.get('metadata');

    if (this.view.toolbar &&
       this.view.toolbar.publishState() ||
       (metadata && metadata.published)) {
      metadata.published = true;
    } else {
      metadata.published = false;
    }

    // Get the title value from heading if we need to.
    if (this.titleAsHeading) {
      metadata.title = (this.view.header) ?
        this.view.header.inputGet() :
        this.model.get('metadata').title[0];
    }

    _.each(this.$el.find('[name]'), function(item) {
      var $item = $(item);
      var value = $item.val();

      switch (item.type) {
        case 'select-multiple':
        case 'select-one':
        case 'textarea':
        case 'text':
          if (value) {
            value = $item.data('type') === 'number' ? Number(value) : value;
            if (metadata.hasOwnProperty(item.name) && metadata[item.name] !== value) {
              metadata[item.name] = _.union(metadata[item.name], value);
            } else {
              metadata[item.name] = value;
            }
          }
          break;
        case 'checkbox':
          if (item.checked) {

            if (metadata.hasOwnProperty(item.name) && metadata[item.name] !== value) {
              metadata[item.name] = _.union(metadata[item.name], item.value);
            } else if (item.value === item.name) {
              metadata[item.name] = item.checked;
            } else {
              metadata[item.name] = item.value;
            }

          } else if (!metadata.hasOwnProperty(item.name) && item.value === item.name) {
            metadata[item.name] = item.checked;
          } else {
            metadata[item.name] = item.checked;
          }
          break;
        case 'button':
          if (value === 'true') {
            metadata[item.name] = true;
          } else if (value === 'false') {
            metadata[item.name] = false;
          }
          break;
      }
    });

    // Load any data coming from a yaml-block of content.
    this.$el.find('.yaml-block').each(function() {
      var editor = $(this).find('.CodeMirror').attr('id');
      var name = $('#' + editor).data('name');

      if (view[editor]) {
        metadata[name] = jsyaml.load(view[editor].getValue());
      }
    });

    // Load any data coming from not defined raw yaml front matter.
    if (this.raw) {
      try {
        metadata = _.merge(metadata, jsyaml.load(this.raw.getValue()) || {});
      } catch (err) {
        throw err;
      }
    }

    return _.merge(this.model.get('hidden') || {}, metadata);
  },

  setValue: function(data) {
    var form = this.$el.find('.form');

    var missing = {};
    var raw;

    _.each(data, (function(value, key) {
      var matched = false;
      var input = this.$el.find('[name="' + key + '"]');
      var length = input.length;
      var options;

      if (length) {

        // iterate over matching fields
        for (var i = 0; i < length; i++) {

          // if value is an array
          if (_.isArray(value)) {

            // iterate over values in array
            for (var j = 0; j < value.length; j++) {
              switch (input[i].type) {
                case 'select-multiple':
                case 'select-one':
                  options = $(input[i]).find('option[value="' + value[j] + '"]');
                  if (options.length) {
                    for (var k = 0; k < options.length; k++) {
                      options[k].selected = 'selected';
                    }

                    matched = true;
                  }
                  break;
                case 'text':
                case 'textarea':
                  input[i].value = value;
                  matched = true;
                  break;
                case 'checkbox':
                  if (input[i].value === value) {
                    input[i].checked = 'checked';
                    matched = true;
                  }
                  break;
              }
            }

          } else {

            switch (input[i].type) {
              case 'select-multiple':
              case 'select-one':
                options = $(input[i]).find('option[value="' + value + '"]');
                if (options.length) {
                  for (var m = 0; m < options.length; m++) {
                    options[m].selected = 'selected';
                  }

                  matched = true;
                }
                break;
              case 'text':
              case 'textarea':
                input[i].value = value;
                matched = true;
                break;
              case 'checkbox':
                input[i].checked = value ? 'checked' : false;
                matched = true;
                break;
              case 'button':
                input[i].value = value ? true : false;
                input[i].innerHTML = value ? input[i].getAttribute('data-on') : input[i].getAttribute('data-off');
                matched = true;
                break;
            }

          }
        }

        if (!matched && value !== null) {
          if (missing.hasOwnProperty(key) && missing[key] !== value) {
            missing[key] = _.union(missing[key], value);
          } else {
            missing[key] = value;
          }
        }

      } else {
        // Don't render the 'published' field or hidden metadata
        // TODO: render metadata values that share a key with a hidden value
        var defaults = _.find(this.model.get('defaults'), function(data) { return data && (data.name === key); });
        var diff = defaults && _.isArray(value) ? _.difference(value, defaults.field.value) : value;

        if (key !== 'published' && key !== 'title' && !defaults) {
          raw = {};
          raw[key] = value;

          if (this.raw) {
            this.raw.setValue(this.raw.getValue() + jsyaml.dump(raw));
          }
        }
      }
    }).bind(this));

    _.each(missing, (function(value, key) {
      if (value === null) return;

      switch (typeof value) {
        case 'boolean':
          var bool = {
            name: key,
            label: value,
            value: value,
            checked: value ? 'checked' : false
          };

          form.append(_.template(templates.meta.checkbox, bool, {
            variable: 'meta'
          }));
          break;
        case 'string':
          var string = {
            name: key,
            label: value,
            value: value,
            type: 'text'
          };

          form.append(_.template(templates.meta.text, string, {
            variable: 'meta'
          }));
          break;
        case 'object':
          var obj = {
            name: key,
            label: key,
            placeholder: key,
            options: value,
            lang: data.lang || 'en'
          };

          form.append(_.template(templates.meta.multiselect, obj, {
            variable: 'meta'
          }));
          break;
        default:
          console.log('ERROR could not create metadata field for ' + typeof value, key + ': ' + value);
          break;
      }

      this.$el.find('.chzn-select').chosen().change(this.updateModel);
    }).bind(this));

    this.$el.find('.chzn-select').trigger('liszt:updated');

    // Update model with defaults
    // TODO: should this makeDirty if any differences?
    this.model.set('metadata', this.getValue());
  },

  getRaw: function() {
    return jsyaml.dump(this.getValue()).trim();
  },

  setRaw: function(data) {
    try {
      this.raw.setValue(jsyaml.dump(data));
      this.refresh;
    } catch (err) {
      throw err;
    }
  },

  refresh: function() {
    var view = this;
    this.$el.find('.yaml-block').each(function() {
      var editor = $(this).find('.CodeMirror').attr('id');
      if (view[editor]) view[editor].refresh();
    });

    // Refresh CodeMirror
    if (this.raw) this.raw.refresh();
  },

  createSelect: function(e) {
    var $parent = $(e.target).parent();
    var $input = $parent.find('input');
    var selectTarget = $(e.target).data('select');
    var $select = this.$el.find('#' + selectTarget);
    var value = $input.val();

    if (value.length > 0) {
      var option = '<option value="' + value + '" selected="selected">' + value + '</option>';

      // Append this new option to the select list.
      $select.append(option);

      // Clear the now added value.
      $input.attr('value', '');

      // Update the list
      $select.trigger('liszt:updated');
    }

    return false;
  },

  exit: function() {
    this.view.nav.active(this.view.mode);

    if (this.view.mode === 'blob') {
      this.view.blob();
    } else {
      this.view.edit();
    }

    return false;
  }
});
<commit_msg>handle yaml files with metadata (site translations), closes #529<commit_after>var $ = require('jquery-browserify');
var chosen = require('chosen-jquery-browserify');
var _ = require('underscore');
_.merge = require('deepmerge');
var jsyaml = require('js-yaml');
var Backbone = require('backbone');
var templates = require('../../dist/templates');
var util = require('.././util');

module.exports = Backbone.View.extend({
  template: templates.metadata,

  events: {
    'change input': 'updateModel',
    'click .create-select': 'createSelect',
    'click .finish': 'exit'
  },

  initialize: function(options) {
    _.bindAll(this);

    this.model = options.model;
    this.titleAsHeading = options.titleAsHeading;
    this.view = options.view;
  },

  render: function() {
    this.$el.empty().append(_.template(this.template));

    var form = this.$el.find('.form');

    var metadata = this.model.get('metadata');
    var lang = metadata && metadata.lang ? metadata.lang : 'en';

    // This renders any fields defined in the metadata entry
    // of a given prose configuration file.
    _.each(this.model.get('defaults'), (function(data, key) {
      var renderTitle = true;

      if (data && data.name === 'title' && this.titleAsHeading) {
        renderTitle = false;
      };

      if (renderTitle) {
        if (data && data.field) {
          switch (data.field.element) {
            case 'button':
              var button = {
                name: data.name,
                label: data.field.label,
                on: data.field.on,
                off: data.field.off
              };

              form.append(_.template(templates.meta.button, button, {
                variable: 'meta'
              }));
              break;
            case 'checkbox':
              var checkbox = {
                name: data.name,
                label: data.field.label,
                value: data.name,
                checked: data.field.value
              };

              form.append(_.template(templates.meta.checkbox, checkbox, {
                variable: 'meta'
              }));
              break;
            case 'text':
              var text = {
                name: data.name,
                label: data.field.label,
                value: data.field.value,
                type: 'text'
              };

              form.append(_.template(templates.meta.text, text, {
                variable: 'meta'
              }));
              break;
            case 'textarea':
              var id = util.stringToUrl(data.name);
              var textarea = {
                name: data.name,
                id: id,
                value: data.field.value,
                label: data.field.label,
                type: 'textarea'
              };

              form.append(_.template(templates.meta.textarea, textarea, {
                variable: 'meta'
              }));

              var textElement = document.getElementById(id);

              this[id] = CodeMirror(function(el) {
                textElement.parentNode.replaceChild(el, textElement);
                el.id = id;
                el.className += ' inner ';
                el.setAttribute('data-name', data.name);
              }, {
                mode: id,
                value: textElement.value,
                lineWrapping: true,
                theme: 'prose-bright'
              });

              break;
            case 'number':
              var number = {
                name: data.name,
                label: data.field.label,
                value: data.field.value,
                type: 'number'
              };

              form.append(_.template(templates.meta.text, number, {
                variable: 'meta'
              }));
              break;
            case 'select':
              var select = {
                name: data.name,
                label: data.field.label,
                placeholder: data.field.placeholder,
                options: data.field.options,
                lang: lang
              };

              form.append(_.template(templates.meta.select, select, {
                variable: 'meta'
              }));
              break;
            case 'multiselect':
              var multiselect = {
                name: data.name,
                label: data.field.label,
                alterable: data.field.alterable,
                placeholder: data.field.placeholder,
                options: data.field.options,
                lang: lang
              };

              form.append(_.template(templates.meta.multiselect, multiselect, {
                variable: 'meta'
              }));

              break;
            case 'hidden':
              var tmpl = {};
              tmpl[data.name] = data.field.value;
              this.model.set('metadata', _.merge(tmpl, this.model.get('metadata') || {}));
              this.model.set('hidden', _.merge(tmpl, this.model.get('hidden') || {}));
              break;
          }
        } else {
          var txt = {
            name: key,
            label: key,
            value: data,
            type: 'text'
          };

          form.append(_.template(templates.meta.text, txt, {
            variable: 'meta'
          }));
        }
      }
    }).bind(this));

    this.$el.find('.chzn-select').chosen().change(this.updateModel);

    this.renderRaw();

    return this;
  },

  updateModel: function(e) {
    var target = e.currentTarget;
    var key = target.name;
    var value = target.value;

    var delta = {};
    delta[key] = value;

    var metadata = this.model.get('metadata');
    this.model.set('metadata', _.extend(metadata, delta));

    this.view.makeDirty();
  },

  rawKeyMap: function() {
    return {
      'Ctrl-S': this.view.updateFile
    };
  },

  renderRaw: function() {
    var yaml = this.model.get('lang') === 'yaml';
    var $el = yaml ? this.view.$el.find('#code') : this.$el.find('#raw');

    if (yaml) {
      $el.empty();
    } else {
      this.$el.find('.form').append(_.template(templates.meta.raw));
    }

    this.raw = CodeMirror($el[0], {
      mode: 'yaml',
      value: '',
      lineWrapping: true,
      lineNumbers: yaml,
      extraKeys: this.rawKeyMap(),
      theme: 'prose-bright'
    });

    this.listenTo(this.raw, 'blur', (function(cm) {
      var value = cm.getValue();
      var raw;

      try {
        raw = jsyaml.load(value);
      } catch(err) {
        console.log(err);
      }

      if (raw) {
        var metadata = this.model.get('metadata');
        this.model.set('metadata', _.extend(metadata, raw));

        this.view.makeDirty();
      }
    }).bind(this));

    this.setValue(this.model.get('metadata'));
  },

  getValue: function() {
    var view = this;
    var metadata = this.model.get('metadata');

    if (this.view.toolbar &&
       this.view.toolbar.publishState() ||
       (metadata && metadata.published)) {
      metadata.published = true;
    } else {
      metadata.published = false;
    }

    // Get the title value from heading if we need to.
    if (this.titleAsHeading) {
      metadata.title = (this.view.header) ?
        this.view.header.inputGet() :
        this.model.get('metadata').title[0];
    }

    _.each(this.$el.find('[name]'), function(item) {
      var $item = $(item);
      var value = $item.val();

      switch (item.type) {
        case 'select-multiple':
        case 'select-one':
        case 'textarea':
        case 'text':
          if (value) {
            value = $item.data('type') === 'number' ? Number(value) : value;
            if (metadata.hasOwnProperty(item.name) && metadata[item.name] !== value) {
              metadata[item.name] = _.union(metadata[item.name], value);
            } else {
              metadata[item.name] = value;
            }
          }
          break;
        case 'checkbox':
          if (item.checked) {

            if (metadata.hasOwnProperty(item.name) && metadata[item.name] !== value) {
              metadata[item.name] = _.union(metadata[item.name], item.value);
            } else if (item.value === item.name) {
              metadata[item.name] = item.checked;
            } else {
              metadata[item.name] = item.value;
            }

          } else if (!metadata.hasOwnProperty(item.name) && item.value === item.name) {
            metadata[item.name] = item.checked;
          } else {
            metadata[item.name] = item.checked;
          }
          break;
        case 'button':
          if (value === 'true') {
            metadata[item.name] = true;
          } else if (value === 'false') {
            metadata[item.name] = false;
          }
          break;
      }
    });

    // Load any data coming from a yaml-block of content.
    this.$el.find('.yaml-block').each(function() {
      var editor = $(this).find('.CodeMirror').attr('id');
      var name = $('#' + editor).data('name');

      if (view[editor]) {
        metadata[name] = jsyaml.load(view[editor].getValue());
      }
    });

    // Load any data coming from not defined raw yaml front matter.
    if (this.raw) {
      try {
        metadata = _.merge(metadata, jsyaml.load(this.raw.getValue()) || {});
      } catch (err) {
        throw err;
      }
    }

    return _.merge(this.model.get('hidden') || {}, metadata);
  },

  setValue: function(data) {
    var form = this.$el.find('.form');

    var missing = {};
    var raw;

    _.each(data, (function(value, key) {
      var matched = false;
      var input = this.$el.find('[name="' + key + '"]');
      var length = input.length;
      var options;

      if (length) {

        // iterate over matching fields
        for (var i = 0; i < length; i++) {

          // if value is an array
          if (_.isArray(value)) {

            // iterate over values in array
            for (var j = 0; j < value.length; j++) {
              switch (input[i].type) {
                case 'select-multiple':
                case 'select-one':
                  options = $(input[i]).find('option[value="' + value[j] + '"]');
                  if (options.length) {
                    for (var k = 0; k < options.length; k++) {
                      options[k].selected = 'selected';
                    }

                    matched = true;
                  }
                  break;
                case 'text':
                case 'textarea':
                  input[i].value = value;
                  matched = true;
                  break;
                case 'checkbox':
                  if (input[i].value === value) {
                    input[i].checked = 'checked';
                    matched = true;
                  }
                  break;
              }
            }

          } else {

            switch (input[i].type) {
              case 'select-multiple':
              case 'select-one':
                options = $(input[i]).find('option[value="' + value + '"]');
                if (options.length) {
                  for (var m = 0; m < options.length; m++) {
                    options[m].selected = 'selected';
                  }

                  matched = true;
                }
                break;
              case 'text':
              case 'textarea':
                input[i].value = value;
                matched = true;
                break;
              case 'checkbox':
                input[i].checked = value ? 'checked' : false;
                matched = true;
                break;
              case 'button':
                input[i].value = value ? true : false;
                input[i].innerHTML = value ? input[i].getAttribute('data-on') : input[i].getAttribute('data-off');
                matched = true;
                break;
            }

          }
        }

        if (!matched && value !== null) {
          if (missing.hasOwnProperty(key) && missing[key] !== value) {
            missing[key] = _.union(missing[key], value);
          } else {
            missing[key] = value;
          }
        }

      } else {
        // Don't render the 'published' field or hidden metadata
        // TODO: render metadata values that share a key with a hidden value
        var defaults = _.find(this.model.get('defaults'), function(data) { return data && (data.name === key); });
        var diff = defaults && _.isArray(value) ? _.difference(value, defaults.field.value) : value;

        if (key !== 'published' && key !== 'title' && !defaults) {
          raw = {};
          raw[key] = value;

          if (this.raw) {
            this.raw.setValue(this.raw.getValue() + jsyaml.dump(raw));
          }
        }
      }
    }).bind(this));

    _.each(missing, (function(value, key) {
      if (value === null) return;

      switch (typeof value) {
        case 'boolean':
          var bool = {
            name: key,
            label: value,
            value: value,
            checked: value ? 'checked' : false
          };

          form.append(_.template(templates.meta.checkbox, bool, {
            variable: 'meta'
          }));
          break;
        case 'string':
          var string = {
            name: key,
            label: value,
            value: value,
            type: 'text'
          };

          form.append(_.template(templates.meta.text, string, {
            variable: 'meta'
          }));
          break;
        case 'object':
          var obj = {
            name: key,
            label: key,
            placeholder: key,
            options: value,
            lang: data.lang || 'en'
          };

          form.append(_.template(templates.meta.multiselect, obj, {
            variable: 'meta'
          }));
          break;
        default:
          console.log('ERROR could not create metadata field for ' + typeof value, key + ': ' + value);
          break;
      }

      this.$el.find('.chzn-select').chosen().change(this.updateModel);
    }).bind(this));

    this.$el.find('.chzn-select').trigger('liszt:updated');

    // Update model with defaults
    // TODO: should this makeDirty if any differences?
    this.model.set('metadata', this.getValue());
  },

  getRaw: function() {
    return jsyaml.dump(this.getValue()).trim();
  },

  setRaw: function(data) {
    try {
      this.raw.setValue(jsyaml.dump(data));
      this.refresh;
    } catch (err) {
      throw err;
    }
  },

  refresh: function() {
    var view = this;
    this.$el.find('.yaml-block').each(function() {
      var editor = $(this).find('.CodeMirror').attr('id');
      if (view[editor]) view[editor].refresh();
    });

    // Refresh CodeMirror
    if (this.raw) this.raw.refresh();
  },

  createSelect: function(e) {
    var $parent = $(e.target).parent();
    var $input = $parent.find('input');
    var selectTarget = $(e.target).data('select');
    var $select = this.$el.find('#' + selectTarget);
    var value = $input.val();

    if (value.length > 0) {
      var option = '<option value="' + value + '" selected="selected">' + value + '</option>';

      // Append this new option to the select list.
      $select.append(option);

      // Clear the now added value.
      $input.attr('value', '');

      // Update the list
      $select.trigger('liszt:updated');
    }

    return false;
  },

  exit: function() {
    this.view.nav.active(this.view.mode);

    if (this.view.mode === 'blob') {
      this.view.blob();
    } else {
      this.view.edit();
    }

    return false;
  }
});
<|endoftext|>


<commit_before>jQuery(document).ready(function($) {

  vectorcam = new VectorCam();

});

// simple class declaration & inheritance
Class = function(methods) {
  var klass = function() {
    this.initialize.apply(this, arguments);
  };

  for (var property in methods) {
    klass.prototype[property] = methods[property];
  }

  if (!klass.prototype.initialize) klass.prototype.initialize = function(){};

  return klass;
};

VectorCam = Class({

  options: {
    numberofcolors: 16,
    colorquantcycles: 5,
  },

  initialize: function() {

    if (typeof window.FileReader == "undefined") {
      $('.instructions').html('You need a newer browser (Firefox 38+, Safari 7.1+, Chrome 31+) to use this service.');
      $('.upload').attr('disabled', true);
    }

    this.tracer = new ImageTracer();

    this.canvas = $('canvas.canvas')[0]
    this.context = this.canvas.getContext('2d');
    this.canvas.width = $(window).width();
    this.canvas.height = $(window).height();

    var _vectorcam = this;

    $("#file-select input").change(function(e) {

      $('.spinner').show();
      $('.instructions').hide();

      var reader = new FileReader(),
          f = e.target.files[0];

      // Closure to capture the file information.
      reader.onload = (function(file) {
        return function(e) {

          _vectorcam.img = new Image();

          _vectorcam.img.onload = function(e) {

            var _img = e.path[0];

            _vectorcam.imgWidth  = _img.width;
            _vectorcam.imgHeight = _img.height;
            _vectorcam.imgRatio  = _img.height/_img.width;

            if (_img.width > 1000 || _img.height > 1000) {
              _vectorcam.imgWidth = 1000;
              _vectorcam.imgHeight = _vectorcam.imgWidth * _vectorcam.imgRatio;
            }

            _vectorcam.canvas.width = _vectorcam.imgWidth;
            _vectorcam.canvas.height = _vectorcam.imgHeight;

            _vectorcam.context.drawImage(_vectorcam.img, 0, 0, _vectorcam.canvas.width, _vectorcam.canvas.width * _vectorcam.imgRatio);

            _vectorcam.generate();

          };
          _vectorcam.img.src = e.target.result;

        };
      })(f);

      // Read in the image file as a data URL.
      reader.readAsDataURL(f);

    });

    this.generate = function() {

      $('#svg').remove();

      var img = _vectorcam.tracer.getImgdata( _vectorcam.canvas );

      var svgstr = _vectorcam.tracer.imagedataToSVG( img, _vectorcam.options );

      _vectorcam.tracer.appendSVGString( svgstr, 'svg' );

      $('.save').attr('href',"data:image/svg+xml;utf8,"+$('#svg').html());
      $('.save').show();
      $('.btn-options').show();
      $('.canvas').hide();
      $('.upload').hide();
      $('#svg').show();
      $('.spinner').hide();

    }

    $('.btn-options').click(function(e) {
      $('.options').toggle();
    });

    $('.reload').click(function(e) {
      $('.spinner').show();
      _vectorcam.options.numberofcolors = parseInt($('.colors').val());
      _vectorcam.options.pathomit = parseInt($('.pathomit').val());
      _vectorcam.generate();
    });

    $('.save').click(function(e) {
      var name = prompt('Name your image', 'vectorcam.svg');
      $('.save').attr('download', name);
    });

  },

  clear: function() {
    $('.canvas').show();
    $('.upload').show();
    $('.btn-options').hide();
    $('#svg').hide();
  }

});

<commit_msg>ios safari fix<commit_after>jQuery(document).ready(function($) {

  vectorcam = new VectorCam();

});

// simple class declaration & inheritance
Class = function(methods) {
  var klass = function() {
    this.initialize.apply(this, arguments);
  };

  for (var property in methods) {
    klass.prototype[property] = methods[property];
  }

  if (!klass.prototype.initialize) klass.prototype.initialize = function(){};

  return klass;
};

VectorCam = Class({

  options: {
    numberofcolors: 16,
    colorquantcycles: 5,
  },

  initialize: function() {

    if (typeof window.FileReader == "undefined") {
      $('.instructions').html('You need a newer browser (Firefox 38+, Safari 7.1+, Chrome 31+) to use this service.');
      $('.upload').attr('disabled', true);
    }

    this.tracer = new ImageTracer();

    this.canvas = $('canvas.canvas')[0]
    this.context = this.canvas.getContext('2d');
    this.canvas.width = $(window).width();
    this.canvas.height = $(window).height();

    var _vectorcam = this;

    $("#file-select input").change(function(e) {

      $('.spinner').show();
      $('.instructions').hide();

      var reader = new FileReader(),
          f = e.target.files[0];

      // Closure to capture the file information.
      reader.onload = (function(file) {

        return function(e) {

          _vectorcam.img = new Image();

          _vectorcam.img.onload = function(e) {

            var _img = this; //e.path[0];

            _vectorcam.imgWidth  = _img.width;
            _vectorcam.imgHeight = _img.height;
            _vectorcam.imgRatio  = _img.height/_img.width;

            if (_img.width > 1000 || _img.height > 1000) {
              _vectorcam.imgWidth = 1000;
              _vectorcam.imgHeight = _vectorcam.imgWidth * _vectorcam.imgRatio;
            }

            _vectorcam.canvas.width = _vectorcam.imgWidth;
            _vectorcam.canvas.height = _vectorcam.imgHeight;

            _vectorcam.context.drawImage(_vectorcam.img, 0, 0, _vectorcam.canvas.width, _vectorcam.canvas.width * _vectorcam.imgRatio);

            _vectorcam.generate();

          };
          _vectorcam.img.src = e.target.result;

        };

      })(f);

      // Read in the image file as a data URL.
      reader.readAsDataURL(f);

    });

    this.generate = function() {

      $('#svg').remove();

      var img = _vectorcam.tracer.getImgdata( _vectorcam.canvas );

      var svgstr = _vectorcam.tracer.imagedataToSVG( img, _vectorcam.options );

      _vectorcam.tracer.appendSVGString( svgstr, 'svg' );

      $('.save').attr('href',"data:image/svg+xml;utf8,"+$('#svg').html());
      $('.save').show();
      $('.btn-options').show();
      $('.canvas').hide();
      $('.upload').hide();
      $('#svg').show();
      $('.spinner').hide();

    }

    $('.btn-options').click(function(e) {
      $('.options').toggle();
    });

    $('.reload').click(function(e) {
      $('.spinner').show();
      _vectorcam.options.numberofcolors = parseInt($('.colors').val());
      _vectorcam.options.pathomit = parseInt($('.pathomit').val());
      _vectorcam.generate();
    });

    $('.save').click(function(e) {
      var name = prompt('Name your image', 'vectorcam.svg');
      $('.save').attr('download', name);
    });

  },

  clear: function() {
    $('.canvas').show();
    $('.upload').show();
    $('.btn-options').hide();
    $('#svg').hide();
  }

});

<|endoftext|>


<commit_before>import gql from 'graphql-tag';
import { ApolloClient, createNetworkInterface } from 'apollo-client';
import * as http from 'http';
// import ApolloWrapperService from 'apollo/apollo-wrapper-service'

export class CarsController {

    constructor($scope, ApolloWrapperService) {
        this.scope= $scope
        this.ApolloWrapperService= ApolloWrapperService;
        this.car = {};
        this.cars = [];
        this.fetchCarsList();
        this.startSubscriptions();
    }

    fetchCarsList() {
        this.ApolloWrapperService.getAllCars().then(result => {
            this.addAllQueryResults(result);
            this.scope.$apply();
        });
    };

    startSubscriptions() {
        this.subscribeToUpdates();
        this.subscribeToAdds();
        this.subscribeToDeletes();
    }

    subscribeToUpdates() {
        this.ApolloWrapperService.subscribeToUpdates()
            .subscribe({
                next: data => {
                    console.log('Got data- ', data);
                    console.log('Pushing to car list...');
                    this.updateCarsByUpdate(data.carUpdated);
                    // this.cars.push(data);
                    // this.scope.$apply();
                    return data;
                },
                error: (err) => {
                    console.log('Error- ', err);
                }
            })
    }
    subscribeToAdds() {
        this.ApolloWrapperService.subscribeToAdds()
            .subscribe({
                next: data => {
                    console.log('Got data- ', data);
                    console.log('Addddd to car list...');
                    this.cars.push(data.carAdded);
                    this.scope.$apply();
                    return data;
                },
                error: (err) => {
                    console.log('Error- ', err);
                }
            })
    }
    subscribeToDeletes() {
        this.ApolloWrapperService.subscribeToDeletes()
            .subscribe({
                next: data => {
                    console.log('Got data- ', data);
                    console.log('Removing from cars list...');
                    console.log(data.carDeleted);
                    this.updateCarsByDelete(data.carDeleted)
                    // this.cars.push(data.carAdded);
                    return data;
                },
                error: (err) => {
                    console.log('Error- ', err);
                }
            })
    }

    updateCarsByUpdate(updatedCar) {
        this.cars.forEach(car => {
            if(car._id === updatedCar._id) {
                car.name = updatedCar.name;
                this.scope.$apply();
            }
        })
    }
    updateCarsByDelete(deletedCar) {
        console.log(this.cars)
        console.log(deletedCar)
        let indexToRemove = 0;
        let currentIndex = 0;
        this.cars.forEach(car => {
            if(car._id === deletedCar._id) {
                console.log('Going to delete car - ', car);
                indexToRemove = currentIndex;
            }
            currentIndex++;
        })
        this.cars.splice(indexToRemove, 1);
        this.scope.$apply();
    }

    addAllQueryResults(result) {
        this.cars = [];
        let immutableCars = result.data.car;
        this.cars = JSON.parse( JSON.stringify( immutableCars ));
    }

    showAddForm (){
        this.addFormShow = true;
    }
    hideAddForm (){
        this.addFormShow = false;
        this.editFormShow = false;
    }

    showEditForm (car){
        this.editFormShow = true;
        this.editedCarName = car.name;
        this.editedCarId = car.id;
    }

    addNewCar (car) {
        this.ApolloWrapperService.addNewCar(this.car).then(result => {
            this.fetchCarsList();
            this.car.name = ''
            this.addFormShow = false;
        });
    };

    editCar (car) {
        car.id = this.editedCarId;
        console.log(car);
        this.ApolloWrapperService.editCar(this.editedCarName, this.car.name).then(result => {
            this.fetchCarsList();
            this.car.name = ''
            this.addFormShow = false;
        });
        this.editFormShow = false;
    };

    removeLogic(name) {
        http.delete("http://localhost:8080/cars/removeCar/" + name).success(function (res) {
            console.log(res)
            this.fetchCarsList();
        });
    }

    removeCar (name) {
        this.ApolloWrapperService.deleteCar(name)
            .then(result => {
                console.log("After delete - ", name)
            })
        this.car.name = '';
    }
};<commit_msg>Using ES6 findIndex for deleting sub<commit_after>import gql from 'graphql-tag';
import { ApolloClient, createNetworkInterface } from 'apollo-client';
import * as http from 'http';
// import ApolloWrapperService from 'apollo/apollo-wrapper-service'

export class CarsController {

    constructor($scope, ApolloWrapperService) {
        this.scope= $scope
        this.ApolloWrapperService= ApolloWrapperService;
        this.car = {};
        this.cars = [];
        this.fetchCarsList();
        this.startSubscriptions();
    }

    fetchCarsList() {
        this.ApolloWrapperService.getAllCars().then(result => {
            this.addAllQueryResults(result);
            this.scope.$apply();
        });
    };

    startSubscriptions() {
        this.subscribeToUpdates();
        this.subscribeToAdds();
        this.subscribeToDeletes();
    }

    subscribeToUpdates() {
        this.ApolloWrapperService.subscribeToUpdates()
            .subscribe({
                next: data => {
                    console.log('Got data- ', data);
                    console.log('Pushing to car list...');
                    this.updateCarsByUpdate(data.carUpdated);
                    return data;
                },
                error: (err) => {
                    console.log('Error- ', err);
                }
            })
    }
    subscribeToAdds() {
        this.ApolloWrapperService.subscribeToAdds()
            .subscribe({
                next: data => {
                    console.log('Got data- ', data);
                    console.log('Addddd to car list...');
                    this.cars.push(data.carAdded);
                    this.scope.$apply();
                    return data;
                },
                error: (err) => {
                    console.log('Error- ', err);
                }
            })
    }
    subscribeToDeletes() {
        this.ApolloWrapperService.subscribeToDeletes()
            .subscribe({
                next: data => {
                    console.log('Got data- ', data);
                    console.log('Removing from cars list...');
                    console.log(data.carDeleted);
                    this.updateCarsByDelete(data.carDeleted)
                    return data;
                },
                error: (err) => {
                    console.log('Error- ', err);
                }
            })
    }

    updateCarsByUpdate(updatedCar) {
        this.cars.forEach(car => {
            if(car._id === updatedCar._id) {
                car.name = updatedCar.name;
                this.scope.$apply();
            }
        })
    }
    updateCarsByDelete(deletedCar) {
        let indexToRemove = 0;
        indexToRemove = this.cars.findIndex((car) => car._id === deletedCar._id);
        this.cars.splice(indexToRemove, 1);
        this.scope.$apply();
    }

    addAllQueryResults(result) {
        this.cars = [];
        let immutableCars = result.data.car;
        this.cars = JSON.parse( JSON.stringify( immutableCars ));
    }

    showAddForm (){
        this.addFormShow = true;
    }
    hideAddForm (){
        this.addFormShow = false;
        this.editFormShow = false;
    }

    showEditForm (car){
        this.editFormShow = true;
        this.editedCarName = car.name;
        this.editedCarId = car.id;
    }

    addNewCar (car) {
        this.ApolloWrapperService.addNewCar(this.car).then(result => {
            this.fetchCarsList();
            this.car.name = ''
            this.addFormShow = false;
        });
    };

    editCar (car) {
        car.id = this.editedCarId;
        console.log(car);
        this.ApolloWrapperService.editCar(this.editedCarName, this.car.name).then(result => {
            this.fetchCarsList();
            this.car.name = ''
            this.addFormShow = false;
        });
        this.editFormShow = false;
    };

    removeLogic(name) {
        http.delete("http://localhost:8080/cars/removeCar/" + name).success(function (res) {
            console.log(res)
            this.fetchCarsList();
        });
    }

    removeCar (name) {
        this.ApolloWrapperService.deleteCar(name)
            .then(result => {
                console.log("After delete - ", name)
            })
        this.car.name = '';
    }
};<|endoftext|>


<commit_before>import {Dialog} from "./dialog"

/** Creates a dropdown box.
 * @param btn The button to open and close the dropdown box.
 * @param box The node containing the contents of the dropdown box.
 * @param preopen An optional function to be called before opening the dropdown box. Used to position dropdown box.
 */

export const addDropdownBox = function(btn, box, preopen=false) {
    btn.addEventListener('click', event => {
        event.preventDefault()
        event.stopPropagation()
        if (btn.classList.contains('disabled')) {
            return
        }
        if (!box.clientWidth) {
            if (preopen) {
                preopen()
            }
            openDropdownBox(box)
        }
    })
}

/** Opens a dropdown box.
 * @param box The node containing the contents of the dropdown box.
 */

export const openDropdownBox = function(box) {
    // Show this box
    box.style.display = 'block'

    const closeDropdownBox = function(event) {
        event.preventDefault()
        box.style.display = ''
        document.removeEventListener('click', closeDropdownBox, false)
    }
    document.body.addEventListener('click', closeDropdownBox, false)
}

/** Checks or unchecks a checkable label. This is used for example for bibliography categories when editing bibliography items.
 * @param label The node who's parent has to be checked or unchecked.
 */
export const setCheckableLabel = function(labelEl) {
    if (labelEl.classList.contains('checked')) {
        labelEl.classList.remove('checked')
    } else {
        labelEl.classList.add('checked')
    }
}

/** Cover the page signaling to the user to wait.
 */
export const activateWait = function() {
    const waitEl = document.getElementById('wait')
    if (waitEl) {
        waitEl.classList.add('active')
    }
}

/** Remove the wait cover.
 */
export const deactivateWait = function() {
    const waitEl = document.getElementById('wait')
    if (waitEl) {
        waitEl.classList.remove('active')
    }
}

/** Show a message to the user.
 * @param alertType The type of message that is shown (error, warning, info or success).
 * @param alertMsg The message text.
 */
export const addAlert = function(alertType, alertMsg) {
    const iconNames = {
        'error': 'exclamation-circle',
        'warning': 'exclamation-circle',
        'info': 'info-circle',
        'success': 'check-circle'
    }
    if (!document.getElementById('#alerts-outer-wrapper'))
        document.body.insertAdjacentHTML('beforeend', '

')
    const alertsWrapper = document.getElementById('alerts-wrapper')
    alertsWrapper.insertAdjacentHTML('beforeend', `<li class="alerts-${alertType} fa fa-${iconNames[alertType]}">${alertMsg}</li>`)
    const alertBox = alertsWrapper.lastElementChild
    setTimeout(()=>{
        alertBox.classList.add('visible')
        setTimeout(()=>{
            alertBox.classList.remove('visible')
            setTimeout(()=>alertsWrapper.removeChild(alertBox), 2000)
        }, 4000)
    }, 1)
}

// Used for system mesages
export const showSystemMessage = function(message) {
    const dialog = new Dialog({
        title: gettext('System message'),
        body: `<p>${escapeText(message)}</p>`,
        buttons: [{type: 'close'}]
    })
    dialog.open()
}

/** Turn milliseconds since epoch (UTC) into a local date string.
 * @param {number} milliseconds Number of milliseconds since epoch (1/1/1970 midnight, UTC).
 * @param {boolean} type 'full' for full date (default), 'sortable-date' for sortable date, 'minutes' for minute accuracy
 */
export const localizeDate = function(milliseconds, type='full') {
    milliseconds = parseInt(milliseconds)
    if (milliseconds > 0) {
        const theDate = new Date(milliseconds)
        let yyyy, mm, dd, returnValue
        switch (type) {
            case 'sortable-date':
                yyyy = theDate.getFullYear()
                mm = theDate.getMonth() + 1
                dd = theDate.getDate()
                returnValue = `${yyyy}-${String(mm).padStart(2, '0')}-${String(dd).padStart(2, '0')}`
                break
            case 'minutes':
                returnValue = theDate.toLocaleString([], {year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute:'2-digit'})
                break
            default:
                returnValue = theDate.toLocaleString()
        }
        return returnValue
    }
    else {
        return ''
    }
}

/**
 * Turn string literals into single line, removing spaces at start of line
 */

export const noSpaceTmp = function(_strings) {
     const values = Array.from(arguments)
     const tmpStrings = Array.from(values.shift())

     let combined = ""
     while (tmpStrings.length > 0 || values.length > 0) {
         if (tmpStrings.length > 0) {
             combined += tmpStrings.shift()
         }
         if (values.length > 0) {
             combined += values.shift()
         }
     }

     let out = ""
     combined.split('\n').forEach(line => {
         out += line.replace(/^\s*/g, '')
     })
     return out
 }

export const escapeText = function(text) {
     return text
         .replace(/&/g, '&')
         .replace(/</g, '<')
         .replace(/>/g, '>')
 }
/**
 * Return a cancel promise if you need to cancel a promise chain. Import as
 * ES6 promises are not (yet) cancelable.
 */

export const cancelPromise = () => new Promise(()=>{})

// Check if selector matches one of the ancestors of the event target.
// Used in switch statements of document event listeners.
export const findTarget = function(event, selector, el={}) {
    el.target = event.target.closest(selector)
    if (el.target) {
        event.stopPropagation()
        return true
    }
    return false
}

// Promise when page has been loaded.
export const whenReady = function() {
    if (document.readyState === "complete") {
        return Promise.resolve()
    } else {
        return new Promise(resolve => {
            document.addEventListener("readystatechange", _event => {
                if (document.readyState === "complete") {
                    resolve()
                }
            })
        })
    }
}

export const setDocTitle = function(title) {
    const titleText = `${title} - Fidus Writer`
    if (document.title !== titleText) {
        document.title = titleText
    }

}
<commit_msg>cache localizeDate output<commit_after>import {Dialog} from "./dialog"

/** Creates a dropdown box.
 * @param btn The button to open and close the dropdown box.
 * @param box The node containing the contents of the dropdown box.
 * @param preopen An optional function to be called before opening the dropdown box. Used to position dropdown box.
 */

export const addDropdownBox = function(btn, box, preopen=false) {
    btn.addEventListener('click', event => {
        event.preventDefault()
        event.stopPropagation()
        if (btn.classList.contains('disabled')) {
            return
        }
        if (!box.clientWidth) {
            if (preopen) {
                preopen()
            }
            openDropdownBox(box)
        }
    })
}

/** Opens a dropdown box.
 * @param box The node containing the contents of the dropdown box.
 */

export const openDropdownBox = function(box) {
    // Show this box
    box.style.display = 'block'

    const closeDropdownBox = function(event) {
        event.preventDefault()
        box.style.display = ''
        document.removeEventListener('click', closeDropdownBox, false)
    }
    document.body.addEventListener('click', closeDropdownBox, false)
}

/** Checks or unchecks a checkable label. This is used for example for bibliography categories when editing bibliography items.
 * @param label The node who's parent has to be checked or unchecked.
 */
export const setCheckableLabel = function(labelEl) {
    if (labelEl.classList.contains('checked')) {
        labelEl.classList.remove('checked')
    } else {
        labelEl.classList.add('checked')
    }
}

/** Cover the page signaling to the user to wait.
 */
export const activateWait = function() {
    const waitEl = document.getElementById('wait')
    if (waitEl) {
        waitEl.classList.add('active')
    }
}

/** Remove the wait cover.
 */
export const deactivateWait = function() {
    const waitEl = document.getElementById('wait')
    if (waitEl) {
        waitEl.classList.remove('active')
    }
}

/** Show a message to the user.
 * @param alertType The type of message that is shown (error, warning, info or success).
 * @param alertMsg The message text.
 */
export const addAlert = function(alertType, alertMsg) {
    const iconNames = {
        'error': 'exclamation-circle',
        'warning': 'exclamation-circle',
        'info': 'info-circle',
        'success': 'check-circle'
    }
    if (!document.getElementById('#alerts-outer-wrapper'))
        document.body.insertAdjacentHTML('beforeend', '

')
    const alertsWrapper = document.getElementById('alerts-wrapper')
    alertsWrapper.insertAdjacentHTML('beforeend', `<li class="alerts-${alertType} fa fa-${iconNames[alertType]}">${alertMsg}</li>`)
    const alertBox = alertsWrapper.lastElementChild
    setTimeout(()=>{
        alertBox.classList.add('visible')
        setTimeout(()=>{
            alertBox.classList.remove('visible')
            setTimeout(()=>alertsWrapper.removeChild(alertBox), 2000)
        }, 4000)
    }, 1)
}

// Used for system mesages
export const showSystemMessage = function(message) {
    const dialog = new Dialog({
        title: gettext('System message'),
        body: `<p>${escapeText(message)}</p>`,
        buttons: [{type: 'close'}]
    })
    dialog.open()
}

/** Turn milliseconds since epoch (UTC) into a local date string.
 * @param {number} milliseconds Number of milliseconds since epoch (1/1/1970 midnight, UTC).
 * @param {boolean} type 'full' for full date (default), 'sortable-date' for sortable date, 'minutes' for minute accuracy
 */
const CACHED_DATES = {
    'sortable-date': {},
    'minutes': {},
    'full': {}
}
export const localizeDate = function(milliseconds, type='full') {
    if (milliseconds === 0) {
        return ''
    } else if (CACHED_DATES[type][milliseconds]) {
        return CACHED_DATES[type][milliseconds]
    }
    const theDate = new Date(milliseconds)
    let returnValue
    switch (type) {
        case 'sortable-date': {
            const yyyy = theDate.getFullYear()
            const mm = theDate.getMonth() + 1
            const dd = theDate.getDate()
            returnValue = `${yyyy}-${String(mm).padStart(2, '0')}-${String(dd).padStart(2, '0')}`
            break
        }
        case 'minutes':
            returnValue = theDate.toLocaleString([], {year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit'})
            break
        default:
            returnValue = theDate.toLocaleString()
    }
    if (Object.keys(CACHED_DATES[type]).length > 5000) {
        CACHED_DATES[type] = {}
    }
    CACHED_DATES[type][milliseconds] = returnValue
    return returnValue
}

/**
 * Turn string literals into single line, removing spaces at start of line
 */

export const noSpaceTmp = function(_strings) {
     const values = Array.from(arguments)
     const tmpStrings = Array.from(values.shift())

     let combined = ""
     while (tmpStrings.length > 0 || values.length > 0) {
         if (tmpStrings.length > 0) {
             combined += tmpStrings.shift()
         }
         if (values.length > 0) {
             combined += values.shift()
         }
     }

     let out = ""
     combined.split('\n').forEach(line => {
         out += line.replace(/^\s*/g, '')
     })
     return out
 }

export const escapeText = function(text) {
     return text
         .replace(/&/g, '&')
         .replace(/</g, '<')
         .replace(/>/g, '>')
 }
/**
 * Return a cancel promise if you need to cancel a promise chain. Import as
 * ES6 promises are not (yet) cancelable.
 */

export const cancelPromise = () => new Promise(()=>{})

// Check if selector matches one of the ancestors of the event target.
// Used in switch statements of document event listeners.
export const findTarget = function(event, selector, el={}) {
    el.target = event.target.closest(selector)
    if (el.target) {
        event.stopPropagation()
        return true
    }
    return false
}

// Promise when page has been loaded.
export const whenReady = function() {
    if (document.readyState === "complete") {
        return Promise.resolve()
    } else {
        return new Promise(resolve => {
            document.addEventListener("readystatechange", _event => {
                if (document.readyState === "complete") {
                    resolve()
                }
            })
        })
    }
}

export const setDocTitle = function(title) {
    const titleText = `${title} - Fidus Writer`
    if (document.title !== titleText) {
        document.title = titleText
    }

}
<|endoftext|>


<commit_before>module.exports = config;

/**
 * Remote config request (from cloud)
 */
function config(dat, cb) {

	if(!dat.CONFIG || !dat.id) { return; }

	dat.CONFIG.map(processRequest.bind(this));

	var cloudBuffer = [ ];

	/**
	 * Called for each config element in the request
	 */
	function processRequest(req) {

		var
			ninja = this
			, response = function(err, res, mod) {

				var
					id = dat.id
					, module = mod
				;
				// error in module response
				if(err) {

					// what to do here?
					return ninja.log.error(

						"cloudConfig: %s (%s:%s)"
						, err
						, module
						, id
					);
				}
				ninja.log.debug(

					"cloudConfig: Sending response (%s:%s)"
					, module
					, id
				);
				ninja.cloud.config({

					"CONFIG" : [{

						type : "MODULE"
						, module : module
						, data : res
					}]
					, id : id
				});
			};
		;

		if(req.type !== "MODULE") { // We only implement MODULE

			return;
		}

		if(!req.module) { // probe the bloke~!

			blockProbe(mod, res);
		}

		// If a module has a config method, always prefer that
		if(this.modules[req.module].config) {

			/**
			 * Called when a module response comes back
			 */

			this.log.info(

				"cloudConfig: Attempting request (%s:%s)"
				, req.module
				, dat.id
			);
			this.modules[req.module].config(req.data || null, function(err, dat) {

				response(err, dat, req.module);
			});
			return;
		}
		// module has no .config method, send an error or somethign?
	};

	function blockProbe(mod, res) {

		if(!ninja.modules) { return; }

		Object.keys(ninja.modules).map(sendRequest);
		function sendRequest(mod) {

			if((ninja.modules[mod] && ninja.modules[mod].config)) {

				ninja.modules[mod].config(req.data || null, function(err, res) {

					response(err, res, mod);
				});
			}
		};
		return this.log.debug("cloudConfig: Cloud requesting block config");
	}
};
<commit_msg>Added batch response from module config callbacks.<commit_after>module.exports = config;

/**
 * Remote config request (from cloud)
 */
function config(dat, cb) {

	if(!dat.CONFIG || !dat.id) { return; }

	var
		cloudBuffer = {

			configResponse : {

				CONFIG : [ ]
				, id : dat.id
			}
			, requested : 0
			, responded : 0
			, timeout : undefined
		}
		, ninja = this

	;

	dat.CONFIG.map(processRequest.bind(this));

	/**
	 * Called for each config element in the request
	 */
	function processRequest(req) {

		if(req.type !== "MODULE") { // We only implement MODULE

			return;
		}

		if(!req.module) { // probe the bloke~!

			// we may want to add filtering of "system" modules from the probes?
			return blockProbe(req, dat.id);
		}

		moduleProbe(req, dat.id);
	};

	function blockProbe(req, id) {

		if(!ninja.modules) { return; }
		var mods = Object.keys(ninja.modules);
		cloudBuffer.timeout = setTimeout(sendResponse, 3000);
		cloudBuffer.requested = mods.length;

		ninja.log.debug("cloudConfig: Initiating requests for %s modules", mods.length);
		mods.map(sendRequest);
		function sendRequest(mod) {

			if((ninja.modules[mod] && ninja.modules[mod].config)) {

				ninja.log.debug("cloudConfig: Requesting config from %s", mod);
				ninja.modules[mod].config(req.data || null, function(err, res) {

					ninja.log.debug("cloudConfig: Received response from %s", mod);
					configResponse(err, res, mod);
				});
			}
		};

		return ninja.log.debug("cloudConfig: Cloud requesting block config");
	};

	function moduleProbe(req, id) {

		ninja.log.info(

			"cloudConfig: Attempting request (%s:%s)"
			, req.module
			, id
		);
		cloudBuffer.requested = 1;
		ninja.modules[req.module].config(req.data || { }, function(err, dat) {

			configResponse(err, dat, req.module);
		});
	};

	function configResponse(err, res, mod) {

		if(!cloudBuffer.configResponse.CONFIG) {

			cloudBuffer.configResponse.CONFIG = [ ];
		}
		// error in module configResponse
		if(err) {

			// what to do here?
			return ninja.log.error(

				"cloudConfig: %s (%s:%s)"
				, err
				, mod
				, dat.id
			);
		}
		ninja.log.debug("cloudConfig: Pushing module response (%s) onto stack", mod);
		cloudBuffer.configResponse.CONFIG.push({

			type : "MODULE"
			, module : mod
			, data : res
		})
		if(++cloudBuffer.responded >= cloudBuffer.requested) {

			sendResponse();
		}
	};

	function sendResponse() {

		ninja.log.debug("cloudConfig: sending config collection");
		ninja.cloud.config(cloudBuffer.configResponse);
	}
};
<|endoftext|>


<commit_before><commit_msg>Fixed bug in new version of fs-extra<commit_after><|endoftext|>


<commit_before>// @flow
import React from "react";

const AddButton = () =>
  <button className="center-block button-primary">Add task</button>;

export default AddButton;
<commit_msg>Button onClick<commit_after>// @flow
import React from "react";

const AddButton = ({ add }: { add: () => void }) =>
  <button className="center-block button-primary" onClick={add}>
    Add task
  </button>;

export default AddButton;
<|endoftext|>