<commit_before>/*
    Copyright 2014 UW Information Technology, University of Washington

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

    Changes:

    =================================================================

*/

window.spacescout_reviews = {
    review_char_limit: 300,
    pagination: 5
};

function setupRatingsAndReviews() {
    var enable_submit = function () {
            $('button#space-review-submit').removeAttr('disabled');
        },
        disable_submit = function () {
            $('button#space-review-submit').attr('disabled', 'disabled');
        },
        show_guidelines = function () {
            var ul = $('.space-review-compose ul');

            ul.show();
            ul.prev().find('i').switchClass('fs-angle-double-down', 'fs-angle-double-up');
        },
        hide_guidelines = function () {
            var ul = $('.space-review-compose ul');

            ul.hide();
            ul.prev().find('i').switchClass('fs-angle-double-up', 'fs-angle-double-down');
        };

    $('.space-ratings-and-reviews').html(Handlebars.compile($('#space_reviews').html())());

    // wire up events for markup in reviews.html
    $('.space-ratings-and-reviews h4 .write-a-review').on('click', function (e) {
        $('.space-reviews button.write-a-review').hide();
        $('.space-review-compose').show(400);
        $('.space-reviews-none').hide(400);
        $('#space-review-remaining').html(window.spacescout_reviews.review_char_limit);
    });

    disable_submit();

    $('.space-review-compose textarea').keyup(function (e) {
        var l = $(this).val().length,
            remaining = window.spacescout_reviews.review_char_limit - l,
            span = $('#space-review-remaining');

        if (remaining > 0) {
            span.html(remaining);
            span.removeClass('required');
        } else {
            span.html(0);
            span.addClass('required');
        }

        if (l > 0 && $('.space-review-compose .space-review-stars i.fa-star').length) {
            enable_submit();
        } else {
            disable_submit();
        }
    });

    $('button#space-review-cancel').click(function (e) {
        var node = $('.space-review-compose');

        node.hide(400);
        $('.space-reviews-none').show();
        $('.space-reviews button.write-a-review').show();

        disable_submit();
        hide_guidelines();
        $('textarea', node).val('');
        $('.space-review-stars span + span', node).html('');
        $('#space-review-remaining').html(window.spacescout_reviews.review_char_limit);
        $('.space-review-rating div + div span', node).removeClass('required');
        $('.space-review-rating i', node).switchClass('fa-star', 'fa-star-o');
    });

    $('button#space-review-submit').click(function (e) {
        var id = $(e.target).closest('div[id^=detail_container_]').attr('id').match(/_(\d+)$/)[1];

        submitRatingAndReview(id);
    });

    $('.space-review-submitted a').click(function (e) {
        $('.space-review-submitted').hide(400);
        $('.space-reviews-none').show();
        $('.space-reviews button.write-a-review').show();
    });

    $(document).on('click', '.space-review-stars i', function (e) {
        var target = $(e.target),
            stars = target.prevAll('i'),
            rating = stars.length + 1,
            ratings = ['', gettext('terrible'), gettext('poor'),
                       gettext('average'), gettext('good'), gettext('excellent')];

        stars.switchClass('fa-star-o', 'fa-star');
        target.switchClass('fa-star-o', 'fa-star');
        target.nextAll('i').switchClass('fa-star', 'fa-star-o');
        $('.space-review-stars span:last-child').html(ratings[rating]);
        if ($('.space-review-compose textarea').val().length) {
            enable_submit();
        }
    });

    $('.space-review-compose a').on('click', function () {
        if ($(this).next().is(':visible')) {
            hide_guidelines();
        } else {
            show_guidelines();
        }
    });

    if (window.spacescout_authenticated_user.length > 0) {
        var review = $.cookie('space_review'),
            json_review;

        if (review != null) {
            json_review = JSON.parse(review);
            postRatingAndReview(json_review.id, json_review.review);
            $.removeCookie('space_review');
        }
    }
}

function loadRatingsAndReviews(id) {
    $.ajax({
        url: 'web_api/v1/space/' + id + '/reviews',
        success: function (data) {
            var template = Handlebars.compile($('#space_reviews_review').html()),
                content = $('.space-reviews-content'),
                rating_sum = 0,
                node;

            content.html('');

            if (data && data.length > 0) {
                $.each(data, function(i) {
                    var review = this,
                        rating = this.rating,
                        date = new Date(this.date_submitted);

                    node = $(template({
                        reviewer: this.reviewer,
                        review: (this.review && this.review.length) ? this.review : 'No review provided',
                        date: date ? monthname_from_month(date.getMonth()) + ' ' + date.getDate() + ', ' + date.getFullYear() : ''
                    }));

                    rating_sum += parseInt(this.rating);

                    $('.space-review-header i', node).each(function(i) {
                        if (i < rating) {
                            $(this).switchClass('fa-star-o', 'fa-star');
                        }
                    });

                    if (i >= window.spacescout_reviews.pagination) {
                        node.hide();
                    }

                    content.append(node);
                });

                if (data.length > window.spacescout_reviews.pagination) {
                    node = Handlebars.compile($('#more_space_reviews').html())();
                    content.append(node);

                    $('.more-space-reviews a').on('click', function (e) {
                        $('.space-reviews-review:hidden').each(function (i) {
                            if (i < window.spacescout_reviews.pagination) {
                                $(this).slideDown(400);
                            }
                        });

                        if ($('.space-reviews-review:hidden').length <= 0) {
                            $(this).parent().hide();
                        }
                    });
                }

                if (rating_sum) {
                    var avg = Math.ceil((rating_sum) / data.length);

                    $('.space-actions i').each(function(i) {
                        if (i < avg) {
                            $(this).switchClass('fa-star-o', 'fa-star');
                        }
                    });

                    $('.space-actions span#review_count').html(data.length);
                }

                $('.space-ratings-and-reviews h4 .write-a-review').show();
            } else {
                $('.space-ratings-and-reviews h4 .write-a-review').hide();
                template = Handlebars.compile($('#no_space_reviews').html());
                content.html(template());
                $('.write-a-review', content).on('click', function (e) {
                    $('.space-reviews button.write-a-review').hide();
                    $('.space-review-compose').show(400);
                    $('.space-reviews-none').hide(400);
                    $('#space-review-remaining').html(window.spacescout_reviews.review_char_limit);
                });
            }

        },
        error: function (xhr, textStatus, errorThrown) {
            console.log('Unable to load reviews: ' + xhr.responseText);
        }
    });
}

function submitRatingAndReview(id) {
    var node = $('.space-review-compose'),
        review = {
            rating: $('.space-review-rating i.fa-star', node).length,
            review: $('textarea', node).val().trim()
        };

    // validate
    if (review.rating < 1 || review.rating > 5 || review.review.length <= 0) {
        return;
    }

    // defer until authenticated
    if (window.spacescout_authenticated_user.length == 0) {
        $.cookie('space_review', JSON.stringify({ id: id, review: review }));
        window.location.href = '/login?next=' + window.location.pathname;
    }

    postRatingAndReview(id, review);
}

function postRatingAndReview(id, review) {
    $.ajax({
        url: 'web_api/v1/space/' + id + '/reviews',
        dataType: 'json',
        contentType: "application/json",
        data: JSON.stringify(review),
        type: "POST",
        success: function (data) {
            $('.space-reviews button.write-a-review').hide();
            $('.space-review-compose').hide(400);
            $('.space-review-submitted').show();
        },
        error: function (xhr, textStatus, errorThrown) {
            console.log('Unable to post reviews: ' + xhr.responseText);
        }
    });
}

<commit_msg>moves rating/review editor into full view when opened<commit_after>/*
    Copyright 2014 UW Information Technology, University of Washington

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

    Changes:

    =================================================================

*/

window.spacescout_reviews = {
    review_char_limit: 300,
    pagination: 5
};

function setupRatingsAndReviews() {
    var enable_submit = function () {
            $('button#space-review-submit').removeAttr('disabled');
        },
        disable_submit = function () {
            $('button#space-review-submit').attr('disabled', 'disabled');
        },
        show_guidelines = function () {
            var ul = $('.space-review-compose ul');

            ul.show();
            ul.prev().find('i').switchClass('fs-angle-double-down', 'fs-angle-double-up');
        },
        hide_guidelines = function () {
            var ul = $('.space-review-compose ul');

            ul.hide();
            ul.prev().find('i').switchClass('fs-angle-double-up', 'fs-angle-double-down');
        };

    $('.space-ratings-and-reviews').html(Handlebars.compile($('#space_reviews').html())());

    // wire up events for markup in reviews.html
    $('.space-ratings-and-reviews h4 .write-a-review').on('click', function (e) {
        showRatingEditor();
    });

    disable_submit();

    $('.space-review-compose textarea').keyup(function (e) {
        var l = $(this).val().length,
            remaining = window.spacescout_reviews.review_char_limit - l,
            span = $('#space-review-remaining');

        if (remaining > 0) {
            span.html(remaining);
            span.removeClass('required');
        } else {
            span.html(0);
            span.addClass('required');
        }

        if (l > 0 && $('.space-review-compose .space-review-stars i.fa-star').length) {
            enable_submit();
        } else {
            disable_submit();
        }
    });

    $('button#space-review-cancel').click(function (e) {
        var node = $('.space-review-compose');

        node.hide(400);
        $('.space-reviews-none').show();
        $('.space-reviews button.write-a-review').show();

        disable_submit();
        hide_guidelines();
        $('textarea', node).val('');
        $('.space-review-stars span + span', node).html('');
        $('#space-review-remaining').html(window.spacescout_reviews.review_char_limit);
        $('.space-review-rating div + div span', node).removeClass('required');
        $('.space-review-rating i', node).switchClass('fa-star', 'fa-star-o');
    });

    $('button#space-review-submit').click(function (e) {
        var id = $(e.target).closest('div[id^=detail_container_]').attr('id').match(/_(\d+)$/)[1];

        submitRatingAndReview(id);
    });

    $('.space-review-submitted a').click(function (e) {
        $('.space-review-submitted').hide(400);
        $('.space-reviews-none').show();
        $('.space-reviews button.write-a-review').show();
    });

    $(document).on('click', '.space-review-stars i', function (e) {
        var target = $(e.target),
            stars = target.prevAll('i'),
            rating = stars.length + 1,
            ratings = ['', gettext('terrible'), gettext('poor'),
                       gettext('average'), gettext('good'), gettext('excellent')];

        stars.switchClass('fa-star-o', 'fa-star');
        target.switchClass('fa-star-o', 'fa-star');
        target.nextAll('i').switchClass('fa-star', 'fa-star-o');
        $('.space-review-stars span:last-child').html(ratings[rating]);
        if ($('.space-review-compose textarea').val().length) {
            enable_submit();
        }
    });

    $('.space-review-compose a').on('click', function () {
        if ($(this).next().is(':visible')) {
            hide_guidelines();
        } else {
            show_guidelines();
        }
    });

    if (window.spacescout_authenticated_user.length > 0) {
        var review = $.cookie('space_review'),
            json_review;

        if (review != null) {
            json_review = JSON.parse(review);
            postRatingAndReview(json_review.id, json_review.review);
            $.removeCookie('space_review');
        }
    }
}

function loadRatingsAndReviews(id) {
    $.ajax({
        url: 'web_api/v1/space/' + id + '/reviews',
        success: function (data) {
            var template = Handlebars.compile($('#space_reviews_review').html()),
                content = $('.space-reviews-content'),
                rating_sum = 0,
                node;

            content.html('');

            if (data && data.length > 0) {
                $.each(data, function(i) {
                    var review = this,
                        rating = this.rating,
                        date = new Date(this.date_submitted);

                    node = $(template({
                        reviewer: this.reviewer,
                        review: (this.review && this.review.length) ? this.review : 'No review provided',
                        date: date ? monthname_from_month(date.getMonth()) + ' ' + date.getDate() + ', ' + date.getFullYear() : ''
                    }));

                    rating_sum += parseInt(this.rating);

                    $('.space-review-header i', node).each(function(i) {
                        if (i < rating) {
                            $(this).switchClass('fa-star-o', 'fa-star');
                        }
                    });

                    if (i >= window.spacescout_reviews.pagination) {
                        node.hide();
                    }

                    content.append(node);
                });

                if (data.length > window.spacescout_reviews.pagination) {
                    node = Handlebars.compile($('#more_space_reviews').html())();
                    content.append(node);

                    $('.more-space-reviews a').on('click', function (e) {
                        $('.space-reviews-review:hidden').each(function (i) {
                            if (i < window.spacescout_reviews.pagination) {
                                $(this).slideDown(400);
                            }
                        });

                        if ($('.space-reviews-review:hidden').length <= 0) {
                            $(this).parent().hide();
                        }
                    });
                }

                if (rating_sum) {
                    var avg = Math.ceil((rating_sum) / data.length);

                    $('.space-actions i').each(function(i) {
                        if (i < avg) {
                            $(this).switchClass('fa-star-o', 'fa-star');
                        }
                    });

                    $('.space-actions span#review_count').html(data.length);
                }

                $('.space-ratings-and-reviews h4 .write-a-review').show();
            } else {
                $('.space-ratings-and-reviews h4 .write-a-review').hide();
                template = Handlebars.compile($('#no_space_reviews').html());
                content.html(template());
                $('.write-a-review', content).on('click', function (e) {
                    showRatingEditor();
                });
            }

        },
        error: function (xhr, textStatus, errorThrown) {
            console.log('Unable to load reviews: ' + xhr.responseText);
        }
    });
}

function submitRatingAndReview(id) {
    var node = $('.space-review-compose'),
        review = {
            rating: $('.space-review-rating i.fa-star', node).length,
            review: $('textarea', node).val().trim()
        };

    // validate
    if (review.rating < 1 || review.rating > 5 || review.review.length <= 0) {
        return;
    }

    // defer until authenticated
    if (window.spacescout_authenticated_user.length == 0) {
        $.cookie('space_review', JSON.stringify({ id: id, review: review }));
        window.location.href = '/login?next=' + window.location.pathname;
    }

    postRatingAndReview(id, review);
}

function postRatingAndReview(id, review) {
    $.ajax({
        url: 'web_api/v1/space/' + id + '/reviews',
        dataType: 'json',
        contentType: "application/json",
        data: JSON.stringify(review),
        type: "POST",
        success: function (data) {
            $('.space-reviews button.write-a-review').hide();
            $('.space-review-compose').hide(400);
            $('.space-review-submitted').show();
        },
        error: function (xhr, textStatus, errorThrown) {
            console.log('Unable to post reviews: ' + xhr.responseText);
        }
    });
}

function showRatingEditor () {
    $('.space-reviews button.write-a-review').hide();
    $('#space-review-remaining').html(window.spacescout_reviews.review_char_limit);
    $('.space-reviews-none').hide(400);
    $('.space-review-compose').show(400, function(){
        var w_node = $('.space-detail-body'),
            w_top = w_node.scrollTop(),
            w_height = w_node.height(),
            t_node = $(this),
            t_top = t_node.offset().top - w_node.offset().top,
            t_height = t_node.height(),
            diff = Math.ceil((t_top + t_height) - (w_top + w_height)),
            padding = 20;

        if (diff > 0) {
            w_node.animate( {scrollTop: (diff + w_top + padding)}, '500');
        }
    });
}<|endoftext|>


<commit_before>$(document).ready(function() {
    var codes = document.getElementsByTagName("code");
    var title, elTitle, elPre;
    for (var i=0, l=codes.length ; i<l ; i++) {
        elPre = codes[i].parentNode;
        if (elPre.tagName != "PRE") continue;

        // Prepare for highlighting
        // elPre.className = elPre.className.replace("sourceCode ","");
        if (elPre.className.match("sourceCode")) {
            switch (elPre.className.replace("sourceCode ","")) {
                case 'css':
                case 'haskell':
                case 'html':
                case 'php':
                case 'java':
                case 'python':
                    elPre.className = "sourceCode sh_" + elPre.className.replace("sourceCode ", "");
                    break;
                case 'js':
                    elPre.className += " sh_javascript";
                    break;
                case 'literate haskell':
                    elPre.className += " sh_haskell";
                    break;
            }
        }
    }
    sh_highlightDocument('/static/js/lang/', '.js');
});
<commit_msg>relative url to lang files<commit_after>$(document).ready(function() {
    var codes = document.getElementsByTagName("code");
    var title, elTitle, elPre;
    for (var i=0, l=codes.length ; i<l ; i++) {
        elPre = codes[i].parentNode;
        if (elPre.tagName != "PRE") continue;

        // Prepare for highlighting
        // elPre.className = elPre.className.replace("sourceCode ","");
        if (elPre.className.match("sourceCode")) {
            switch (elPre.className.replace("sourceCode ","")) {
                case 'css':
                case 'haskell':
                case 'html':
                case 'php':
                case 'java':
                case 'python':
                    elPre.className = "sourceCode sh_" + elPre.className.replace("sourceCode ", "");
                    break;
                case 'js':
                    elPre.className += " sh_javascript";
                    break;
                case 'literate haskell':
                    elPre.className += " sh_haskell";
                    break;
            }
        }
    }
    sh_highlightDocument('../static/js/lang/', '.js');
});
<|endoftext|>


<commit_before>export default function foo() {
  console.log('it worked!');
}<commit_msg>try logging heroku-specific message<commit_after>export default function foo() {
  console.log('heroku is building this!');
}<|endoftext|>


<commit_before>(function () {

// This is where most of our initialization takes place.
// TODO: Organize it a lot better.  In particular, move bigger
//       functions to other modules.

/* We use 'visibility' rather than 'display' and jQuery's show() / hide(),
   because we want to reserve space for the email address.  This avoids
   things jumping around slightly when the email address is shown. */

var current_message_hover;
function message_unhover() {
    if (current_message_hover === undefined) {
        return;
    }
    current_message_hover.find('span.edit_content').html("");
    current_message_hover.removeClass('message_hovered');
    current_message_hover = undefined;
}

function message_hover(message_row) {
    var message;

    var id = parseInt(message_row.attr("zid"), 10);
    if (current_message_hover && message_row && current_message_hover.attr("zid") === message_row.attr("zid")) {
        return;
    }
    // Don't allow on-hover editing for local-only messages
    if (message_row.hasClass('local')) {
        return;
    }
    message = current_msg_list.get(rows.id(message_row));
    message_unhover();
    message_row.addClass('message_hovered');
    current_message_hover = message_row;

    if (!message_edit.is_topic_editable(message)) {
        // The actions and reactions icon hover logic is handled entirely by CSS
        return;
    }

    // But the message edit hover icon is determined by whether the message is still editable
    if (message_edit.get_editability(message) === message_edit.editability_types.FULL &&
        !message.status_message) {
        message_row.find(".edit_content").html('');
    } else {
        message_row.find(".edit_content").html('');
    }
}

function should_skip_mobile_resize() {
    // If we are in the mobile browser then we need to handle resize event
    // more carefully because virtual keyboard causes resize event to
    // trigger and this leads the input elements to loose focus.
    if (util.is_mobile()) {
        // If user is trying to search other users in right sidebar
        // then don't resize due to opening of virtual keyboard in
        // mobile browser because this leads the search bar to loose
        // focus and it becomes impossible to type in the input field.
        if ($('.user-list-filter').is(':focus')) {
            return true;
        }
        // Don't resize when the user is filtering the streams due to the
        // reasons mentioned in the previous comment.
        if ($('.stream-list-filter').is(':focus')) {
            return true;
        }
    }
    // resize in all other cases.
    return false;
}

exports.initialize_kitchen_sink_stuff = function () {
    // TODO:
    //      This function is a historical dumping ground
    //      for lots of miscellaneous setup.  Almost all of
    //      the code here can probably be moved to more
    //      specific-purpose modules like message_viewport.js.

    var throttled_mousewheelhandler = _.throttle(function (e, delta) {
        // Most of the mouse wheel's work will be handled by the
        // scroll handler, but when we're at the top or bottom of the
        // page, the pointer may still need to move.

        if (delta < 0) {
            if (message_viewport.at_top()) {
                navigate.up();
            }
        } else if (delta > 0) {
            if (message_viewport.at_bottom()) {
                navigate.down();
            }
        }

        message_viewport.last_movement_direction = delta;
    }, 50);

    message_viewport.message_pane.on('wheel', function (e) {
        var delta = e.originalEvent.deltaY;
        if (!overlays.is_active()) {
            // In the message view, we use a throttled mousewheel handler.
            throttled_mousewheelhandler(e, delta);
        }
        // If in a modal, we neither handle the event nor
        // preventDefault, allowing the modal to scroll normally.
    });

    $(window).resize(_.throttle(function () {
        if (!should_skip_mobile_resize()) {
            resize.handler();
        }
    }, 50));

    // Scrolling in overlays. input boxes, and other elements that
    // explicitly scroll should not scroll the main view.  Stop
    // propagation in all cases.  Also, ignore the event if the
    // element is already at the top or bottom.  Otherwise we get a
    // new scroll event on the parent (?).
    $('.modal-body, .scrolling_list, input, textarea').on('wheel', function (e) {
        var self = $(this);
        var scroll = self.scrollTop();
        var delta = e.originalEvent.deltaY;

        // The -1 fudge factor is important here due to rounding errors.  Better
        // to err on the side of not scrolling.
        var max_scroll = this.scrollHeight - self.innerHeight() - 1;

        e.stopPropagation();
        if (delta < 0 && scroll <= 0 ||
            delta > 0 && scroll >= max_scroll) {
            e.preventDefault();
        }
    });

    // Ignore wheel events in the compose area which weren't already handled above.
    $('#compose').on('wheel', function (e) {
        e.stopPropagation();
        e.preventDefault();
    });

    // A little hackish, because it doesn't seem to totally get us the
    // exact right width for the floating_recipient_bar and compose
    // box, but, close enough for now.
    resize.handler();

    if (!page_params.left_side_userlist) {
        $("#navbar-buttons").addClass("right-userlist");
    }

    if (page_params.high_contrast_mode) {
        $("body").addClass("high-contrast");
    }

    if (!page_params.dense_mode) {
        $("body").addClass("less_dense_mode");
    } else {
        $("body").addClass("more_dense_mode");
    }

    $("#main_div").on("mouseover", ".message_row", function () {
        var row = $(this).closest(".message_row");
        message_hover(row);
    });

    $("#main_div").on("mouseleave", ".message_row", function () {
        message_unhover();
    });

    $("#main_div").on("mouseover", ".sender_info_hover", function () {
        var row = $(this).closest(".message_row");
        row.addClass("sender_name_hovered");
    });

    $("#main_div").on("mouseout", ".sender_info_hover", function () {
        var row = $(this).closest(".message_row");
        row.removeClass("sender_name_hovered");
    });

    $("#main_div").on("mouseenter", ".youtube-video a", function () {
        $(this).addClass("fa fa-play");
    });

    $("#main_div").on("mouseleave", ".youtube-video a", function () {
        $(this).removeClass("fa fa-play");
    });

    $("#subscriptions_table").on("mouseover", ".subscription_header", function () {
        $(this).addClass("active");
    });

    $("#subscriptions_table").on("mouseout", ".subscription_header", function () {
        $(this).removeClass("active");
    });

    $("#stream_message_recipient_stream").on('blur', function () {
        compose_actions.decorate_stream_bar(this.value);
    });

    $(window).on('blur', function () {
        $(document.body).addClass('window_blurred');
    });

    $(window).on('focus', function () {
        $(document.body).removeClass('window_blurred');
    });

    $(document).on('message_selected.zulip', function (event) {
        if (current_msg_list !== event.msg_list) {
            return;
        }
        if (event.id === -1) {
            // If the message list is empty, don't do anything
            return;
        }
        var row = event.msg_list.get_row(event.id);
        $('.selected_message').removeClass('selected_message');
        row.addClass('selected_message');

        if (event.then_scroll) {
            if (row.length === 0) {
                var row_from_dom = current_msg_list.get_row(event.id);
                var messages = event.msg_list.all_messages();
                blueslip.debug("message_selected missing selected row", {
                    previously_selected: event.previously_selected,
                    selected_id: event.id,
                    selected_idx: event.msg_list.selected_idx(),
                    selected_idx_exact: messages.indexOf(event.msg_list.get(event.id)),
                    render_start: event.msg_list.view._render_win_start,
                    render_end: event.msg_list.view._render_win_end,
                    selected_id_from_idx: messages[event.msg_list.selected_idx()].id,
                    msg_list_sorted: _.isEqual(
                        _.pluck(messages, 'id'),
                        _.chain(current_msg_list.all_messages()).pluck('id').clone().value().sort()
                    ),
                    found_in_dom: row_from_dom.length,
                });
            }
            if (event.target_scroll_offset !== undefined) {
                current_msg_list.view.set_message_offset(event.target_scroll_offset);
            } else {
                // Scroll to place the message within the current view;
                // but if this is the initial placement of the pointer,
                // just place it in the very center
                message_viewport.recenter_view(row,
                                               {from_scroll: event.from_scroll,
                                                force_center: event.previously_selected === -1});
            }
        }
    });

    $("#main_div").on("mouseenter", ".message_time", function (e) {
        var time_elem = $(e.target);
        var row = time_elem.closest(".message_row");
        var message = current_msg_list.get(rows.id(row));
        timerender.set_full_datetime(message, time_elem);
    });

    $('#streams_header h4').tooltip({placement: 'right',
                                     animation: false});

    $('#streams_header i[data-toggle="tooltip"]').tooltip({placement: 'left',
                                                           animation: false});

    $('#userlist-header #userlist-title').tooltip({placement: 'right',
                                                   animation: false});

    $('#userlist-header #user_filter_icon').tooltip({placement: 'left',
                                                     animation: false});

    $('.message_failed i[data-toggle="tooltip"]').tooltip();

    $('.copy_message[data-toggle="tooltip"]').tooltip();

    $('#keyboard-icon').tooltip();

    $("body").on("mouseover", ".message_edit_content", function () {
        $(this).closest(".message_row").find(".copy_message").show();
    });

    $("body").on("mouseout", ".message_edit_content", function () {
        $(this).closest(".message_row").find(".copy_message").hide();
    });

    $("body").on("mouseenter", ".copy_message", function () {
        $(this).show();
        $(this).tooltip('show');
    });

    $("body").on("mouseleave", ".copy_message", function () {
        $(this).tooltip('hide');
    });

    if (!page_params.realm_allow_message_editing) {
        $("#edit-message-hotkey-help").hide();
    }

    if (page_params.realm_presence_disabled) {
        $("#user-list").hide();
        $("#group-pm-list").hide();
    }
};

exports.initialize_everything = function () {
    // initialize other stuff
    people.initialize();
    scroll_bar.initialize();
    message_viewport.initialize();
    exports.initialize_kitchen_sink_stuff();
    echo.initialize();
    stream_color.initialize();
    stream_edit.initialize();
    stream_data.initialize();
    muting.initialize();
    subs.initialize();
    condense.initialize();
    lightbox.initialize();
    click_handlers.initialize();
    copy_and_paste.initialize();
    overlays.initialize();
    invite.initialize();
    timerender.initialize();
    if (!page_params.search_pills_enabled) {
        tab_bar.initialize();
    }
    server_events.initialize();
    user_status.initialize();
    compose_pm_pill.initialize();
    search_pill_widget.initialize();
    reload.initialize();
    user_groups.initialize();
    unread.initialize();
    bot_data.initialize(); // Must happen after people.initialize()
    message_fetch.initialize();
    message_scroll.initialize();
    emoji.initialize();
    markdown.initialize(); // Must happen after emoji.initialize()
    compose.initialize();
    composebox_typeahead.initialize(); // Must happen after compose.initialize()
    search.initialize();
    tutorial.initialize();
    notifications.initialize();
    gear_menu.initialize();
    settings_panel_menu.initialize();
    settings_sections.initialize();
    settings_toggle.initialize();
    hashchange.initialize();
    pointer.initialize();
    unread_ui.initialize();
    activity.initialize();
    emoji_picker.initialize();
    compose_fade.initialize();
    pm_list.initialize();
    stream_list.initialize();
    topic_list.initialize();
    topic_zoom.initialize();
    drafts.initialize();
    sent_messages.initialize();
    hotspots.initialize();
    ui.initialize();
    panels.initialize();
    typing.initialize();
    starred_messages.initialize();
    user_status_ui.initialize();
};

$(function () {
    exports.initialize_everything();
});

}());
<commit_msg>emoji: Allow users to add emoji or react in mobile browsers.<commit_after>(function () {

// This is where most of our initialization takes place.
// TODO: Organize it a lot better.  In particular, move bigger
//       functions to other modules.

/* We use 'visibility' rather than 'display' and jQuery's show() / hide(),
   because we want to reserve space for the email address.  This avoids
   things jumping around slightly when the email address is shown. */

var current_message_hover;
function message_unhover() {
    if (current_message_hover === undefined) {
        return;
    }
    current_message_hover.find('span.edit_content').html("");
    current_message_hover.removeClass('message_hovered');
    current_message_hover = undefined;
}

function message_hover(message_row) {
    var message;

    var id = parseInt(message_row.attr("zid"), 10);
    if (current_message_hover && message_row && current_message_hover.attr("zid") === message_row.attr("zid")) {
        return;
    }
    // Don't allow on-hover editing for local-only messages
    if (message_row.hasClass('local')) {
        return;
    }
    message = current_msg_list.get(rows.id(message_row));
    message_unhover();
    message_row.addClass('message_hovered');
    current_message_hover = message_row;

    if (!message_edit.is_topic_editable(message)) {
        // The actions and reactions icon hover logic is handled entirely by CSS
        return;
    }

    // But the message edit hover icon is determined by whether the message is still editable
    if (message_edit.get_editability(message) === message_edit.editability_types.FULL &&
        !message.status_message) {
        message_row.find(".edit_content").html('');
    } else {
        message_row.find(".edit_content").html('');
    }
}

function should_skip_mobile_resize() {
    // If we are in the mobile browser then we need to handle resize event
    // more carefully because virtual keyboard causes resize event to
    // trigger and this leads the input elements to loose focus.
    if (util.is_mobile()) {
        // If user is trying to search other users in right sidebar
        // then don't resize due to opening of virtual keyboard in
        // mobile browser because this leads the search bar to loose
        // focus and it becomes impossible to type in the input field.
        if ($('.user-list-filter').is(':focus')) {
            return true;
        }
        // Don't resize when the user is filtering the streams due to the
        // reasons mentioned in the previous comment.
        if ($('.stream-list-filter').is(':focus')) {
            return true;
        }
        // Don't resize in mobile browser when the user is trying to add
        // emoji to the message or trying to react on other message due
        // to the reasons mentioned above.
        if ($('.emoji-popover-filter').is(':focus')) {
            return true;
        }
    }
    // resize in all other cases.
    return false;
}

exports.initialize_kitchen_sink_stuff = function () {
    // TODO:
    //      This function is a historical dumping ground
    //      for lots of miscellaneous setup.  Almost all of
    //      the code here can probably be moved to more
    //      specific-purpose modules like message_viewport.js.

    var throttled_mousewheelhandler = _.throttle(function (e, delta) {
        // Most of the mouse wheel's work will be handled by the
        // scroll handler, but when we're at the top or bottom of the
        // page, the pointer may still need to move.

        if (delta < 0) {
            if (message_viewport.at_top()) {
                navigate.up();
            }
        } else if (delta > 0) {
            if (message_viewport.at_bottom()) {
                navigate.down();
            }
        }

        message_viewport.last_movement_direction = delta;
    }, 50);

    message_viewport.message_pane.on('wheel', function (e) {
        var delta = e.originalEvent.deltaY;
        if (!overlays.is_active()) {
            // In the message view, we use a throttled mousewheel handler.
            throttled_mousewheelhandler(e, delta);
        }
        // If in a modal, we neither handle the event nor
        // preventDefault, allowing the modal to scroll normally.
    });

    $(window).resize(_.throttle(function () {
        if (!should_skip_mobile_resize()) {
            resize.handler();
        }
    }, 50));

    // Scrolling in overlays. input boxes, and other elements that
    // explicitly scroll should not scroll the main view.  Stop
    // propagation in all cases.  Also, ignore the event if the
    // element is already at the top or bottom.  Otherwise we get a
    // new scroll event on the parent (?).
    $('.modal-body, .scrolling_list, input, textarea').on('wheel', function (e) {
        var self = $(this);
        var scroll = self.scrollTop();
        var delta = e.originalEvent.deltaY;

        // The -1 fudge factor is important here due to rounding errors.  Better
        // to err on the side of not scrolling.
        var max_scroll = this.scrollHeight - self.innerHeight() - 1;

        e.stopPropagation();
        if (delta < 0 && scroll <= 0 ||
            delta > 0 && scroll >= max_scroll) {
            e.preventDefault();
        }
    });

    // Ignore wheel events in the compose area which weren't already handled above.
    $('#compose').on('wheel', function (e) {
        e.stopPropagation();
        e.preventDefault();
    });

    // A little hackish, because it doesn't seem to totally get us the
    // exact right width for the floating_recipient_bar and compose
    // box, but, close enough for now.
    resize.handler();

    if (!page_params.left_side_userlist) {
        $("#navbar-buttons").addClass("right-userlist");
    }

    if (page_params.high_contrast_mode) {
        $("body").addClass("high-contrast");
    }

    if (!page_params.dense_mode) {
        $("body").addClass("less_dense_mode");
    } else {
        $("body").addClass("more_dense_mode");
    }

    $("#main_div").on("mouseover", ".message_row", function () {
        var row = $(this).closest(".message_row");
        message_hover(row);
    });

    $("#main_div").on("mouseleave", ".message_row", function () {
        message_unhover();
    });

    $("#main_div").on("mouseover", ".sender_info_hover", function () {
        var row = $(this).closest(".message_row");
        row.addClass("sender_name_hovered");
    });

    $("#main_div").on("mouseout", ".sender_info_hover", function () {
        var row = $(this).closest(".message_row");
        row.removeClass("sender_name_hovered");
    });

    $("#main_div").on("mouseenter", ".youtube-video a", function () {
        $(this).addClass("fa fa-play");
    });

    $("#main_div").on("mouseleave", ".youtube-video a", function () {
        $(this).removeClass("fa fa-play");
    });

    $("#subscriptions_table").on("mouseover", ".subscription_header", function () {
        $(this).addClass("active");
    });

    $("#subscriptions_table").on("mouseout", ".subscription_header", function () {
        $(this).removeClass("active");
    });

    $("#stream_message_recipient_stream").on('blur', function () {
        compose_actions.decorate_stream_bar(this.value);
    });

    $(window).on('blur', function () {
        $(document.body).addClass('window_blurred');
    });

    $(window).on('focus', function () {
        $(document.body).removeClass('window_blurred');
    });

    $(document).on('message_selected.zulip', function (event) {
        if (current_msg_list !== event.msg_list) {
            return;
        }
        if (event.id === -1) {
            // If the message list is empty, don't do anything
            return;
        }
        var row = event.msg_list.get_row(event.id);
        $('.selected_message').removeClass('selected_message');
        row.addClass('selected_message');

        if (event.then_scroll) {
            if (row.length === 0) {
                var row_from_dom = current_msg_list.get_row(event.id);
                var messages = event.msg_list.all_messages();
                blueslip.debug("message_selected missing selected row", {
                    previously_selected: event.previously_selected,
                    selected_id: event.id,
                    selected_idx: event.msg_list.selected_idx(),
                    selected_idx_exact: messages.indexOf(event.msg_list.get(event.id)),
                    render_start: event.msg_list.view._render_win_start,
                    render_end: event.msg_list.view._render_win_end,
                    selected_id_from_idx: messages[event.msg_list.selected_idx()].id,
                    msg_list_sorted: _.isEqual(
                        _.pluck(messages, 'id'),
                        _.chain(current_msg_list.all_messages()).pluck('id').clone().value().sort()
                    ),
                    found_in_dom: row_from_dom.length,
                });
            }
            if (event.target_scroll_offset !== undefined) {
                current_msg_list.view.set_message_offset(event.target_scroll_offset);
            } else {
                // Scroll to place the message within the current view;
                // but if this is the initial placement of the pointer,
                // just place it in the very center
                message_viewport.recenter_view(row,
                                               {from_scroll: event.from_scroll,
                                                force_center: event.previously_selected === -1});
            }
        }
    });

    $("#main_div").on("mouseenter", ".message_time", function (e) {
        var time_elem = $(e.target);
        var row = time_elem.closest(".message_row");
        var message = current_msg_list.get(rows.id(row));
        timerender.set_full_datetime(message, time_elem);
    });

    $('#streams_header h4').tooltip({placement: 'right',
                                     animation: false});

    $('#streams_header i[data-toggle="tooltip"]').tooltip({placement: 'left',
                                                           animation: false});

    $('#userlist-header #userlist-title').tooltip({placement: 'right',
                                                   animation: false});

    $('#userlist-header #user_filter_icon').tooltip({placement: 'left',
                                                     animation: false});

    $('.message_failed i[data-toggle="tooltip"]').tooltip();

    $('.copy_message[data-toggle="tooltip"]').tooltip();

    $('#keyboard-icon').tooltip();

    $("body").on("mouseover", ".message_edit_content", function () {
        $(this).closest(".message_row").find(".copy_message").show();
    });

    $("body").on("mouseout", ".message_edit_content", function () {
        $(this).closest(".message_row").find(".copy_message").hide();
    });

    $("body").on("mouseenter", ".copy_message", function () {
        $(this).show();
        $(this).tooltip('show');
    });

    $("body").on("mouseleave", ".copy_message", function () {
        $(this).tooltip('hide');
    });

    if (!page_params.realm_allow_message_editing) {
        $("#edit-message-hotkey-help").hide();
    }

    if (page_params.realm_presence_disabled) {
        $("#user-list").hide();
        $("#group-pm-list").hide();
    }
};

exports.initialize_everything = function () {
    // initialize other stuff
    people.initialize();
    scroll_bar.initialize();
    message_viewport.initialize();
    exports.initialize_kitchen_sink_stuff();
    echo.initialize();
    stream_color.initialize();
    stream_edit.initialize();
    stream_data.initialize();
    muting.initialize();
    subs.initialize();
    condense.initialize();
    lightbox.initialize();
    click_handlers.initialize();
    copy_and_paste.initialize();
    overlays.initialize();
    invite.initialize();
    timerender.initialize();
    if (!page_params.search_pills_enabled) {
        tab_bar.initialize();
    }
    server_events.initialize();
    user_status.initialize();
    compose_pm_pill.initialize();
    search_pill_widget.initialize();
    reload.initialize();
    user_groups.initialize();
    unread.initialize();
    bot_data.initialize(); // Must happen after people.initialize()
    message_fetch.initialize();
    message_scroll.initialize();
    emoji.initialize();
    markdown.initialize(); // Must happen after emoji.initialize()
    compose.initialize();
    composebox_typeahead.initialize(); // Must happen after compose.initialize()
    search.initialize();
    tutorial.initialize();
    notifications.initialize();
    gear_menu.initialize();
    settings_panel_menu.initialize();
    settings_sections.initialize();
    settings_toggle.initialize();
    hashchange.initialize();
    pointer.initialize();
    unread_ui.initialize();
    activity.initialize();
    emoji_picker.initialize();
    compose_fade.initialize();
    pm_list.initialize();
    stream_list.initialize();
    topic_list.initialize();
    topic_zoom.initialize();
    drafts.initialize();
    sent_messages.initialize();
    hotspots.initialize();
    ui.initialize();
    panels.initialize();
    typing.initialize();
    starred_messages.initialize();
    user_status_ui.initialize();
};

$(function () {
    exports.initialize_everything();
});

}());
<|endoftext|>


<commit_before>function geocodeAddress(address) {
	console.log("gcA0");
	var geocoder = new google.maps.Geocoder();
	geocoder.geocode({address: address}, function(results, status) {
		console.log(results);
	    if (status == google.maps.GeocoderStatus.OK) {
	   		const location = {
	   			lat: results[0].geometry.location.lat(),
	   			lon: results[0].geometry.location.lng(),
	   			postCode: results[0].address_components[5].long_name
	   		};
	   		showLocation(location);
	    }
	    else{
	    	console.log("Something went wrong");
	    	return {};
	    }
	});
}

function showLocation(location){
	console.log(location.postCode);
	var barData = {
		name: $('#name').val(),
		address: $('#address').val(),
		postCode: location.postCode,
		city: $('#city').val(),
		lat: location.lat,
		lon: location.lon
		};
	console.log(JSON.stringify(barData));

	var url = "http://barbababa-skeletor.rhcloud.com/saveBar";

	$.post(url, barData);

    if(confirm("Bar added succesfully!")){
    	location.reload();
    }
    else{
    	location.reload();
    }

/*
	$.ajax({
		url: url,
		type: 'POST',
        data: barData,
        contentType: 'application/json; charset=utf-8',
		dataType: 'json',
		success: function (json) {
			console.log(json);
		}
	});
*/
};

$("#barForm").submit(function( event ) {
	event.preventDefault();
  	var address = $('#address').val();
  	var city = $('#city').val();
  	var addressInput = address +", " + city;
  	console.log(addressInput);
	geocodeAddress(addressInput);
});
<commit_msg>webform update<commit_after>function geocodeAddress(address) {
	console.log("gcA0");
	var geocoder = new google.maps.Geocoder();
	geocoder.geocode({address: address}, function(results, status) {
		console.log(results);
	    if (status == google.maps.GeocoderStatus.OK) {
	   		const location = {
	   			lat: results[0].geometry.location.lat(),
	   			lon: results[0].geometry.location.lng(),
	   			postCode: results[0].address_components[5].long_name
	   		};
	   		showLocation(location);
	    }
	    else{
	    	console.log("Something went wrong");
	    	return {};
	    }
	});
}

function showLocation(location){
	console.log(location.postCode);
	var barData = {
		name: $('#name').val(),
		address: $('#address').val(),
		postCode: location.postCode,
		city: $('#city').val(),
		lat: location.lat,
		lon: location.lon
		};
	console.log(JSON.stringify(barData));

	var url = "http://barbababa-skeletor.rhcloud.com/saveBar";

	$.post(url, barData);

    if(confirm("Bar added succesfully!")){
    	window.location.reload();
    }
    else{
    	window.location.reload();
    }

/*
	$.ajax({
		url: url,
		type: 'POST',
        data: barData,
        contentType: 'application/json; charset=utf-8',
		dataType: 'json',
		success: function (json) {
			console.log(json);
		}
	});
*/
};

$("#barForm").submit(function( event ) {
	event.preventDefault();
  	var address = $('#address').val();
  	var city = $('#city').val();
  	var addressInput = address +", " + city;
  	console.log(addressInput);
	geocodeAddress(addressInput);
});
<|endoftext|>


<commit_before><commit_msg>Tested commit<commit_after>var objects = "";
<|endoftext|>


<commit_before>import { React, observable, action, computed } from 'vendor';
import { first, pick, sortBy, filter, sumBy } from 'lodash';
import ScrollTo from '../../helpers/scroll-to';
import DropQuestion from '../../models/task-plans/teacher/dropped_question';
import EditUX from '../assignment-edit/ux';
import DetailsBody from '../assignment-edit/details-body';
import rowDataSorter from './scores-data-sorter';

export default class AssignmentReviewUX {

  @observable selectedPeriod;
  @observable exercisesHaveBeenFetched = false;
  @observable isDisplayingGrantExtension = false;
  @observable isDisplayingDropQuestions = false;
  @observable isDisplayingConfirmDelete = false;
  @observable isDisplayingEditAssignment = false;
  @observable isDeleting = false;
  @observable editUX;
  @observable editablePlan;
  @observable rowSort = { key: 0, asc: true, dataType: 'name' };
  @observable searchingMatcher = null;
  @observable reverseNameOrder = false;
  @observable displayTotalInPercent = false;

  freeResponseQuestions = observable.map();
  pendingExtensions = observable.map();
  pendingDroppedQuestions = observable.map();

  constructor(attrs = null) {
    if (attrs) { this.initialize(attrs); }
  }

  @action async initialize({
    id, course, onCompleteDelete, onEditAssignedQuestions, onTabSelection, history,
    scores = course.teacherTaskPlans.withPlanId(id).scores,
    windowImpl = window,
  }) {
    this.id = id;
    this.history = history;
    this.scroller = new ScrollTo({ windowImpl });
    this.planScores = scores;
    this.course = course;
    this.selectedPeriod = first(course.periods.active);
    this.onCompleteDelete = onCompleteDelete;
    this.onEditAssignedQuestions = onEditAssignedQuestions;
    this.onTabSelection = onTabSelection;

    await this.planScores.fetch();
    await this.planScores.taskPlan.fetch();
    await this.planScores.taskPlan.analytics.fetch();

    await this.planScores.ensureExercisesLoaded();

    this.exercisesHaveBeenFetched = true;
  }

  @computed get isScoresReady() { return this.planScores.api.hasBeenFetched; }
  @computed get isExercisesReady() { return this.isScoresReady && this.exercisesHaveBeenFetched; }
  @computed get planId() { return this.planScores.id; }

  @action.bound setSelectedPeriod(period) {
    this.selectedPeriod = period;
  }

  @computed get scores() {
    return this.planScores.tasking_plans.find(tp => this.selectedPeriod.id == tp.period_id);
  }

  @computed get taskingPlan() {
    return this.planScores.taskPlan.tasking_plans.forPeriod(this.selectedPeriod);
  }

  @computed get taskPlan() {
    return this.planScores.taskPlan;
  }

  // methods relating to sorting and filtering scores table

  @computed get sortedStudents() {
    const students = rowDataSorter(this.scores.students, this.rowSort);
    if (!this.searchingMatcher) {
      return students;
    }
    return filter(students, s => s.name.match(this.searchingMatcher));
  }

  @action.bound changeRowSortingOrder(key, dataType) {
    this.rowSort.asc = this.rowSort.key === key ? (!this.rowSort.asc) : false;
    this.rowSort.key = key;
    this.rowSort.dataType = dataType;
  }

  isRowSortedBy({ sortKey, dataType }) {
    return (this.rowSort.key === sortKey) && (this.rowSort.dataType === dataType);
  }

  sortForColumn(sortKey, dataType) {
    return (this.rowSort.key === sortKey) && (this.rowSort.dataType === dataType) ? this.rowSort : false;
  }

  @action.bound toggleNameOrder() {
    this.reverseNameOrder = !this.reverseNameOrder;
  }

  @computed get nameOrderHeader() {
    return this.reverseNameOrder ? 'Firstname Lastname' : 'Lastname, Firstname';
  }

  isShowingFreeResponseForQuestion(question) {
    return Boolean(this.freeResponseQuestions.get(question.id));
  }

  @action.bound toggleFreeResponseForQuestion(question) {
    this.freeResponseQuestions.set(question.id, !this.isShowingFreeResponseForQuestion(question));
  }

  @action.bound onSearchStudentChange({ target: { value } }) {
    this.searchingMatcher = value ? RegExp(value, 'i') : null;
  }

  // methods relating to granting extensions

  @action.bound cancelDisplayingGrantExtension() {
    this.pendingExtensions.clear();
    this.isDisplayingGrantExtension = false;
  }

  @action.bound async saveDisplayingGrantExtension(values) {
    const due_at = this.course.momentInZone(values.extension_due_date);
    const closes_at = this.course.momentInZone(values.extension_close_date);
    const extensions = [];
    this.pendingExtensions.forEach((extend, role_id) => {
      if (extend) {
        extensions.push({ role_id, due_at, closes_at });
      }
    });
    if (extensions.length > 0) {
      await this.taskPlan.grantExtensions(extensions);
    }
    this.cancelDisplayingGrantExtension();
  }

  wasGrantedExtension(role_id) {
    return Boolean(this.taskPlan.extensions.find(e => e.role_id == role_id));
  }

  // methods relating to droppping questions

  @action toggleDropQuestion(isDropped, { question_id }) {
    if (isDropped) {
      this.pendingDroppedQuestions.set(question_id, new DropQuestion({ question_id }));
    } else {
      this.pendingDroppedQuestions.delete(question_id);
    }
  }

  @action.bound cancelDisplayingDropQuestions() {
    this.pendingDroppedQuestions.clear();
    this.changedDroppedQuestions.forEach(dq => dq.dropped.isChanged = false);
    this.isDisplayingDropQuestions = false;
  }

  @action.bound async saveDropQuestions() {
    const { taskPlan } = this;

    this.pendingDroppedQuestions.forEach(dq => {
      taskPlan.dropped_questions.push(dq);
      this.planScores.dropped_questions.push(dq);
    });

    // Existing dropped Qs need to be updated to pick up allocation changes
    this.changedDroppedQuestions.forEach(h => {
      const { question_id, drop_method } = h.dropped;
      taskPlan.dropped_questions.find(dq => dq.question_id == question_id).drop_method = drop_method;
    });

    await taskPlan.saveDroppedQuestions();
    this.cancelDisplayingDropQuestions();
  }

  droppedQuestionRecord(heading) {
    return heading.dropped || this.pendingDroppedQuestions.get(heading.question_id);
  }

  @computed get changedDroppedQuestions() {
    return this.scores.question_headings.filter(h => h.dropped && h.dropped.isChanged);
  }

  @computed get canSubmitDroppedQuestions() {
    return Boolean(
      this.changedDroppedQuestions.length > 0 ||
      this.pendingDroppedQuestions.size > 0
    );
  }

  @action.bound onDelete() {
    this.isDisplayingConfirmDelete = true;
  }

  @action.bound async onConfirmDelete() {
    const { taskPlan } = this.planScores;
    const date = taskPlan.dateRanges.opens.start.format('YYYY-MM-DD');
    this.isDeleting = true;
    await taskPlan.destroy();
    this.onCompleteDelete(date);
  }

  @action.bound onCancelDelete() {
    this.isDisplayingConfirmDelete = false;
  }

  @action.bound async onEdit() {
    await this.taskPlan.fetch();

    this.editUX = new EditUX();

    await this.editUX.initialize({
      ...this.params,
      plan: this.taskPlan,
      history,
      course: this.course,
    });

    this.isDisplayingEditAssignment = true;
  }

  @action.bound onCancelEdit() {
    this.isDisplayingEditAssignment = false;
  }

  @action.bound async onSavePlan() {
    await this.editUX.savePlan();
    Object.assign(this.planScores, pick(this.editUX.plan, ['title', 'description']));
    this.planScores.grading_template = this.editUX.plan.gradingTemplate;
    this.isDisplayingEditAssignment = false;
  }

  @action.bound renderDetails(form) {
    this.editUX.form = form;
    return <DetailsBody ux={this.editUX} />;
  }

  @action.bound async onPublishScores() {
    await this.taskingPlan.publishScores();
  }

  @computed get isPublishingScores() {
    return Boolean(
      this.taskingPlan && this.taskingPlan.api.isPending
    );
  }

  @computed get submitPending() {
    return Boolean(
      this.editUX.plan.api.isPending
    );
  }

  @computed get canSubmit() {
    return Boolean(
      this.editUX.validations.isValid
    );
  }

  @computed get areTaskingDatesSame() {
    return Boolean(
      this.planScores.taskPlan.areTaskingDatesSame
    );
  }

  @computed get taskingPlanDetails() {
    return this.areTaskingDatesSame ?
      [first(this.planScores.taskPlan.tasking_plans)] :
      sortBy(this.planScores.taskPlan.tasking_plans, tp => tp.period.name);
  }

  @computed get stats() {
    return this.planScores.taskPlan.analytics.stats;
  }

  @computed get progressStatsForPeriod() {
    // period stats will be undefined if no-ones worked the assignment in the period yet
    const periodStats = this.stats.find(s => s.period_id == this.selectedPeriod.id);
    const { total_count = 0, complete_count = 0, partially_complete_count = 0 } = periodStats || { };
    const notStartedCount = total_count - (complete_count + partially_complete_count);

    const items = [
      { label: 'Completed',
        value: complete_count,
        percent: (complete_count / total_count),
      },
      { label: 'In progress',
        value: partially_complete_count,
        percent: (partially_complete_count / total_count),
      },
      { label: 'Not started',
        value: notStartedCount,
        percent: (notStartedCount / total_count),
      },
    ];

    return items;
  }

  @computed get canDisplayGradingBlock() {
    return Boolean(this.planScores.isHomework && this.scores);
  }

  @computed get isReadingOrHomework() {
    return Boolean(['reading', 'homework'].includes(this.planScores.type));
  }

  @computed get hasUnPublishedScores() {
    return Boolean(this.scores.hasUnPublishedScores);
  }

  @computed get gradeableQuestionCount() {
    return sumBy(this.scores.question_headings.map(qh => qh.gradedStats), 'remaining');
  }

  @computed get hasGradeableAnswers() {
    return Boolean(this.gradeableQuestionCount > 0);
  }

}
<commit_msg>extensions on taskplan is null by default<commit_after>import { React, observable, action, computed } from 'vendor';
import { first, pick, sortBy, filter, sumBy } from 'lodash';
import ScrollTo from '../../helpers/scroll-to';
import DropQuestion from '../../models/task-plans/teacher/dropped_question';
import EditUX from '../assignment-edit/ux';
import DetailsBody from '../assignment-edit/details-body';
import rowDataSorter from './scores-data-sorter';

export default class AssignmentReviewUX {

  @observable selectedPeriod;
  @observable exercisesHaveBeenFetched = false;
  @observable isDisplayingGrantExtension = false;
  @observable isDisplayingDropQuestions = false;
  @observable isDisplayingConfirmDelete = false;
  @observable isDisplayingEditAssignment = false;
  @observable isDeleting = false;
  @observable editUX;
  @observable editablePlan;
  @observable rowSort = { key: 0, asc: true, dataType: 'name' };
  @observable searchingMatcher = null;
  @observable reverseNameOrder = false;
  @observable displayTotalInPercent = false;

  freeResponseQuestions = observable.map();
  pendingExtensions = observable.map();
  pendingDroppedQuestions = observable.map();

  constructor(attrs = null) {
    if (attrs) { this.initialize(attrs); }
  }

  @action async initialize({
    id, course, onCompleteDelete, onEditAssignedQuestions, onTabSelection, history,
    scores = course.teacherTaskPlans.withPlanId(id).scores,
    windowImpl = window,
  }) {
    this.id = id;
    this.history = history;
    this.scroller = new ScrollTo({ windowImpl });
    this.planScores = scores;
    this.course = course;
    this.selectedPeriod = first(course.periods.active);
    this.onCompleteDelete = onCompleteDelete;
    this.onEditAssignedQuestions = onEditAssignedQuestions;
    this.onTabSelection = onTabSelection;

    await this.planScores.fetch();
    await this.planScores.taskPlan.fetch();
    await this.planScores.taskPlan.analytics.fetch();

    await this.planScores.ensureExercisesLoaded();

    this.exercisesHaveBeenFetched = true;
  }

  @computed get isScoresReady() { return this.planScores.api.hasBeenFetched; }
  @computed get isExercisesReady() { return this.isScoresReady && this.exercisesHaveBeenFetched; }
  @computed get planId() { return this.planScores.id; }

  @action.bound setSelectedPeriod(period) {
    this.selectedPeriod = period;
  }

  @computed get scores() {
    return this.planScores.tasking_plans.find(tp => this.selectedPeriod.id == tp.period_id);
  }

  @computed get taskingPlan() {
    return this.planScores.taskPlan.tasking_plans.forPeriod(this.selectedPeriod);
  }

  @computed get taskPlan() {
    return this.planScores.taskPlan;
  }

  // methods relating to sorting and filtering scores table

  @computed get sortedStudents() {
    const students = rowDataSorter(this.scores.students, this.rowSort);
    if (!this.searchingMatcher) {
      return students;
    }
    return filter(students, s => s.name.match(this.searchingMatcher));
  }

  @action.bound changeRowSortingOrder(key, dataType) {
    this.rowSort.asc = this.rowSort.key === key ? (!this.rowSort.asc) : false;
    this.rowSort.key = key;
    this.rowSort.dataType = dataType;
  }

  isRowSortedBy({ sortKey, dataType }) {
    return (this.rowSort.key === sortKey) && (this.rowSort.dataType === dataType);
  }

  sortForColumn(sortKey, dataType) {
    return (this.rowSort.key === sortKey) && (this.rowSort.dataType === dataType) ? this.rowSort : false;
  }

  @action.bound toggleNameOrder() {
    this.reverseNameOrder = !this.reverseNameOrder;
  }

  @computed get nameOrderHeader() {
    return this.reverseNameOrder ? 'Firstname Lastname' : 'Lastname, Firstname';
  }

  isShowingFreeResponseForQuestion(question) {
    return Boolean(this.freeResponseQuestions.get(question.id));
  }

  @action.bound toggleFreeResponseForQuestion(question) {
    this.freeResponseQuestions.set(question.id, !this.isShowingFreeResponseForQuestion(question));
  }

  @action.bound onSearchStudentChange({ target: { value } }) {
    this.searchingMatcher = value ? RegExp(value, 'i') : null;
  }

  // methods relating to granting extensions

  @action.bound cancelDisplayingGrantExtension() {
    this.pendingExtensions.clear();
    this.isDisplayingGrantExtension = false;
  }

  @action.bound async saveDisplayingGrantExtension(values) {
    const due_at = this.course.momentInZone(values.extension_due_date);
    const closes_at = this.course.momentInZone(values.extension_close_date);
    const extensions = [];
    this.pendingExtensions.forEach((extend, role_id) => {
      if (extend) {
        extensions.push({ role_id, due_at, closes_at });
      }
    });
    if (extensions.length > 0) {
      await this.taskPlan.grantExtensions(extensions);
    }
    this.cancelDisplayingGrantExtension();
  }

  wasGrantedExtension(role_id) {
    return Boolean(
      this.taskPlan.extensions.length > 0 && this.taskPlan.extensions.find(e => e.role_id == role_id)
    );
  }

  // methods relating to droppping questions

  @action toggleDropQuestion(isDropped, { question_id }) {
    if (isDropped) {
      this.pendingDroppedQuestions.set(question_id, new DropQuestion({ question_id }));
    } else {
      this.pendingDroppedQuestions.delete(question_id);
    }
  }

  @action.bound cancelDisplayingDropQuestions() {
    this.pendingDroppedQuestions.clear();
    this.changedDroppedQuestions.forEach(dq => dq.dropped.isChanged = false);
    this.isDisplayingDropQuestions = false;
  }

  @action.bound async saveDropQuestions() {
    const { taskPlan } = this;

    this.pendingDroppedQuestions.forEach(dq => {
      taskPlan.dropped_questions.push(dq);
      this.planScores.dropped_questions.push(dq);
    });

    // Existing dropped Qs need to be updated to pick up allocation changes
    this.changedDroppedQuestions.forEach(h => {
      const { question_id, drop_method } = h.dropped;
      taskPlan.dropped_questions.find(dq => dq.question_id == question_id).drop_method = drop_method;
    });

    await taskPlan.saveDroppedQuestions();
    this.cancelDisplayingDropQuestions();
  }

  droppedQuestionRecord(heading) {
    return heading.dropped || this.pendingDroppedQuestions.get(heading.question_id);
  }

  @computed get changedDroppedQuestions() {
    return this.scores.question_headings.filter(h => h.dropped && h.dropped.isChanged);
  }

  @computed get canSubmitDroppedQuestions() {
    return Boolean(
      this.changedDroppedQuestions.length > 0 ||
      this.pendingDroppedQuestions.size > 0
    );
  }

  @action.bound onDelete() {
    this.isDisplayingConfirmDelete = true;
  }

  @action.bound async onConfirmDelete() {
    const { taskPlan } = this.planScores;
    const date = taskPlan.dateRanges.opens.start.format('YYYY-MM-DD');
    this.isDeleting = true;
    await taskPlan.destroy();
    this.onCompleteDelete(date);
  }

  @action.bound onCancelDelete() {
    this.isDisplayingConfirmDelete = false;
  }

  @action.bound async onEdit() {
    await this.taskPlan.fetch();

    this.editUX = new EditUX();

    await this.editUX.initialize({
      ...this.params,
      plan: this.taskPlan,
      history,
      course: this.course,
    });

    this.isDisplayingEditAssignment = true;
  }

  @action.bound onCancelEdit() {
    this.isDisplayingEditAssignment = false;
  }

  @action.bound async onSavePlan() {
    await this.editUX.savePlan();
    Object.assign(this.planScores, pick(this.editUX.plan, ['title', 'description']));
    this.planScores.grading_template = this.editUX.plan.gradingTemplate;
    this.isDisplayingEditAssignment = false;
  }

  @action.bound renderDetails(form) {
    this.editUX.form = form;
    return <DetailsBody ux={this.editUX} />;
  }

  @action.bound async onPublishScores() {
    await this.taskingPlan.publishScores();
  }

  @computed get isPublishingScores() {
    return Boolean(
      this.taskingPlan && this.taskingPlan.api.isPending
    );
  }

  @computed get submitPending() {
    return Boolean(
      this.editUX.plan.api.isPending
    );
  }

  @computed get canSubmit() {
    return Boolean(
      this.editUX.validations.isValid
    );
  }

  @computed get areTaskingDatesSame() {
    return Boolean(
      this.planScores.taskPlan.areTaskingDatesSame
    );
  }

  @computed get taskingPlanDetails() {
    return this.areTaskingDatesSame ?
      [first(this.planScores.taskPlan.tasking_plans)] :
      sortBy(this.planScores.taskPlan.tasking_plans, tp => tp.period.name);
  }

  @computed get stats() {
    return this.planScores.taskPlan.analytics.stats;
  }

  @computed get progressStatsForPeriod() {
    // period stats will be undefined if no-ones worked the assignment in the period yet
    const periodStats = this.stats.find(s => s.period_id == this.selectedPeriod.id);
    const { total_count = 0, complete_count = 0, partially_complete_count = 0 } = periodStats || { };
    const notStartedCount = total_count - (complete_count + partially_complete_count);

    const items = [
      { label: 'Completed',
        value: complete_count,
        percent: (complete_count / total_count),
      },
      { label: 'In progress',
        value: partially_complete_count,
        percent: (partially_complete_count / total_count),
      },
      { label: 'Not started',
        value: notStartedCount,
        percent: (notStartedCount / total_count),
      },
    ];

    return items;
  }

  @computed get canDisplayGradingBlock() {
    return Boolean(this.planScores.isHomework && this.scores);
  }

  @computed get isReadingOrHomework() {
    return Boolean(['reading', 'homework'].includes(this.planScores.type));
  }

  @computed get hasUnPublishedScores() {
    return Boolean(this.scores.hasUnPublishedScores);
  }

  @computed get gradeableQuestionCount() {
    return sumBy(this.scores.question_headings.map(qh => qh.gradedStats), 'remaining');
  }

  @computed get hasGradeableAnswers() {
    return Boolean(this.gradeableQuestionCount > 0);
  }

}
<|endoftext|>


<commit_before>import React, {PropTypes} from 'react'
import classnames from 'classnames'

import LayoutRenderer from 'shared/components/LayoutRenderer'
import Dropdown from 'shared/components/Dropdown'

const Dashboard = ({
  source,
  timeRange,
  dashboard,
  onAddCell,
  onEditCell,
  autoRefresh,
  onRenameCell,
  onUpdateCell,
  onDeleteCell,
  onPositionChange,
  inPresentationMode,
  onOpenTemplateManager,
  onSummonOverlayTechnologies,
  onSelectTV,
}) => {
  if (dashboard.id === 0) {
    return null
  }

  const cells = dashboard.cells.map((cell) => {
    const dashboardCell = {...cell}
    dashboardCell.queries = dashboardCell.queries.map(({label, query, queryConfig, db}) =>
      ({
        label,
        query,
        queryConfig,
        db,
        database: db,
        text: query,
      })
    )
    return dashboardCell
  })

  return (

        Template Variables
        {
          dashboard.templates.map(({id, values}) => {
            let items
            if (values === null) {
              items = [{text: 'Loading...'}]
            } else {
              items = values.map(value => ({text: value}))
            }
            return (
              <Dropdown
                key={id}
                items={items}
                selected={items[0].text}
                onChoose={(item) => onSelectTV(id, item.text)}
              />
            )
          })
        }
        <button className="btn btn-primary btn-sm" onClick={onOpenTemplateManager}>Manage</button>

      {cells.length ?
        <LayoutRenderer
          timeRange={timeRange}
          cells={cells}
          autoRefresh={autoRefresh}
          source={source.links.proxy}
          onPositionChange={onPositionChange}
          onEditCell={onEditCell}
          onRenameCell={onRenameCell}
          onUpdateCell={onUpdateCell}
          onDeleteCell={onDeleteCell}
          onSummonOverlayTechnologies={onSummonOverlayTechnologies}
        /> :

This Dashboard has no Graphs

          <button
            className="btn btn-primary btn-m"
            onClick={onAddCell}
          >
            Add Graph
          </button>

      }

  )
}

const {
  bool,
  func,
  shape,
  string,
  number,
} = PropTypes

Dashboard.propTypes = {
  dashboard: shape({}).isRequired,
  inPresentationMode: bool,
  onAddCell: func,
  onPositionChange: func,
  onEditCell: func,
  onRenameCell: func,
  onUpdateCell: func,
  onDeleteCell: func,
  onSummonOverlayTechnologies: func,
  source: shape({
    links: shape({
      proxy: string,
    }).isRequired,
  }).isRequired,
  autoRefresh: number.isRequired,
  timeRange: shape({}).isRequired,
  onOpenTemplateManager: func.isRequired,
  onSelectTV: func.isRequired,
}

export default Dashboard
<commit_msg>Display selected value; disallow selection while loading<commit_after>import React, {PropTypes} from 'react'
import classnames from 'classnames'

import LayoutRenderer from 'shared/components/LayoutRenderer'
import Dropdown from 'shared/components/Dropdown'

const Dashboard = ({
  source,
  timeRange,
  dashboard,
  onAddCell,
  onEditCell,
  autoRefresh,
  onRenameCell,
  onUpdateCell,
  onDeleteCell,
  onPositionChange,
  inPresentationMode,
  onOpenTemplateManager,
  onSummonOverlayTechnologies,
  onSelectTV,
}) => {
  if (dashboard.id === 0) {
    return null
  }

  const cells = dashboard.cells.map((cell) => {
    const dashboardCell = {...cell}
    dashboardCell.queries = dashboardCell.queries.map(({label, query, queryConfig, db}) =>
      ({
        label,
        query,
        queryConfig,
        db,
        database: db,
        text: query,
      })
    )
    return dashboardCell
  })

  return (

        Template Variables
        {
          dashboard.templates.map(({id, values, selected}) => {
            const items = values ? values.map(value => ({text: value})) : []
            return (
              <Dropdown
                key={id}
                items={items}
                selected={selected || "Loading..."}
                onChoose={(item) => onSelectTV(id, item.text)}
              />
            )
          })
        }
        <button className="btn btn-primary btn-sm" onClick={onOpenTemplateManager}>Manage</button>

      {cells.length ?
        <LayoutRenderer
          timeRange={timeRange}
          cells={cells}
          autoRefresh={autoRefresh}
          source={source.links.proxy}
          onPositionChange={onPositionChange}
          onEditCell={onEditCell}
          onRenameCell={onRenameCell}
          onUpdateCell={onUpdateCell}
          onDeleteCell={onDeleteCell}
          onSummonOverlayTechnologies={onSummonOverlayTechnologies}
        /> :

This Dashboard has no Graphs

          <button
            className="btn btn-primary btn-m"
            onClick={onAddCell}
          >
            Add Graph
          </button>

      }

  )
}

const {
  bool,
  func,
  shape,
  string,
  number,
} = PropTypes

Dashboard.propTypes = {
  dashboard: shape({}).isRequired,
  inPresentationMode: bool,
  onAddCell: func,
  onPositionChange: func,
  onEditCell: func,
  onRenameCell: func,
  onUpdateCell: func,
  onDeleteCell: func,
  onSummonOverlayTechnologies: func,
  source: shape({
    links: shape({
      proxy: string,
    }).isRequired,
  }).isRequired,
  autoRefresh: number.isRequired,
  timeRange: shape({}).isRequired,
  onOpenTemplateManager: func.isRequired,
  onSelectTV: func.isRequired,
}

export default Dashboard
<|endoftext|>


<commit_before>import React, {PropTypes} from 'react';
import AutoRefresh from 'shared/components/AutoRefresh';
import LineGraph from 'shared/components/LineGraph';
import ReactGridLayout from 'react-grid-layout';
import _ from 'lodash';

const RefreshingLineGraph = AutoRefresh(LineGraph);

export const LayoutRenderer = React.createClass({
  propTypes: {
    timeRange: PropTypes.string.isRequired,
    cells: PropTypes.arrayOf(
      PropTypes.shape({
        queries: PropTypes.arrayOf(
          PropTypes.shape({
            rp: PropTypes.string.isRequired,
            text: PropTypes.string.isRequired,
            database: PropTypes.string.isRequired,
            groupbys: PropTypes.arrayOf(PropTypes.string),
            wheres: PropTypes.arrayOf(PropTypes.string),
          }).isRequired
        ).isRequired,
        x: PropTypes.number.isRequired,
        y: PropTypes.number.isRequired,
        w: PropTypes.number.isRequired,
        h: PropTypes.number.isRequired,
        i: PropTypes.string.isRequired,
        name: PropTypes.string.isRequired,
      }).isRequired
    ),
    autoRefreshMs: PropTypes.number.isRequired,
    host: PropTypes.string.isRequired,
    source: PropTypes.string,
  },

  getInitialState() {
    return ({
      layout: _.without(this.props.cells, ['queries']),
    });
  },

  generateGraphs() {
    const {timeRange, host, autoRefreshMs, source} = this.props;

    return this.props.cells.map((cell) => {
      const qs = cell.queries.map((q) => {
        _.merge(q, {host: source});
        q.text += ` where \"host\" = '${host}' and time > ${timeRange}`;
        if (q.wheres && q.wheres.length > 0) {
          q.text += ` and ${q.wheres.join(' and ')}`;
        }
        if (q.groupbys && q.groupbys.length > 0) {
          q.text += ` group by ${q.groupbys.join(',')}`;
        }
        return q;
      });
      return (

{cell.name}

            <RefreshingLineGraph
              queries={qs}
              autoRefresh={autoRefreshMs}
            />

      );
    });
  },

  render() {
    return (
      <ReactGridLayout layout={this.state.layout} isDraggable={false} isResizable={false} cols={12} rowHeight={90} width={1200}>
        {this.generateGraphs()}
      </ReactGridLayout>
    );
  },
});

export default LayoutRenderer;
<commit_msg>Create new queries rather than reusing old ones<commit_after>import React, {PropTypes} from 'react';
import AutoRefresh from 'shared/components/AutoRefresh';
import LineGraph from 'shared/components/LineGraph';
import ReactGridLayout from 'react-grid-layout';
import _ from 'lodash';

const RefreshingLineGraph = AutoRefresh(LineGraph);

export const LayoutRenderer = React.createClass({
  propTypes: {
    timeRange: PropTypes.string.isRequired,
    cells: PropTypes.arrayOf(
      PropTypes.shape({
        queries: PropTypes.arrayOf(
          PropTypes.shape({
            rp: PropTypes.string.isRequired,
            text: PropTypes.string.isRequired,
            database: PropTypes.string.isRequired,
            groupbys: PropTypes.arrayOf(PropTypes.string),
            wheres: PropTypes.arrayOf(PropTypes.string),
          }).isRequired
        ).isRequired,
        x: PropTypes.number.isRequired,
        y: PropTypes.number.isRequired,
        w: PropTypes.number.isRequired,
        h: PropTypes.number.isRequired,
        i: PropTypes.string.isRequired,
        name: PropTypes.string.isRequired,
      }).isRequired
    ),
    autoRefreshMs: PropTypes.number.isRequired,
    host: PropTypes.string.isRequired,
    source: PropTypes.string,
  },

  getInitialState() {
    return ({
      layout: _.without(this.props.cells, ['queries']),
    });
  },

  generateGraphs() {
    const {timeRange, host, autoRefreshMs, source} = this.props;

    return this.props.cells.map((cell) => {
      const qs = cell.queries.map((q) => {
        let text = q.text;
        text += ` where \"host\" = '${host}' and time > ${timeRange}`;
        if (q.wheres && q.wheres.length > 0) {
          text += ` and ${q.wheres.join(' and ')}`;
        }
        if (q.groupbys && q.groupbys.length > 0) {
          text += ` group by ${q.groupbys.join(',')}`;
        }
        return {
          host: source,
          text,
        };
      });
      return (

{cell.name}

            <RefreshingLineGraph
              queries={qs}
              autoRefresh={autoRefreshMs}
            />

      );
    });
  },

  render() {
    return (
      <ReactGridLayout layout={this.state.layout} isDraggable={false} isResizable={false} cols={12} rowHeight={90} width={1200}>
        {this.generateGraphs()}
      </ReactGridLayout>
    );
  },
});

export default LayoutRenderer;
<|endoftext|>


<commit_before>const Disposable = require('promise-toolbox/Disposable')
const ignoreErrors = require('promise-toolbox/ignoreErrors')
const { compose } = require('@vates/compose')
const { createDebounceResource } = require('@vates/disposable/debounceResource')
const { deduped } = require('@vates/disposable/deduped')
const { getHandler } = require('@xen-orchestra/fs')
const { parseDuration } = require('@vates/parse-duration')
const { Xapi } = require('@xen-orchestra/xapi')

const { Backup } = require('./Backup')
const { RemoteAdapter } = require('./RemoteAdapter')
const { Task } = require('./Task')

class BackupWorker {
  #config
  #job
  #recordToXapi
  #remoteOptions
  #remotes
  #schedule
  #xapiOptions
  #xapis

  constructor({ config, job, recordToXapi, remoteOptions, remotes, resourceCacheDelay, schedule, xapiOptions, xapis }) {
    this.#config = config
    this.#job = job
    this.#recordToXapi = recordToXapi
    this.#remoteOptions = remoteOptions
    this.#remotes = remotes
    this.#schedule = schedule
    this.#xapiOptions = xapiOptions
    this.#xapis = xapis

    const debounceResource = createDebounceResource()
    debounceResource.defaultDelay = parseDuration(resourceCacheDelay)
    this.debounceResource = debounceResource
  }

  run() {
    return new Backup({
      config: this.#config,
      getAdapter: remoteId => this.getAdapter(this.#remotes[remoteId]),
      getConnectedRecord: Disposable.factory(async function* getConnectedRecord(type, uuid) {
        const xapiId = this.#recordToXapi[uuid]
        if (xapiId === undefined) {
          throw new Error('no XAPI associated to ' + uuid)
        }

        const xapi = yield this.getXapi(this.#xapis[xapiId])
        return xapi.getRecordByUuid(type, uuid)
      }).bind(this),
      job: this.#job,
      schedule: this.#schedule,
    }).run()
  }

  getAdapter = Disposable.factory(this.getAdapter)
  getAdapter = deduped(this.getAdapter, remote => [remote.url])
  getAdapter = compose(this.getAdapter, function (resource) {
    return this.debounceResource(resource)
  })
  async *getAdapter(remote) {
    const handler = getHandler(remote, this.#remoteOptions)
    await handler.sync()
    try {
      yield new RemoteAdapter(handler, {
        debounceResource: this.debounceResource,
        dirMode: this.#config.dirMode,
      })
    } finally {
      await handler.forget()
    }
  }

  getXapi = Disposable.factory(this.getXapi)
  getXapi = deduped(this.getXapi, ({ url }) => [url])
  getXapi = compose(this.getXapi, function (resource) {
    return this.debounceResource(resource)
  })
  async *getXapi({ credentials: { username: user, password }, ...opts }) {
    const xapi = new Xapi({
      ...this.#xapiOptions,
      ...opts,
      auth: {
        user,
        password,
      },
    })

    await xapi.connect()
    try {
      await xapi.objectsFetched

      yield xapi
    } finally {
      await xapi.disconnect()
    }
  }
}

// Received message:
//
// Message {
//   action: 'run'
//   data: object
//   runWithLogs: boolean
// }
//
// Sent message:
//
// Message {
//   type: 'log' | 'result'
//   data?: object
//   status?: 'success' | 'failure'
//   result?: any
// }
process.on('message', async message => {
  if (message.action === 'run') {
    const backupWorker = new BackupWorker(message.data)
    try {
      const result = message.runWithLogs
        ? await Task.run(
            {
              name: 'backup run',
              onLog: data =>
                process.send({
                  data,
                  type: 'log',
                }),
            },
            () => backupWorker.run()
          )
        : await backupWorker.run()

      process.send({
        type: 'result',
        result,
        status: 'success',
      })
    } catch (error) {
      process.send({
        type: 'result',
        result: error,
        status: 'failure',
      })
    } finally {
      await ignoreErrors.call(backupWorker.debounceResource.flushAll())
      process.disconnect()
    }
  }
})
<commit_msg>feat(backups/_backupWorker): log global errors<commit_after>require('@xen-orchestra/log/configure').catchGlobalErrors(
  require('@xen-orchestra/log').createLogger('xo:backups:worker')
)

const Disposable = require('promise-toolbox/Disposable')
const ignoreErrors = require('promise-toolbox/ignoreErrors')
const { compose } = require('@vates/compose')
const { createDebounceResource } = require('@vates/disposable/debounceResource')
const { deduped } = require('@vates/disposable/deduped')
const { getHandler } = require('@xen-orchestra/fs')
const { parseDuration } = require('@vates/parse-duration')
const { Xapi } = require('@xen-orchestra/xapi')

const { Backup } = require('./Backup')
const { RemoteAdapter } = require('./RemoteAdapter')
const { Task } = require('./Task')

class BackupWorker {
  #config
  #job
  #recordToXapi
  #remoteOptions
  #remotes
  #schedule
  #xapiOptions
  #xapis

  constructor({ config, job, recordToXapi, remoteOptions, remotes, resourceCacheDelay, schedule, xapiOptions, xapis }) {
    this.#config = config
    this.#job = job
    this.#recordToXapi = recordToXapi
    this.#remoteOptions = remoteOptions
    this.#remotes = remotes
    this.#schedule = schedule
    this.#xapiOptions = xapiOptions
    this.#xapis = xapis

    const debounceResource = createDebounceResource()
    debounceResource.defaultDelay = parseDuration(resourceCacheDelay)
    this.debounceResource = debounceResource
  }

  run() {
    return new Backup({
      config: this.#config,
      getAdapter: remoteId => this.getAdapter(this.#remotes[remoteId]),
      getConnectedRecord: Disposable.factory(async function* getConnectedRecord(type, uuid) {
        const xapiId = this.#recordToXapi[uuid]
        if (xapiId === undefined) {
          throw new Error('no XAPI associated to ' + uuid)
        }

        const xapi = yield this.getXapi(this.#xapis[xapiId])
        return xapi.getRecordByUuid(type, uuid)
      }).bind(this),
      job: this.#job,
      schedule: this.#schedule,
    }).run()
  }

  getAdapter = Disposable.factory(this.getAdapter)
  getAdapter = deduped(this.getAdapter, remote => [remote.url])
  getAdapter = compose(this.getAdapter, function (resource) {
    return this.debounceResource(resource)
  })
  async *getAdapter(remote) {
    const handler = getHandler(remote, this.#remoteOptions)
    await handler.sync()
    try {
      yield new RemoteAdapter(handler, {
        debounceResource: this.debounceResource,
        dirMode: this.#config.dirMode,
      })
    } finally {
      await handler.forget()
    }
  }

  getXapi = Disposable.factory(this.getXapi)
  getXapi = deduped(this.getXapi, ({ url }) => [url])
  getXapi = compose(this.getXapi, function (resource) {
    return this.debounceResource(resource)
  })
  async *getXapi({ credentials: { username: user, password }, ...opts }) {
    const xapi = new Xapi({
      ...this.#xapiOptions,
      ...opts,
      auth: {
        user,
        password,
      },
    })

    await xapi.connect()
    try {
      await xapi.objectsFetched

      yield xapi
    } finally {
      await xapi.disconnect()
    }
  }
}

// Received message:
//
// Message {
//   action: 'run'
//   data: object
//   runWithLogs: boolean
// }
//
// Sent message:
//
// Message {
//   type: 'log' | 'result'
//   data?: object
//   status?: 'success' | 'failure'
//   result?: any
// }
process.on('message', async message => {
  if (message.action === 'run') {
    const backupWorker = new BackupWorker(message.data)
    try {
      const result = message.runWithLogs
        ? await Task.run(
            {
              name: 'backup run',
              onLog: data =>
                process.send({
                  data,
                  type: 'log',
                }),
            },
            () => backupWorker.run()
          )
        : await backupWorker.run()

      process.send({
        type: 'result',
        result,
        status: 'success',
      })
    } catch (error) {
      process.send({
        type: 'result',
        result: error,
        status: 'failure',
      })
    } finally {
      await ignoreErrors.call(backupWorker.debounceResource.flushAll())
      process.disconnect()
    }
  }
})
<|endoftext|>


<commit_before>function onError(error) {//log errors
  console.log(`Error: ${error}`);
}

function escapeHTML(str) {//"This method is a last resort which should be used only as a temporary measure in established code bases. It is safe, though inefficient [..]."
                          //See: https://developer.mozilla.org/en-US/Add-ons/Overlay_Extensions/XUL_School/DOM_Building_and_HTML_Insertion
     return str.replace(/[&"'<>]/g, (m) => escapeHTML.replacements[m]);
   }
   escapeHTML.replacements = {
     "&": "&",
     '"': """,
     "'": "'",
     "<": "<",
     ">": ">"
   };

function onGot(item) {
  var pages = item.pages;
  if(pages.length == 0){//remove the loader element from the HTML if there are no saved pages
    $("#overlay").detach();
     $("#overlay-alert").fadeIn(1500);//fade in the alert "You currently have no history."
  }
  else{
    for (i in pages) {//iterate every page and add it to the HTML
      $("#items").prepend("

" + escapeHTML(pages[i].title) + "

");
    }
    $("#overlay").detach();//remove the loader element once the iteration is finished
  }
}

$(document).ready(function() {
  let pages = browser.storage.local.get("pages");//get the JSON object
  pages.then(onGot, onError);//promise
});
<commit_msg>Fixed a security problem.<commit_after>function onError(error) { //log errors
  console.log(`Error: ${error}`);
}

function onGot(item) {
  var pages = item.pages;
  if (pages.length == 0) { //remove the loader element from the HTML if there are no saved pages
    $("#overlay").detach();
    $("#overlay-alert").fadeIn(1500); //fade in the alert "You currently have no history."
  } else {
    for (i in pages) { //iterate every page and add it to the HTML
      if (pages[i].url.startsWith('http') && pages[i].image.startsWith('data:image/jpeg;base64,')) { // making sure the url is a url and the image is a data uri graphic
        let div = document.createElement('div');
        let div2 = div.cloneNode(false); // making a clone

        div.title = pages[i].hostname;
        div.className = 'page';

        let a = document.createElement('a');
        a.href = pages[i].url;

        let img = document.createElement('img');
        img.src = pages[i].image;

        div2.className = 'desc';
        div2.setAttribute('style', 'line-height:30px;');
        div2.textContent = pages[i].title;

        a.appendChild(img);
        a.appendChild(div2);
        div.appendChild(a);

        $("#items").prepend(div);//adding the div to the HTML
      }
    }
    $("#overlay").detach(); //remove the loader element once the iteration is finished
  }
}

$(document).ready(function() {
  let pages = browser.storage.local.get("pages"); //get the JSON object
  pages.then(onGot, onError); //promise
});
<|endoftext|>


<commit_before>
var Plottables = {};

function loadScript(url, callback) {
  var element = document.createElement("script");
  element.type = "text/javascript";
  element.src = url;
  element.onload = callback;
  document.head.appendChild(element);
}

function loadPlottable(branchName, callback) {
  var url;
  if (branchName != null) {
    url = "https://rawgithub.com/palantir/plottable/" + branchName + "/plottable.js";
  } else {
    branchName = "#local";
    url = "../plottable.js"; //load local version
  }
  var inner = function() {
    console.log("loaded Plottable:" + branchName);
    Plottables[branchName] = Plottable;
    Plottable = null;
    callback();
  }
  loadScript(url, inner);
}

var quicktests = []
function loadQuicktests(qts, callback) {
  var nLoaded = 0;

  var inner = function() {
    if (++nLoaded === qts.length) callback();
  }

  qts.forEach(function(q) {
    loadScript("quicktests/" + q + ".js", inner);
  });
}

function loadAllQuicktests(callback) {
  loadScript("quicktests/list_of_quicktests.js", function() {
    console.log("about to load quicktests", callback);
    loadQuicktests(list_of_quicktests, callback);
  });
}

function loadQuickTestsAndPlottables(otherBranch, callback) {
  var loaded = 0;
  var inner = function() {
    if (++loaded === 3) callback();
  }

  loadPlottable("master", inner);
  loadPlottable(otherBranch, inner);
  console.log("about to load all quicktests", inner);
  loadAllQuicktests(inner);
}

var data1 = makeRandomData(50);
var data2 = makeRandomData(50);

function loadSingleQuicktest(container, quickTest, Plottable) {
  container.append("p").text(quickTest.quicktestName);
  var svg = container.append("svg").attr("height", 500);
  quickTest(svg, _.cloneDeep([data1, data2]), Plottable);
}

function runQuicktest(tableSelection, quickTest, Plottable1, Plottable2) {
  var tr = tableSelection.append("tr");
  loadSingleQuicktest(tr.append("td"), quickTest, Plottable1);
  tr.append("td");
  loadSingleQuicktest(tr.append("td"), quickTest, Plottable2);
}

function main() {
  var table = d3.select("table");
  quicktests.forEach(function(q) {
    runQuicktest(table, q, Plottables["master"], Plottables["master"]);
  });
}

window.onload = function() {loadQuickTestsAndPlottables("master", main)};

var button = document.getElementById('button');
button.onclick = function () {
  var fb = $('#featureBranch').val();
  loadQuickTestsAndPlottables("master", fb);
}
<commit_msg>Update quicktest.js<commit_after>
var Plottables = {};

function loadScript(url, callback) {
  var element = document.createElement("script");
  element.type = "text/javascript";
  element.src = url;
  element.onload = callback;
  document.head.appendChild(element);
}

function loadPlottable(branchName, callback) {
  var url;
  if (branchName != null) {
    url = "https://rawgithub.com/palantir/plottable/" + branchName + "/plottable.js";
  } else {
    branchName = "#local";
    url = "../plottable.js"; //load local version
  }
  var inner = function() {
    console.log("loaded Plottable:" + branchName);
    Plottables[branchName] = Plottable;
    Plottable = null;
    callback();
  }
  loadScript(url, inner);
}

var quicktests = []
function loadQuicktests(qts, callback) {
  var nLoaded = 0;

  var inner = function() {
    if (++nLoaded === qts.length) callback();
  }

  qts.forEach(function(q) {
    loadScript("quicktests/" + q + ".js", inner);
  });
}

function loadAllQuicktests(callback) {
  loadScript("quicktests/list_of_quicktests.js", function() {
    console.log("about to load quicktests", callback);
    loadQuicktests(list_of_quicktests, callback);
  });
}

function loadQuickTestsAndPlottables(otherBranch, callback) {
  var loaded = 0;
  var inner = function() {
    if (++loaded === 3) callback();
  }

  loadPlottable("master", inner);
  loadPlottable(otherBranch, inner);
  console.log("about to load all quicktests", inner);
  loadAllQuicktests(inner);
}

var data1 = makeRandomData(50);
var data2 = makeRandomData(50);

function loadSingleQuicktest(container, quickTest, Plottable) {
  container.append("p").text(quickTest.quicktestName);
  var svg = container.append("svg").attr("height", 500);
  quickTest(svg, _.cloneDeep([data1, data2]), Plottable);
}

function runQuicktest(tableSelection, quickTest, Plottable1, Plottable2) {
  var tr = tableSelection.append("tr");
  loadSingleQuicktest(tr.append("td"), quickTest, Plottable1);
  tr.append("td");
  loadSingleQuicktest(tr.append("td"), quickTest, Plottable2);
}

function main() {
  var table = d3.select("table");
  quicktests.forEach(function(q) {
    runQuicktest(table, q, Plottables["master"], Plottables["master"]);
  });
}

window.onload = function() {loadQuickTestsAndPlottables("master", main)};

var button = document.getElementById('button');
button.onclick = function () {
  var fb = $('#featureBranch').val();
  console.log(fb);
  loadQuickTestsAndPlottables("master", fb);
}
<|endoftext|>