<commit_before>// We want to remember how far we were scrolled on each 'tab'.
// To do so, we need to save away the old position of the
// scrollbar when we switch to a new tab (and restore it
// when we switch back.)
var scroll_positions = {};

function register_onclick(message_row, message_id) {
    message_row.find(".messagebox").click(function (e) {
        if (!(clicking && mouse_moved)) {
            // Was a click (not a click-and-drag).
            select_message_by_id(message_id);
            respond_to_message();
        }
        mouse_moved = false;
        clicking = false;
    });
}

function focus_on(field_id) {
    // Call after autocompleting on a field, to advance the focus to
    // the next input field.

    // Bootstrap's typeahead does not expose a callback for when an
    // autocomplete selection has been made, so we have to do this
    // manually.
    $("#" + field_id).focus();
}

/* 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. */

function hide_email() {
    $('.sender_email').addClass('invisible');
}

function show_email(message_id) {
    hide_email();
    rows.get(message_id).find('.sender_email').removeClass('invisible');
}

function report_message(response, status_box, cls) {
    if (cls === undefined)
        cls = 'alert';

    status_box.removeClass(status_classes).addClass(cls)
              .text(response).stop(true).fadeTo(0, 1);
    status_box.show();
}

function report_error(response, xhr, status_box) {
    if (xhr.status.toString().charAt(0) === "4") {
        // Only display the error response for 4XX, where we've crafted
        // a nice response.
        response += ": " + $.parseJSON(xhr.responseText).msg;
    }

    report_message(response, status_box, 'alert-error');
}

function report_success(response, status_box) {
    report_message(response, status_box, 'alert-success');
}

var clicking = false;
var mouse_moved = false;

function mousedown() {
    mouse_moved = false;
    clicking = true;
}

function mousemove() {
    if (clicking) {
        mouse_moved = true;
    }
}

function resizehandler(e) {
    var sidebar = $("#sidebar");
    var sidebar_nav = $(".sidebar-nav");
    var composebox = $("#compose");
    var top_statusbar = $("#top_statusbar");
    if (viewport.width() <= 767) {
        sidebar.removeClass('nav-stacked');

        var space_taken_up_by_navbar = sidebar_nav.outerHeight(true);

        // .visible-phone only, so doesn't need undoing
        $("#nav_whitespace").height(space_taken_up_by_navbar);

        top_statusbar.css('top', space_taken_up_by_navbar);

        var message_list_width = $("#main_div").outerWidth();
        composebox.width(message_list_width);
        top_statusbar.width(message_list_width);
        sidebar_nav.width(message_list_width);
    } else {
        sidebar.addClass('nav-stacked');
        top_statusbar.css('top', 0);
        top_statusbar.width('');
        composebox.width('');
        sidebar_nav.width('');
    }

    // This function might run onReady (if we're in a narrow window),
    // but before we've loaded in the messages; in that case, don't
    // try to scroll to one.
    if (selected_message_id !== -1) {
        scroll_to_selected();
    }
}

var old_label;
var is_floating_recipient_bar_showing = false;
function replace_floating_recipient_bar(desired_label) {
    if (desired_label !== old_label) {
        if (desired_label.children(".message_header_stream").length !== 0) {
            $("#current_label_stream td:last").replaceWith(
                desired_label.children(".message_header_stream.right_part").clone());
            $("#current_label_huddle").css('display', 'none');
            $("#current_label_stream").css('display', 'table-row');
        } else {
            $("#current_label_huddle td:last").replaceWith(
                desired_label.children(".message_header_huddle.right_part").clone());
            $("#current_label_stream").css('display', 'none');
            $("#current_label_huddle").css('display', 'table-row');
        }
        old_label = desired_label;
    }
    if (!is_floating_recipient_bar_showing) {
        $(".floating_recipient_bar").css('visibility', 'visible');
        is_floating_recipient_bar_showing = true;
    }
}

function hide_floating_recipient_bar() {
    if (is_floating_recipient_bar_showing) {
        $(".floating_recipient_bar").css('visibility', 'hidden');
        is_floating_recipient_bar_showing = false;
    }
}

function update_floating_recipient_bar() {
    var top_statusbar = $("#top_statusbar");
    var top_statusbar_top = top_statusbar.offset().top;
    var top_statusbar_bottom = top_statusbar_top + top_statusbar.outerHeight();

    // Find the last message where the top of the recipient
    // row is at least partially occluded by our box.
    // Start with the pointer's current location.
    var candidate = selected_message;
    if (candidate === undefined) {
        return;
    }
    while (true) {
        candidate = candidate.prev();
        if (candidate.length === 0) {
            // We're at the top of the page and no labels are above us.
            hide_floating_recipient_bar();
            return;
        }
        if (candidate.is(".focused_table .recipient_row")) {
            if (candidate.offset().top < top_statusbar_bottom) {
                break;
            }
        }
    }
    var current_label = candidate;

    // We now know what the floating stream/subject bar should say.
    // Do we show it?

    // Hide if the bottom of our floating stream/subject label is not
    // lower than the bottom of current_label (since that means we're
    // covering up a label that already exists).
    if (top_statusbar_bottom <=
        (current_label.offset().top + current_label.outerHeight())) {
        hide_floating_recipient_bar();
        return;
    }

    // Hide if our bottom is in our bookend (or one bookend-height
    // above it). This means we're not showing any useful part of the
    // message above us, so why bother showing the label?)
    var current_bookend = current_label.nextUntil(".bookend_tr")
                                       .andSelf()
                                       .next(".bookend_tr:first");
    // (The last message currently doesn't have a bookend, which is why this might be 0).
    if (current_bookend.length > 0) {
        if (top_statusbar_bottom >
            (current_bookend.offset().top - current_bookend.outerHeight())) {
            hide_floating_recipient_bar();
            return;
        }
    }

    // If we're narrowed to a huddle or a subject, the floating
    // recipient bar would be identical to the narrowing header, so
    // don't display it.
    if (narrow.narrowing_type() === "huddle" || narrow.narrowing_type() === "subject") {
        hide_floating_recipient_bar();
        return;
    }

    replace_floating_recipient_bar(current_label);
}
function hack_for_floating_recipient_bar() {
    // So, as of this writing, Firefox respects visibility: collapse,
    // but WebKit does not (at least, my Chrome doesn't.)  Instead it
    // renders it basically as visibility: hidden, which leaves a
    // slight gap that our messages peek through as they scroll
    // by. This hack fixes this by programmatically measuring how big
    // the gap is, and then moving our table up to compensate.
    var gap = $("#floating_recipient_layout_row").outerHeight(true);
    var floating_recipient = $(".floating_recipient");
    var offset = floating_recipient.offset();
    offset.top = offset.top - gap;
    floating_recipient.offset(offset);
}

function show_api_key_box() {
    $("#get_api_key_box").show();
    $("#api_key_button_box").hide();
}

var userinfo_currently_popped;
function userinfo_popover(event, element, id) {
    event.stopPropagation();
    select_message_by_id(id);
    var elt = $(element);
    if (elt.data('popover') === undefined) {
        // One popover at a time.
        if (userinfo_currently_popped) {
            userinfo_currently_popped.popover("destroy");
            userinfo_currently_popped = undefined;
        }
        var message = message_dict[id];
        elt.popover({placement: "bottom",
                     title: templates.userinfo_popover_title(message),
                     content: templates.userinfo_popover_content(message),
                     trigger: "manual"
                    });
        elt.popover("show");
        userinfo_currently_popped = elt;
    } else {
        elt.popover("destroy");
        userinfo_currently_popped = undefined;
    }
}

function safari_composebox_hack(forwards) {
    // OK, so the situation here is basically a lot of work so that
    // Tab-Enter is a valid hotkey for sending a message in Safari.
    // By default, Safari uses Tab only to cycle through textboxes,
    // basically. Even if the tabindex is set on it, a button (like
    // our submit button) will not get focus.

    // HOWEVER, if you set the tabindex on a div, Safari/WebKit will
    // respect that, and will focus it.  So we make a div right before
    // the Send button, which, when selected, focuses the send button.
    // Then, we make another div right after it, that, when selected,
    // focuses back the composebox (so as not to break Shift-Tab in
    // these browsers).

    // This behavior is configurable in Safari, but is not on by
    // default.  (It is on by default in Chrome.)
    if (forwards) {
        $('#compose-send-button').focus();
    } else {
        $('#new_message_content').focus();
    }
}

$(function () {
    // NB: This just binds to current elements, and won't bind to elements
    // created after ready() is called.

    $('#message-type-tabs a[href="#stream-message"]').on('shown', function (e) {
        compose.set_message_type('stream');
    });
    $('#message-type-tabs a[href="#personal-message"]').on('shown', function (e) {
        compose.set_message_type('huddle');
    });

    // Prepare the click handler for subbing to a new stream to which
    // you have composed a message.
    $('#create-it').click(function () {
        subs.subscribe_for_send(compose.stream_name(), $('#stream-dne'));
    });

    // Prepare the click handler for subbing to an existing stream.
    $('#sub-it').click(function () {
        subs.subscribe_for_send(compose.stream_name(), $('#stream-nosub'));
    });

    var throttled_scrollhandler = $.throttle(50, function(e) {
        if ($('#home').hasClass('active')) {
            keep_pointer_in_view();
            update_floating_recipient_bar();
        }
    });
    $(window).scroll(throttled_scrollhandler);

    var throttled_mousewheelhandler = $.throttle(50, 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.
        move_pointer_at_page_top_and_bottom(delta);
    });
    $(window).mousewheel(throttled_mousewheelhandler);

    var throttled_resizehandler = $.throttle(50, resizehandler);
    $(window).resize(throttled_resizehandler);

    function clear_password_change() {
        // Clear the password boxes so that passwords don't linger in the DOM
        // for an XSS attacker to find.
        $('#old_password, #new_password, #confirm_password').val('');
    }

    $('#sidebar a[data-toggle="pill"]').on('show', function (e) {
        // Save the position of our old tab away, before we switch
        var old_tab = $(e.relatedTarget).attr('href');
        scroll_positions[old_tab] = viewport.scrollTop();
    });
    $('#sidebar a[data-toggle="pill"]').on('shown', function (e) {
        // Right after we show the new tab, restore its old scroll position
        var target_tab = $(e.target).attr('href');
        if (scroll_positions.hasOwnProperty(target_tab)) {
            viewport.scrollTop(scroll_positions[target_tab]);
        } else {
            viewport.scrollTop(0);
        }

        // Hide all our error messages when switching tabs
        $('.alert-error').hide();
        $('.alert-success').hide();
        $('.alert-info').hide();
        $('.alert').hide();

        $("#api_key_value").text("");
        $("#get_api_key_box").hide();
        $("#show_api_key_box").hide();
        $("#api_key_button_box").show();

        clear_password_change();

        // Set the URL bar title to show the sub-page you're currently on.
        var browser_url = target_tab;
        if (browser_url === "#home") {
            browser_url = "#";
        }
        window.history.pushState("object or string", "Title", browser_url);
    });

    $('.button-slide').click(function () {
        compose.show('stream', $("#stream"));
    });

    $('#sidebar a[href="#subscriptions"]').click(subs.fetch);

    var settings_status = $('#settings-status');
    $("#settings-change-box form").ajaxForm({
        dataType: 'json', // This seems to be ignored. We still get back an xhr.
        success: function (resp, statusText, xhr, form) {
            var message = "Updated settings!";
            var result = $.parseJSON(xhr.responseText);
            if ((result.full_name !== undefined) || (result.short_name !== undefined)) {
                message = "Updated settings!  You will need to reload the page for your changes to take effect.";
            }
            settings_status.removeClass(status_classes)
                .addClass('alert-success')
                .text(message).stop(true).fadeTo(0,1);
            // TODO: In theory we should auto-reload or something if
            // you changed the email address or other fields that show
            // up on all screens
        },
        error: function (xhr, error_type, xhn) {
            var response = "Error changing settings";
            if (xhr.status.toString().charAt(0) === "4") {
                // Only display the error response for 4XX, where we've crafted
                // a nice response.
                response += ": " + $.parseJSON(xhr.responseText).msg;
            }
            settings_status.removeClass(status_classes)
                .addClass('alert-error')
                .text(response).stop(true).fadeTo(0,1);
        },
        complete: function (xhr, statusText) {
            // Whether successful or not, clear the password boxes.
            // TODO: Clear these earlier, while the request is still pending.
            clear_password_change();
        }
    });

    $("#get_api_key_box").hide();
    $("#show_api_key_box").hide();
    $("#get_api_key_box form").ajaxForm({
        dataType: 'json', // This seems to be ignored. We still get back an xhr.
        success: function (resp, statusText, xhr, form) {
            var message = "Updated settings!";
            var result = $.parseJSON(xhr.responseText);
            $("#get_api_key_password").val("");
            $("#api_key_value").text(result.api_key);
            $("#show_api_key_box").show();
            $("#get_api_key_box").hide();
            settings_status.hide();
        },
        error: function (xhr, error_type, xhn) {
            var response = "Error getting API key";
            if (xhr.status.toString().charAt(0) === "4") {
                // Only display the error response for 4XX, where we've crafted
                // a nice response.
                response += ": " + $.parseJSON(xhr.responseText).msg;
            }
            settings_status.removeClass(status_classes)
                .addClass('alert-error')
                .text(response).stop(true).fadeTo(0,1);
            $("#show_api_key_box").hide();
            $("#get_api_key_box").show();
        }
    });

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

    composebox_typeahead.initialize();

    $("body").bind('click', function() {
        if (userinfo_currently_popped !== undefined) {
            userinfo_currently_popped.popover('destroy');
            userinfo_currently_popped = undefined;
        }
    });
});
<commit_msg>ui: Fix punctuation in a comment<commit_after>// We want to remember how far we were scrolled on each 'tab'.
// To do so, we need to save away the old position of the
// scrollbar when we switch to a new tab (and restore it
// when we switch back.)
var scroll_positions = {};

function register_onclick(message_row, message_id) {
    message_row.find(".messagebox").click(function (e) {
        if (!(clicking && mouse_moved)) {
            // Was a click (not a click-and-drag).
            select_message_by_id(message_id);
            respond_to_message();
        }
        mouse_moved = false;
        clicking = false;
    });
}

function focus_on(field_id) {
    // Call after autocompleting on a field, to advance the focus to
    // the next input field.

    // Bootstrap's typeahead does not expose a callback for when an
    // autocomplete selection has been made, so we have to do this
    // manually.
    $("#" + field_id).focus();
}

/* 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. */

function hide_email() {
    $('.sender_email').addClass('invisible');
}

function show_email(message_id) {
    hide_email();
    rows.get(message_id).find('.sender_email').removeClass('invisible');
}

function report_message(response, status_box, cls) {
    if (cls === undefined)
        cls = 'alert';

    status_box.removeClass(status_classes).addClass(cls)
              .text(response).stop(true).fadeTo(0, 1);
    status_box.show();
}

function report_error(response, xhr, status_box) {
    if (xhr.status.toString().charAt(0) === "4") {
        // Only display the error response for 4XX, where we've crafted
        // a nice response.
        response += ": " + $.parseJSON(xhr.responseText).msg;
    }

    report_message(response, status_box, 'alert-error');
}

function report_success(response, status_box) {
    report_message(response, status_box, 'alert-success');
}

var clicking = false;
var mouse_moved = false;

function mousedown() {
    mouse_moved = false;
    clicking = true;
}

function mousemove() {
    if (clicking) {
        mouse_moved = true;
    }
}

function resizehandler(e) {
    var sidebar = $("#sidebar");
    var sidebar_nav = $(".sidebar-nav");
    var composebox = $("#compose");
    var top_statusbar = $("#top_statusbar");
    if (viewport.width() <= 767) {
        sidebar.removeClass('nav-stacked');

        var space_taken_up_by_navbar = sidebar_nav.outerHeight(true);

        // .visible-phone only, so doesn't need undoing
        $("#nav_whitespace").height(space_taken_up_by_navbar);

        top_statusbar.css('top', space_taken_up_by_navbar);

        var message_list_width = $("#main_div").outerWidth();
        composebox.width(message_list_width);
        top_statusbar.width(message_list_width);
        sidebar_nav.width(message_list_width);
    } else {
        sidebar.addClass('nav-stacked');
        top_statusbar.css('top', 0);
        top_statusbar.width('');
        composebox.width('');
        sidebar_nav.width('');
    }

    // This function might run onReady (if we're in a narrow window),
    // but before we've loaded in the messages; in that case, don't
    // try to scroll to one.
    if (selected_message_id !== -1) {
        scroll_to_selected();
    }
}

var old_label;
var is_floating_recipient_bar_showing = false;
function replace_floating_recipient_bar(desired_label) {
    if (desired_label !== old_label) {
        if (desired_label.children(".message_header_stream").length !== 0) {
            $("#current_label_stream td:last").replaceWith(
                desired_label.children(".message_header_stream.right_part").clone());
            $("#current_label_huddle").css('display', 'none');
            $("#current_label_stream").css('display', 'table-row');
        } else {
            $("#current_label_huddle td:last").replaceWith(
                desired_label.children(".message_header_huddle.right_part").clone());
            $("#current_label_stream").css('display', 'none');
            $("#current_label_huddle").css('display', 'table-row');
        }
        old_label = desired_label;
    }
    if (!is_floating_recipient_bar_showing) {
        $(".floating_recipient_bar").css('visibility', 'visible');
        is_floating_recipient_bar_showing = true;
    }
}

function hide_floating_recipient_bar() {
    if (is_floating_recipient_bar_showing) {
        $(".floating_recipient_bar").css('visibility', 'hidden');
        is_floating_recipient_bar_showing = false;
    }
}

function update_floating_recipient_bar() {
    var top_statusbar = $("#top_statusbar");
    var top_statusbar_top = top_statusbar.offset().top;
    var top_statusbar_bottom = top_statusbar_top + top_statusbar.outerHeight();

    // Find the last message where the top of the recipient
    // row is at least partially occluded by our box.
    // Start with the pointer's current location.
    var candidate = selected_message;
    if (candidate === undefined) {
        return;
    }
    while (true) {
        candidate = candidate.prev();
        if (candidate.length === 0) {
            // We're at the top of the page and no labels are above us.
            hide_floating_recipient_bar();
            return;
        }
        if (candidate.is(".focused_table .recipient_row")) {
            if (candidate.offset().top < top_statusbar_bottom) {
                break;
            }
        }
    }
    var current_label = candidate;

    // We now know what the floating stream/subject bar should say.
    // Do we show it?

    // Hide if the bottom of our floating stream/subject label is not
    // lower than the bottom of current_label (since that means we're
    // covering up a label that already exists).
    if (top_statusbar_bottom <=
        (current_label.offset().top + current_label.outerHeight())) {
        hide_floating_recipient_bar();
        return;
    }

    // Hide if our bottom is in our bookend (or one bookend-height
    // above it). This means we're not showing any useful part of the
    // message above us, so why bother showing the label?
    var current_bookend = current_label.nextUntil(".bookend_tr")
                                       .andSelf()
                                       .next(".bookend_tr:first");
    // (The last message currently doesn't have a bookend, which is why this might be 0).
    if (current_bookend.length > 0) {
        if (top_statusbar_bottom >
            (current_bookend.offset().top - current_bookend.outerHeight())) {
            hide_floating_recipient_bar();
            return;
        }
    }

    // If we're narrowed to a huddle or a subject, the floating
    // recipient bar would be identical to the narrowing header, so
    // don't display it.
    if (narrow.narrowing_type() === "huddle" || narrow.narrowing_type() === "subject") {
        hide_floating_recipient_bar();
        return;
    }

    replace_floating_recipient_bar(current_label);
}
function hack_for_floating_recipient_bar() {
    // So, as of this writing, Firefox respects visibility: collapse,
    // but WebKit does not (at least, my Chrome doesn't.)  Instead it
    // renders it basically as visibility: hidden, which leaves a
    // slight gap that our messages peek through as they scroll
    // by. This hack fixes this by programmatically measuring how big
    // the gap is, and then moving our table up to compensate.
    var gap = $("#floating_recipient_layout_row").outerHeight(true);
    var floating_recipient = $(".floating_recipient");
    var offset = floating_recipient.offset();
    offset.top = offset.top - gap;
    floating_recipient.offset(offset);
}

function show_api_key_box() {
    $("#get_api_key_box").show();
    $("#api_key_button_box").hide();
}

var userinfo_currently_popped;
function userinfo_popover(event, element, id) {
    event.stopPropagation();
    select_message_by_id(id);
    var elt = $(element);
    if (elt.data('popover') === undefined) {
        // One popover at a time.
        if (userinfo_currently_popped) {
            userinfo_currently_popped.popover("destroy");
            userinfo_currently_popped = undefined;
        }
        var message = message_dict[id];
        elt.popover({placement: "bottom",
                     title: templates.userinfo_popover_title(message),
                     content: templates.userinfo_popover_content(message),
                     trigger: "manual"
                    });
        elt.popover("show");
        userinfo_currently_popped = elt;
    } else {
        elt.popover("destroy");
        userinfo_currently_popped = undefined;
    }
}

function safari_composebox_hack(forwards) {
    // OK, so the situation here is basically a lot of work so that
    // Tab-Enter is a valid hotkey for sending a message in Safari.
    // By default, Safari uses Tab only to cycle through textboxes,
    // basically. Even if the tabindex is set on it, a button (like
    // our submit button) will not get focus.

    // HOWEVER, if you set the tabindex on a div, Safari/WebKit will
    // respect that, and will focus it.  So we make a div right before
    // the Send button, which, when selected, focuses the send button.
    // Then, we make another div right after it, that, when selected,
    // focuses back the composebox (so as not to break Shift-Tab in
    // these browsers).

    // This behavior is configurable in Safari, but is not on by
    // default.  (It is on by default in Chrome.)
    if (forwards) {
        $('#compose-send-button').focus();
    } else {
        $('#new_message_content').focus();
    }
}

$(function () {
    // NB: This just binds to current elements, and won't bind to elements
    // created after ready() is called.

    $('#message-type-tabs a[href="#stream-message"]').on('shown', function (e) {
        compose.set_message_type('stream');
    });
    $('#message-type-tabs a[href="#personal-message"]').on('shown', function (e) {
        compose.set_message_type('huddle');
    });

    // Prepare the click handler for subbing to a new stream to which
    // you have composed a message.
    $('#create-it').click(function () {
        subs.subscribe_for_send(compose.stream_name(), $('#stream-dne'));
    });

    // Prepare the click handler for subbing to an existing stream.
    $('#sub-it').click(function () {
        subs.subscribe_for_send(compose.stream_name(), $('#stream-nosub'));
    });

    var throttled_scrollhandler = $.throttle(50, function(e) {
        if ($('#home').hasClass('active')) {
            keep_pointer_in_view();
            update_floating_recipient_bar();
        }
    });
    $(window).scroll(throttled_scrollhandler);

    var throttled_mousewheelhandler = $.throttle(50, 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.
        move_pointer_at_page_top_and_bottom(delta);
    });
    $(window).mousewheel(throttled_mousewheelhandler);

    var throttled_resizehandler = $.throttle(50, resizehandler);
    $(window).resize(throttled_resizehandler);

    function clear_password_change() {
        // Clear the password boxes so that passwords don't linger in the DOM
        // for an XSS attacker to find.
        $('#old_password, #new_password, #confirm_password').val('');
    }

    $('#sidebar a[data-toggle="pill"]').on('show', function (e) {
        // Save the position of our old tab away, before we switch
        var old_tab = $(e.relatedTarget).attr('href');
        scroll_positions[old_tab] = viewport.scrollTop();
    });
    $('#sidebar a[data-toggle="pill"]').on('shown', function (e) {
        // Right after we show the new tab, restore its old scroll position
        var target_tab = $(e.target).attr('href');
        if (scroll_positions.hasOwnProperty(target_tab)) {
            viewport.scrollTop(scroll_positions[target_tab]);
        } else {
            viewport.scrollTop(0);
        }

        // Hide all our error messages when switching tabs
        $('.alert-error').hide();
        $('.alert-success').hide();
        $('.alert-info').hide();
        $('.alert').hide();

        $("#api_key_value").text("");
        $("#get_api_key_box").hide();
        $("#show_api_key_box").hide();
        $("#api_key_button_box").show();

        clear_password_change();

        // Set the URL bar title to show the sub-page you're currently on.
        var browser_url = target_tab;
        if (browser_url === "#home") {
            browser_url = "#";
        }
        window.history.pushState("object or string", "Title", browser_url);
    });

    $('.button-slide').click(function () {
        compose.show('stream', $("#stream"));
    });

    $('#sidebar a[href="#subscriptions"]').click(subs.fetch);

    var settings_status = $('#settings-status');
    $("#settings-change-box form").ajaxForm({
        dataType: 'json', // This seems to be ignored. We still get back an xhr.
        success: function (resp, statusText, xhr, form) {
            var message = "Updated settings!";
            var result = $.parseJSON(xhr.responseText);
            if ((result.full_name !== undefined) || (result.short_name !== undefined)) {
                message = "Updated settings!  You will need to reload the page for your changes to take effect.";
            }
            settings_status.removeClass(status_classes)
                .addClass('alert-success')
                .text(message).stop(true).fadeTo(0,1);
            // TODO: In theory we should auto-reload or something if
            // you changed the email address or other fields that show
            // up on all screens
        },
        error: function (xhr, error_type, xhn) {
            var response = "Error changing settings";
            if (xhr.status.toString().charAt(0) === "4") {
                // Only display the error response for 4XX, where we've crafted
                // a nice response.
                response += ": " + $.parseJSON(xhr.responseText).msg;
            }
            settings_status.removeClass(status_classes)
                .addClass('alert-error')
                .text(response).stop(true).fadeTo(0,1);
        },
        complete: function (xhr, statusText) {
            // Whether successful or not, clear the password boxes.
            // TODO: Clear these earlier, while the request is still pending.
            clear_password_change();
        }
    });

    $("#get_api_key_box").hide();
    $("#show_api_key_box").hide();
    $("#get_api_key_box form").ajaxForm({
        dataType: 'json', // This seems to be ignored. We still get back an xhr.
        success: function (resp, statusText, xhr, form) {
            var message = "Updated settings!";
            var result = $.parseJSON(xhr.responseText);
            $("#get_api_key_password").val("");
            $("#api_key_value").text(result.api_key);
            $("#show_api_key_box").show();
            $("#get_api_key_box").hide();
            settings_status.hide();
        },
        error: function (xhr, error_type, xhn) {
            var response = "Error getting API key";
            if (xhr.status.toString().charAt(0) === "4") {
                // Only display the error response for 4XX, where we've crafted
                // a nice response.
                response += ": " + $.parseJSON(xhr.responseText).msg;
            }
            settings_status.removeClass(status_classes)
                .addClass('alert-error')
                .text(response).stop(true).fadeTo(0,1);
            $("#show_api_key_box").hide();
            $("#get_api_key_box").show();
        }
    });

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

    composebox_typeahead.initialize();

    $("body").bind('click', function() {
        if (userinfo_currently_popped !== undefined) {
            userinfo_currently_popped.popover('destroy');
            userinfo_currently_popped = undefined;
        }
    });
});
<|endoftext|>


<commit_before>/*
 * mongo-edu
 *
 * Copyright (c) 2014 Przemyslaw Pluta
 * Licensed under the MIT license.
 * https://github.com/przemyslawpluta/mongo-edu/blob/master/LICENSE
 */

var fs = require('fs'),
    path = require('path'),
    _ = require('lodash'),
    inquirer = require('inquirer'),
    prompts = require('./prompts'),
    yargs = require('yargs')
    .usage('Usage: $0 [options]')
    .describe('d', 'download path').describe('u', 'email address')
    .describe('h', 'switch from videos (default) to handouts').boolean('h')
    .describe('py', 'py switch').describe('py', 'switch to point to Python')
    .describe('proxy', 'pass proxy').describe('proxy', 'pass proxy switch for video download')
    .describe('test', 'proxy test').describe('test', 'use with --proxy to test if usable')
    .describe('save', 'save presets').describe('save', 'save presets')
    .describe('load', 'load presets').describe('load', 'load presets')
    .describe('cw', 'switch from wiki\'s video lists (default) to courseware').boolean('cw')
    .describe('cwd', 'same as --cw and dumps list of videos to file in -d').boolean('cwd')
    .describe('cc', 'get closed captions').boolean('cc')
    .describe('hq', 'get high quality videos').boolean('hq')
    .describe('ncc', 'no check certificate').boolean('ncc')
    .describe('uz', 'unzip handout files').boolean('uz')
    .describe('co', 'sequence video files in order of the courseware').boolean('co')
    .describe('verbose', 'print debug information').boolean('verbose')
    .example('$0 -d your_download_path', 'download videos from wiki')
    .example('$0 -d your_download_path -u your_user_name --cw --hq --cc', 'download high quality videos from courseware with closed captions')
    .example('$0 -d your_download_path -h --uz', 'download and unzip handouts')
    .example('$0 -d your_download_path --cw --verbose', 'download videos from courseware and print debug info')
    .example('$0 -d your_download_path --cw --proxy http://proxy_ip_address:proxy_port_number', 'download videos from courseware via proxy tunnel')
    .example('$0 -d your_download_path --proxy http://proxy_ip_address:proxy_port_number --test', 'test proxy and download video via proxy tunnel')
    .demand('d');

var base = {},
    optionsPath = path.join(__dirname, '..', '/bin/args.json');

function readFromPath(callback) {

    'use strict';

    fs.readFile(optionsPath, function readFile(err, data) {
        if (err !== null) { return callback(err); }
        callback(null, JSON.parse(data));
    });
}

function saveToPath() {

    'use strict';

    fs.writeFile(optionsPath, JSON.stringify(base), 'utf-8', function writeFile(err) {
        if (err !== null) { return console.log('i'.red + ' Save Error: ' + err.stack); }
    });
}

function saveOptions(name) {

    'use strict';

    var handleRead = function handleRead(err, data) {
        if (err !== null) { return console.log('i'.red + ' Unable To Read File: ' + err.stack); }
        base = data;
        base[name] = _.omit(yargs.argv, 'save', 'load', 'd', '_', '$0');
        saveToPath();
    };

    fs.exists(optionsPath, function isFound(exists) {
        if (!exists) {
            base[name] = _.omit(yargs.argv, 'save', 'load', 'd', '_', '$0');
            return saveToPath();
        }
        readFromPath(handleRead);
    });
}

function loadOptions(name, callback) {

    'use strict';

    if (typeof name === 'function') { callback = name; }

    fs.exists(optionsPath, function isFound(exists) {
        if (!exists) { return callback(null, []); }
        readFromPath(function read(err, data) {
            if (typeof name !== 'function') {
                var status = !!data[name];
                return callback(err, _.omit(_.defaults(data[name], yargs.argv), 'save', 'load'), status);
            }
            callback(null, Object.keys(data));
        });
    });
}

function promptAsk(data, argv, initRun) {

    'use strict';

    inquirer.prompt(prompts.loadPreset(data), function prompt(answers) {
        loadOptions(answers.preset, function load(err, data, status) {
            if (err !== null || !status) { return console.log('i'.red + ' Unable To Load Preset: ' + argv.load); }
            initRun(data);
        });
    });
}

module.exports = (function init() {

    'use strict';

    return {
        build: function build() { return yargs; },
        checkIfLoad: function checkIfLoad(argv, initRun) {
            if (!argv.load) { return initRun(argv); }
            if (typeof argv.load === 'string') {
                loadOptions(argv.load, function load(err, data, status) {
                    if (err !== null || !status) { return console.log('i'.red + ' Preset: ' + argv.load.green + ' not found.'); }
                    initRun(data);
                });
            } else {
                loadOptions(function get(err, data) {
                    if (err !== null || !data.length) { return console.log('i'.magenta + ' No Presets Found.'); }
                    promptAsk(data, argv, initRun);
                });
            }
        },
        checkIfSave: function checkIfSave(argv, initAndConfigure, profile) {
            if (argv.save) {
                if (typeof argv.save === 'string') {
                    saveOptions(argv.save);
                } else {
                    return inquirer.prompt(prompts.savePreset, function savePreset(answers) {
                        argv.save = answers.save;
                        saveOptions(answers.save);
                        initAndConfigure(profile, argv);
                    });
                }
            }
            initAndConfigure(profile, argv);
        }
    };

}());
<commit_msg>update<commit_after>/*
 * mongo-edu
 *
 * Copyright (c) 2014 Przemyslaw Pluta
 * Licensed under the MIT license.
 * https://github.com/przemyslawpluta/mongo-edu/blob/master/LICENSE
 */

var fs = require('fs'),
    path = require('path'),
    _ = require('lodash'),
    inquirer = require('inquirer'),
    prompts = require('./prompts'),
    yargs = require('yargs')
    .usage('Usage: $0 [options]')
    .describe('d', 'download path').describe('u', 'email address')
    .describe('h', 'switch from videos (default) to handouts').boolean('h')
    .describe('py', 'py switch').describe('py', 'switch to point to Python')
    .describe('proxy', 'pass proxy').describe('proxy', 'pass proxy switch for video download')
    .describe('test', 'proxy test').describe('test', 'use with --proxy to test if usable')
    .describe('save', 'save presets').describe('save', 'save presets')
    .describe('load', 'load presets').describe('load', 'load presets')
    .describe('cw', 'switch from wiki\'s video lists (default) to courseware').boolean('cw')
    .describe('cwd', 'same as --cw and dumps list of videos to file in -d').boolean('cwd')
    .describe('cc', 'get closed captions').boolean('cc')
    .describe('hq', 'get high quality videos').boolean('hq')
    .describe('ncc', 'no check certificate').boolean('ncc')
    .describe('uz', 'unzip handout files').boolean('uz')
    .describe('co', 'sequence video files in order of the courseware').boolean('co')
    .describe('verbose', 'print debug information').boolean('verbose')
    .example('$0 -d your_download_path', 'download videos from wiki')
    .example('$0 -d your_download_path -u your_user_name --cw --hq --cc', 'download high quality videos from courseware with closed captions')
    .example('$0 -d your_download_path -u your_user_name --cw --hq --cc --save myvideo', 'save all options under `myvideo` preset and run')
    .example('$0 -d your_download_path --load', 'select and run from available presets')
    .example('$0 -d your_download_path -h --uz', 'download and unzip handouts')
    .example('$0 -d your_download_path --cw --verbose', 'download videos from courseware and print debug info')
    .example('$0 -d your_download_path --cw --proxy http://proxy_ip_address:proxy_port_number', 'download videos from courseware via proxy tunnel')
    .example('$0 -d your_download_path --proxy http://proxy_ip_address:proxy_port_number --test', 'test proxy and download video via proxy tunnel')
    .demand('d');

var base = {},
    optionsPath = path.join(__dirname, '..', '/bin/args.json');

function readFromPath(callback) {

    'use strict';

    fs.readFile(optionsPath, function readFile(err, data) {
        if (err !== null) { return callback(err); }
        callback(null, JSON.parse(data));
    });
}

function saveToPath() {

    'use strict';

    fs.writeFile(optionsPath, JSON.stringify(base), 'utf-8', function writeFile(err) {
        if (err !== null) { return console.log('i'.red + ' Save Error: ' + err.stack); }
    });
}

function saveOptions(name) {

    'use strict';

    var handleRead = function handleRead(err, data) {
        if (err !== null) { return console.log('i'.red + ' Unable To Read File: ' + err.stack); }
        base = data;
        base[name] = _.omit(yargs.argv, 'save', 'load', 'd', '_', '$0');
        saveToPath();
    };

    fs.exists(optionsPath, function isFound(exists) {
        if (!exists) {
            base[name] = _.omit(yargs.argv, 'save', 'load', 'd', '_', '$0');
            return saveToPath();
        }
        readFromPath(handleRead);
    });
}

function loadOptions(name, callback) {

    'use strict';

    if (typeof name === 'function') { callback = name; }

    fs.exists(optionsPath, function isFound(exists) {
        if (!exists) { return callback(null, []); }
        readFromPath(function read(err, data) {
            if (typeof name !== 'function') {
                var status = !!data[name];
                return callback(err, _.omit(_.defaults(data[name], yargs.argv), 'save', 'load'), status);
            }
            callback(null, Object.keys(data));
        });
    });
}

function promptAsk(data, argv, initRun) {

    'use strict';

    inquirer.prompt(prompts.loadPreset(data), function prompt(answers) {
        loadOptions(answers.preset, function load(err, data, status) {
            if (err !== null || !status) { return console.log('i'.red + ' Unable To Load Preset: ' + argv.load); }
            initRun(data);
        });
    });
}

module.exports = (function init() {

    'use strict';

    return {
        build: function build() { return yargs; },
        checkIfLoad: function checkIfLoad(argv, initRun) {
            if (!argv.load) { return initRun(argv); }
            if (typeof argv.load === 'string') {
                loadOptions(argv.load, function load(err, data, status) {
                    if (err !== null || !status) { return console.log('i'.red + ' Preset: ' + argv.load.green + ' not found.'); }
                    initRun(data);
                });
            } else {
                loadOptions(function get(err, data) {
                    if (err !== null || !data.length) { return console.log('i'.magenta + ' No Presets Found.'); }
                    promptAsk(data, argv, initRun);
                });
            }
        },
        checkIfSave: function checkIfSave(argv, initAndConfigure, profile) {
            if (argv.save) {
                if (typeof argv.save === 'string') {
                    saveOptions(argv.save);
                } else {
                    return inquirer.prompt(prompts.savePreset, function savePreset(answers) {
                        argv.save = answers.save;
                        saveOptions(answers.save);
                        initAndConfigure(profile, argv);
                    });
                }
            }
            initAndConfigure(profile, argv);
        }
    };

}());
<|endoftext|>


<commit_before>/**
 * Created by X on 2016/11/1.
 */
import { Template } from 'meteor/templating';
import { Sections } from '../../api/sections/sections.js';
import { Meteor } from 'meteor/meteor';

Template.Study_Section_Page.helpers({

  /**
   * @returns {*} All of the Stuff documents.
   */
  sectionsList() {
    let currentTime = new Date();
    for (let section of Sections.find().fetch()) {
      if (section.endTime.getTime() < currentTime.getTime() && section.startTime.getTime() < currentTime.getTime()){
        // console.log('Removing a section');
        Sections.remove(section._id);
      }
    }

    console.log(Meteor.users.find().fetch());
    return Sections.find();
  },

});

Template.Study_Section_Page.onCreated(function onCreated() {
  this.autorun(() => {
    this.subscribe('Sections');
    this.subscribe('userData');
  });
  // Example API Calls
  // Meteor.call('updateUser','firstName', 'Xyman');
  // Meteor.call('updateUser','lastName', 'Hman');
  // Meteor.call('updateUser','avatar', 'http://semantic-ui.com/images/avatar2/large/kristy.png');
  // Meteor.call('updateUser','senseiPts', 2);
  // Meteor.call('updateUser','grassPts', 10);
  // Meteor.call('updateUser','grassSubjects', 'ICS314');
  // Meteor.call('updateUser','senseiSubjects', 'ICS211');

});
<commit_msg>create section should work now after deployment<commit_after>/**
 * Created by X on 2016/11/1.
 */
import { Template } from 'meteor/templating';
import { Sections } from '../../api/sections/sections.js';
import { Meteor } from 'meteor/meteor';

Template.Study_Section_Page.helpers({

  /**
   * @returns {*} All of the Stuff documents.
   */
  sectionsList() {
    let currentTime = new Date();
    for (let section of Sections.find().fetch()) {
      if (section.endTime.getTime() < currentTime.getTime() && section.startTime.getTime() < currentTime.getTime()){
        // console.log('Removing a section');
        Sections.remove(section._id);
      }
    }

    console.log(Meteor.users.find().fetch());
    return Sections.find();
  },

});

Template.Study_Section_Page.onCreated(function onCreated() {
  this.autorun(() => {
    this.subscribe('Sections');
  });
  // Example API Calls
  // Meteor.call('updateUser','firstName', 'Xyman');
  // Meteor.call('updateUser','lastName', 'Hman');
  // Meteor.call('updateUser','avatar', 'http://semantic-ui.com/images/avatar2/large/kristy.png');
  // Meteor.call('updateUser','senseiPts', 2);
  // Meteor.call('updateUser','grassPts', 10);
  // Meteor.call('updateUser','grassSubjects', 'ICS314');
  // Meteor.call('updateUser','senseiSubjects', 'ICS211');

});
<|endoftext|>


<commit_before>import DS from 'ember-data';

const mapzenSearchAPI = 'https://search.mapzen.com/v1/autocomplete?focus.point.lat=40.7259&focus.point.lon=-73.9805&limit=5&api_key=mapzen-ugqm54r&text=';

export default DS.JSONAPIAdapter.extend({
  keyForAttribute(key) {
    return key;
  },
  buildURL(modelName, id, snapshot, requestType, query) {
    const url = `${mapzenSearchAPI}${query}, New York, NY`;
    return url;
  },
});
<commit_msg>hotfix mapzen api key<commit_after>import DS from 'ember-data';

const mapzenSearchAPI = 'https://search.mapzen.com/v1/autocomplete?focus.point.lat=40.7259&focus.point.lon=-73.9805&limit=5&api_key=mapzen-y89dXNc&text=';

export default DS.JSONAPIAdapter.extend({
  keyForAttribute(key) {
    return key;
  },
  buildURL(modelName, id, snapshot, requestType, query) {
    const url = `${mapzenSearchAPI}${query}, New York, NY`;
    return url;
  },
});
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, hashHistory, IndexRoute } from 'react-router';
import { Provider } from 'react-redux';
// import { syncHistoryWithStore } from 'react-router-redux';
import configureStore from './store/configureStore';

import App from './App';
import SampleForm from './containers/SampleForm';
import RepoList from './containers/DataFetchList';
import TypeWriter from './containers/TypeWriter';

import Welcome from './containers/Welcome';
import TicTacToe from './containers/TicTacToe';
import StopWatch from './containers/StopWatch';
import './index.css'

const repoListContainer = React.createClass({
  render() {
    return <RepoList username="Williammer" />
  }
})

const typeWriterContainer = () => {
  const str = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ultrices dolor ac dolor imperdiet ullamcorper. Suspendisse quam libero, luctus auctor mollis sed, malesuada condimentum magna. Quisque in ante tellus, in placerat est. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec a mi magna, quis mattis dolor. Etiam sit amet ligula quis urna auctor imperdiet nec faucibus ante. Mauri';
  const speed = 20;
  // [Todo] how to handle these config inputs more nicely?
  return TypeWriter(str, speed);
}

const defaultState = {
  ticReducer: {
    onXPlay: true,
    squares: Array(9).fill(null),
    moveRecords: [
      Array(9).fill(null),
    ]
  },
  stopWatchReducer: {
    timing: 0,
    resetCountedDown: 0,
    isRunning: false,
  },
  dataFetchListReducer: {
    repos: [],
    searchKeyword: '',
    isFetching: false,
  },
};

const store = configureStore(defaultState);

// const history = syncHistoryWithStore(hashHistory, store);

// TODO: extract to routes.js
ReactDOM.render(
  <Provider store={store}>
    <Router history={hashHistory}>
      <Route path="/" component={App}>
        <IndexRoute component={Welcome} />
        <Route path="/repoList" component={repoListContainer} />
        <Route path="/stopWatch" component={StopWatch} />
        <Route path="/form" component={SampleForm} />
        <Route path="/typeWriter" component={typeWriterContainer} />
        <Route path="/ticTacToe" component={TicTacToe} />
      </Route>
    </Router>
  </Provider>,
  document.getElementById('root')
)
<commit_msg>refactor<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, hashHistory, IndexRoute } from 'react-router';
import { Provider } from 'react-redux';
// import { syncHistoryWithStore } from 'react-router-redux';
import configureStore from './store/configureStore';

import App from './App';
import SampleForm from './containers/SampleForm';
import DataFetchList from './containers/DataFetchList';
import TypeWriter from './containers/TypeWriter';

import Welcome from './containers/Welcome';
import TicTacToe from './containers/TicTacToe';
import StopWatch from './containers/StopWatch';
import './index.css'

const typeWriterContainer = () => {
  const str = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ultrices dolor ac dolor imperdiet ullamcorper. Suspendisse quam libero, luctus auctor mollis sed, malesuada condimentum magna. Quisque in ante tellus, in placerat est. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec a mi magna, quis mattis dolor. Etiam sit amet ligula quis urna auctor imperdiet nec faucibus ante. Mauri';
  const speed = 20;
  // [Todo] how to handle these config inputs more nicely?
  return TypeWriter(str, speed);
}

const defaultState = {
  ticReducer: {
    onXPlay: true,
    squares: Array(9).fill(null),
    moveRecords: [
      Array(9).fill(null),
    ]
  },
  stopWatchReducer: {
    timing: 0,
    resetCountedDown: 0,
    isRunning: false,
  },
  dataFetchListReducer: {
    repos: [],
    searchKeyword: '',
    username: 'williammer',
    isFetching: false,
  },
};

const store = configureStore(defaultState);

// const history = syncHistoryWithStore(hashHistory, store);

// TODO: extract to routes.js
ReactDOM.render(
  <Provider store={store}>
    <Router history={hashHistory}>
      <Route path="/" component={App}>
        <IndexRoute component={Welcome} />
        <Route path="/repoList" component={DataFetchList} />
        <Route path="/stopWatch" component={StopWatch} />
        <Route path="/form" component={SampleForm} />
        <Route path="/typeWriter" component={typeWriterContainer} />
        <Route path="/ticTacToe" component={TicTacToe} />
      </Route>
    </Router>
  </Provider>,
  document.getElementById('root')
)
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

const {classes: Cc, interfaces: Ci, utils: Cu} = Components;

Cu.import("resource://gre/modules/ctypes.jsm");

Cu.import("chrome://htitle/content/PrefPageObserver.jsm");
Cu.import("chrome://htitle/content/Libs.jsm");

var EXPORTED_SYMBOLS = ["HTitleTools"];

var HTitlePrefObserver = {
    register: function() {
        HTitleTools.prefs.addObserver("", this, false);
    },

    unregister: function() {
        HTitleTools.prefs.removeObserver("", this);
    },

    observe: function(subject, topic, data) {
        if (topic != "nsPref:changed")
            return;

        switch(data) {
            case "debug":
                HTitleTools.DEBUG = HTitleTools.prefs.getBoolPref("debug");
                break;
            case "legacy_mode.timeout_check":
                HTitleTools.timeoutCheck = HTitleTools.prefs.getIntPref("legacy_mode.timeout_check");
                break;
            case "legacy_mode.timeout_between_changes":
                HTitleTools.timeoutBetweenChanges = HTitleTools.prefs.getIntPref("legacy_mode.timeout_between_changes");
                break;
        }
    }
}

var HTitleToolsPrivate = {
    execute: function(path, args, needWait=true) {
        var file = Cc["@mozilla.org/file/local;1"]
                     .createInstance(Ci.nsIFile);
        file.initWithPath(path);

        var process = Cc["@mozilla.org/process/util;1"]
                        .createInstance(Ci.nsIProcess);
        try {
            process.init(file);
            process.run(needWait, args, args.length);
        }
        catch (error) {
            HTitleTools.log(error.message, "ERROR");
            return -1;
        }

        if (needWait) {
            HTitleTools.log("Exit value of " + path + " is \"" + process.exitValue + "\"", "DEBUG");
            return process.exitValue;
        }
        else
            return 0;
    }
}

var HTitleTools = {
    DEBUG: false,
    appInfo: null,
    prefs: null,

    windowControlsLayout: null,
    titlebarActions: null,

    utils: {},
    defaultMethodFailed: false,

    timeoutCheck: 200, // ms
    timeoutBetweenChanges: 200, // ms

    GDK_VERSION: 2,

    init: function() {
        this.appInfo = Cc["@mozilla.org/xre/app-info;1"]
                         .getService(Ci.nsIXULAppInfo);

        this.prefs = Cc["@mozilla.org/preferences-service;1"]
                       .getService(Ci.nsIPrefService)
                       .getBranch("extensions.htitle.");
        HTitlePrefObserver.register();

        this.DEBUG = this.prefs.getBoolPref("debug");
        this.GDK_VERSION = (this.prefs.getCharPref("toolkit") == "gtk3") ? 3 : 2;
        this.timeoutCheck = this.prefs.getIntPref("legacy_mode.timeout_check");
        this.timeoutBetweenChanges = this.prefs.getIntPref("legacy_mode.timeout_between_changes");

        this.windowControlsLayout = this.getWindowControlsLayout();
        this.titlebarActions = this.getTitlebarActions();
    },

    /* ::::: App info functions ::::: */

    isFirefox: function() {
        return (this.appInfo.ID == "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}");
    },

    isThunderbird: function() {
        return (this.appInfo.ID == "{3550f703-e582-4d05-9a08-453d09bdfdc6}");
    },

    /* ::::: Change currentset attribute ::::: */

    addToCurrentset: function(node, id) {
        var currentset = node.getAttribute("currentset");
        if (!currentset)
            currentset = node.getAttribute("defaultset");
        currentset = currentset + (currentset == "" ? "" : ",") + id;
        node.setAttribute("currentset", currentset);
    },

    removeFromCurrentset: function(node, id) {
        var currentset = node.getAttribute("currentset");
        if (!currentset)
            currentset = node.getAttribute("defaultset");
        var re = new RegExp("(^|,)" + id + "($|,)");
        currentset = currentset.replace(re, "$2");
        node.setAttribute("currentset", currentset);
    },

    /* ::::: Use external utilities ::::: */

    findPathToExec: function(name) {
        // Return full path or null. Works like "which $name"

        var file = Cc["@mozilla.org/file/local;1"]
                     .createInstance(Ci.nsIFile);

        var env = Cc["@mozilla.org/process/environment;1"]
                    .getService(Ci.nsIEnvironment);
        var path = env.get("PATH").split(":");

        for (var i = 0; i < path.length; i++) {
            var full_path_to_exec = path[i] + "/" + name;

            file.initWithPath(full_path_to_exec);
            if (file.exists() && file.isExecutable()) {
                this.log("Command \"" + name + "\" was found in \"" + path[i] + "\"", "DEBUG");
                return full_path_to_exec;
            }
        }

        this.log("$PATH = " + path, "DEBUG");
        this.log("Command \"" + name + "\" not found", "ERROR");

        return null;
    },

    checkUtilsAvailable: function(utils) {
        var paths = {};
        for (var i = 0; i < utils.length; i++) {
            var path;
            if (this.utils[utils[i]] === undefined) {
                path = this.findPathToExec(utils[i]);
                this.utils[utils[i]] = path;
            }
            else {
                path = this.utils[utils[i]];
            }
            if (path == null)
                return null;
            paths[utils[i]] = path;
        }
        return paths;
    },

    checkPresenceGnomeShell: function() {
        this.log("Start checking DE", "DEBUG");

        var path = this.checkUtilsAvailable(["pidof"]);

        if (path.pidof) {
            var exitValue = HTitleToolsPrivate.execute(path.pidof, ["gnome-shell"]);
            return (exitValue == 1 ? 1 : 0);
        }
        else {
            this.log("pidof doesn't exist", "ERROR");
            return 2;
        }
    },

    /* ::::: Native window ::::: */

    changeWindowProperty: function(window, mode, action) {
        var X11 = Libs.open("X11");
        var Gdk = Libs.open("Gdk", this.GDK_VERSION, X11);

        /* Get native window */
        var base_window = window.QueryInterface(Ci.nsIInterfaceRequestor)
                                .getInterface(Ci.nsIWebNavigation)
                                .QueryInterface(Ci.nsIDocShellTreeItem)
                                .treeOwner
                                .QueryInterface(Ci.nsIInterfaceRequestor)
                                .nsIBaseWindow;
        var native_handle = base_window.nativeHandle;

        var gdk_window = new Gdk.GdkWindow.ptr(ctypes.UInt64(native_handle));
        gdk_window = Gdk.Window.get_toplevel(gdk_window);

        var gdk_display = Gdk.Display.get_default();
        var x11_display = Gdk.X11Display.get_xdisplay(gdk_display);
        if (this.GDK_VERSION == 3) {
            var x11_window = Gdk.X11Window.get_xid(gdk_window);
        }
        else {
            var x11_window = Gdk.X11Window.get_xid(ctypes.cast(gdk_window, Gdk.GdkDrawable.ptr));
        }

        //Gdk.Window.hide(gdk_window);
        if (mode == "always") {
            Gdk.Window.set_decorations(gdk_window, (action == "set") ? Gdk.GDK_DECOR_BORDER : Gdk.GDK_DECOR_ALL);
        }
        else {
            if (this.GDK_VERSION == 3) {
                Gdk.X11Window.set_hide_titlebar_when_maximized(gdk_window, (action == "set"));
            }
            else {
                let x11_property = Gdk.x11_get_xatom_by_name_for_display(gdk_display, "_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED");
                if (action == "set") {
                    // let t = new Uint8Array([1]);
                    // let x11_data = ctypes.uint8_t.ptr(t);
                    let t = new Uint32Array([1]);
                    let x11_data = ctypes.uint32_t.ptr(t);
                    X11.XChangeProperty(x11_display, x11_window, x11_property, X11.XA_CARDINAL, 32, X11.PropModeReplace, x11_data, 1);
                }
                else {
                    X11.XDeleteProperty(x11_display, x11_window, x11_property);
                }
            }
        }
        //Gdk.Window.show(gdk_window);

        Libs.close(Gdk);
        Libs.close(X11);
    },

    setWindowProperty: function(window, mode) {
        try {
            this.changeWindowProperty(window, mode, "set");
        } catch (e) {
            return -1;
        }
        return 0;
    },

    removeWindowProperty: function(window, mode) {
        try {
            this.changeWindowProperty(window, mode, "remove");
        } catch (e) {
            return -1;
        }
        return 0;
    },

    lowerWindow: function(window) {
        var Gdk = Libs.open("Gdk", this.GDK_VERSION, X11);
        var base_window = window.QueryInterface(Ci.nsIInterfaceRequestor)
                                .getInterface(Ci.nsIWebNavigation)
                                .QueryInterface(Ci.nsIDocShellTreeItem)
                                .treeOwner
                                .QueryInterface(Ci.nsIInterfaceRequestor)
                                .nsIBaseWindow;
        var native_handle = base_window.nativeHandle;
        var gdk_window = new Gdk.GdkWindow.ptr(ctypes.UInt64(native_handle));
        gdk_window = Gdk.Window.get_toplevel(gdk_window);
        Gdk.Window.lower(gdk_window);
        Libs.close(Gdk);
    },

    /* ::::: CSS stylesheets ::::: */

    loadStyle: function(name) {
        var sss = Cc["@mozilla.org/content/style-sheet-service;1"]
                    .getService(Ci.nsIStyleSheetService);
        var io = Cc["@mozilla.org/network/io-service;1"]
                   .getService(Ci.nsIIOService);
        var uri = io.newURI("chrome://htitle/skin/" + name + ".css", null, null);
        if (!sss.sheetRegistered(uri, sss.USER_SHEET))
            sss.loadAndRegisterSheet(uri, sss.USER_SHEET);
    },

    unloadStyle: function(name) {
        var sss = Cc["@mozilla.org/content/style-sheet-service;1"]
                    .getService(Ci.nsIStyleSheetService);
        var io = Cc["@mozilla.org/network/io-service;1"]
                   .getService(Ci.nsIIOService);
        var uri = io.newURI("chrome://htitle/skin/" + name + ".css", null, null);
        if (sss.sheetRegistered(uri, sss.USER_SHEET))
            sss.unregisterSheet(uri, sss.USER_SHEET);
    },

    /* ::::: Preferences ::::: */

    getWindowControlsLayout: function() {
        var layout = ":close"; // It's default for GNOME 3

        if (!this.prefs.getBoolPref("window_controls.get_layout_by_gsettings"))
            return layout;

        try {
            let gsettings = Cc["@mozilla.org/gsettings-service;1"]
                              .getService(Ci.nsIGSettingsService)
                              .getCollectionForSchema("org.gnome.shell.overrides");
            let button_layout = gsettings.getString("button-layout");
            if (/^([a-zA-Z0-9:,]*)$/.test(button_layout)) {
                layout = button_layout;
            }
            this.log("org.gnome.shell.overrides.button-layout = '" + button_layout + "'", "DEBUG");
        } catch(e) {
            this.log("GSettings isn't available", "WARNING");
            return layout;
        }

        return layout;
    },

    getTitlebarActions: function() {
        var actions = {double: "toggle-maximize",
                       middle: "lower",
                       right:  "menu"}; // It's default for GNOME 3

        if (!this.prefs.getBoolPref("titlebar.get_actions_by_gsettings"))
            return actions;

        try {
            let gsettings = Cc["@mozilla.org/gsettings-service;1"]
                              .getService(Ci.nsIGSettingsService)
                              .getCollectionForSchema("org.gnome.desktop.wm.preferences");

            actions.double = gsettings.getString("action-double-click-titlebar");
            actions.middle = gsettings.getString("action-middle-click-titlebar");
            actions.right = gsettings.getString("action-right-click-titlebar");

            this.log("org.gnome.desktop.wm.preferences.action-double-click-titlebar = '" + actions.double + "'", "DEBUG");
            this.log("org.gnome.desktop.wm.preferences.action-middle-click-titlebar = '" + actions.middle + "'", "DEBUG");
            this.log("org.gnome.desktop.wm.preferences.action-right-click-titlebar = '" + actions.right + "'", "DEBUG");
        } catch(e) {
            this.log("GSettings isn't available", "WARNING");
            return actions;
        }

        return actions;
    },

    /* ::::: Logging ::::: */

    log: function(message, level="ERROR") {
        if (this.DEBUG == false && level == "DEBUG")
            return;

        var console = Cc["@mozilla.org/consoleservice;1"]
                        .getService(Ci.nsIConsoleService);

        var flag;
        switch (level) {
            case "ERROR":
                flag = 0;
                break;
            case "WARNING":
                flag = 1;
                break;
            default:
                flag = 4;
        }

        if (flag == 4) {
            console.logStringMessage("HTitle DEBUG: " + message);
        }
        else {
            var console_message = Cc["@mozilla.org/scripterror;1"]
                                    .createInstance(Ci.nsIScriptError);
            console_message.init(message, "HTitle", null, null, null, flag, null);
            console.logMessage(console_message);
        }
    },
}

HTitleTools.init();
<commit_msg>Fix HTitleTools.lowerWindow()<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

const {classes: Cc, interfaces: Ci, utils: Cu} = Components;

Cu.import("resource://gre/modules/ctypes.jsm");

Cu.import("chrome://htitle/content/PrefPageObserver.jsm");
Cu.import("chrome://htitle/content/Libs.jsm");

var EXPORTED_SYMBOLS = ["HTitleTools"];

var HTitlePrefObserver = {
    register: function() {
        HTitleTools.prefs.addObserver("", this, false);
    },

    unregister: function() {
        HTitleTools.prefs.removeObserver("", this);
    },

    observe: function(subject, topic, data) {
        if (topic != "nsPref:changed")
            return;

        switch(data) {
            case "debug":
                HTitleTools.DEBUG = HTitleTools.prefs.getBoolPref("debug");
                break;
            case "legacy_mode.timeout_check":
                HTitleTools.timeoutCheck = HTitleTools.prefs.getIntPref("legacy_mode.timeout_check");
                break;
            case "legacy_mode.timeout_between_changes":
                HTitleTools.timeoutBetweenChanges = HTitleTools.prefs.getIntPref("legacy_mode.timeout_between_changes");
                break;
        }
    }
}

var HTitleToolsPrivate = {
    execute: function(path, args, needWait=true) {
        var file = Cc["@mozilla.org/file/local;1"]
                     .createInstance(Ci.nsIFile);
        file.initWithPath(path);

        var process = Cc["@mozilla.org/process/util;1"]
                        .createInstance(Ci.nsIProcess);
        try {
            process.init(file);
            process.run(needWait, args, args.length);
        }
        catch (error) {
            HTitleTools.log(error.message, "ERROR");
            return -1;
        }

        if (needWait) {
            HTitleTools.log("Exit value of " + path + " is \"" + process.exitValue + "\"", "DEBUG");
            return process.exitValue;
        }
        else
            return 0;
    }
}

var HTitleTools = {
    DEBUG: false,
    appInfo: null,
    prefs: null,

    windowControlsLayout: null,
    titlebarActions: null,

    utils: {},
    defaultMethodFailed: false,

    timeoutCheck: 200, // ms
    timeoutBetweenChanges: 200, // ms

    GDK_VERSION: 2,

    init: function() {
        this.appInfo = Cc["@mozilla.org/xre/app-info;1"]
                         .getService(Ci.nsIXULAppInfo);

        this.prefs = Cc["@mozilla.org/preferences-service;1"]
                       .getService(Ci.nsIPrefService)
                       .getBranch("extensions.htitle.");
        HTitlePrefObserver.register();

        this.DEBUG = this.prefs.getBoolPref("debug");
        this.GDK_VERSION = (this.prefs.getCharPref("toolkit") == "gtk3") ? 3 : 2;
        this.timeoutCheck = this.prefs.getIntPref("legacy_mode.timeout_check");
        this.timeoutBetweenChanges = this.prefs.getIntPref("legacy_mode.timeout_between_changes");

        this.windowControlsLayout = this.getWindowControlsLayout();
        this.titlebarActions = this.getTitlebarActions();
    },

    /* ::::: App info functions ::::: */

    isFirefox: function() {
        return (this.appInfo.ID == "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}");
    },

    isThunderbird: function() {
        return (this.appInfo.ID == "{3550f703-e582-4d05-9a08-453d09bdfdc6}");
    },

    /* ::::: Change currentset attribute ::::: */

    addToCurrentset: function(node, id) {
        var currentset = node.getAttribute("currentset");
        if (!currentset)
            currentset = node.getAttribute("defaultset");
        currentset = currentset + (currentset == "" ? "" : ",") + id;
        node.setAttribute("currentset", currentset);
    },

    removeFromCurrentset: function(node, id) {
        var currentset = node.getAttribute("currentset");
        if (!currentset)
            currentset = node.getAttribute("defaultset");
        var re = new RegExp("(^|,)" + id + "($|,)");
        currentset = currentset.replace(re, "$2");
        node.setAttribute("currentset", currentset);
    },

    /* ::::: Use external utilities ::::: */

    findPathToExec: function(name) {
        // Return full path or null. Works like "which $name"

        var file = Cc["@mozilla.org/file/local;1"]
                     .createInstance(Ci.nsIFile);

        var env = Cc["@mozilla.org/process/environment;1"]
                    .getService(Ci.nsIEnvironment);
        var path = env.get("PATH").split(":");

        for (var i = 0; i < path.length; i++) {
            var full_path_to_exec = path[i] + "/" + name;

            file.initWithPath(full_path_to_exec);
            if (file.exists() && file.isExecutable()) {
                this.log("Command \"" + name + "\" was found in \"" + path[i] + "\"", "DEBUG");
                return full_path_to_exec;
            }
        }

        this.log("$PATH = " + path, "DEBUG");
        this.log("Command \"" + name + "\" not found", "ERROR");

        return null;
    },

    checkUtilsAvailable: function(utils) {
        var paths = {};
        for (var i = 0; i < utils.length; i++) {
            var path;
            if (this.utils[utils[i]] === undefined) {
                path = this.findPathToExec(utils[i]);
                this.utils[utils[i]] = path;
            }
            else {
                path = this.utils[utils[i]];
            }
            if (path == null)
                return null;
            paths[utils[i]] = path;
        }
        return paths;
    },

    checkPresenceGnomeShell: function() {
        this.log("Start checking DE", "DEBUG");

        var path = this.checkUtilsAvailable(["pidof"]);

        if (path.pidof) {
            var exitValue = HTitleToolsPrivate.execute(path.pidof, ["gnome-shell"]);
            return (exitValue == 1 ? 1 : 0);
        }
        else {
            this.log("pidof doesn't exist", "ERROR");
            return 2;
        }
    },

    /* ::::: Native window ::::: */

    changeWindowProperty: function(window, mode, action) {
        var X11 = Libs.open("X11");
        var Gdk = Libs.open("Gdk", this.GDK_VERSION, X11);

        /* Get native window */
        var base_window = window.QueryInterface(Ci.nsIInterfaceRequestor)
                                .getInterface(Ci.nsIWebNavigation)
                                .QueryInterface(Ci.nsIDocShellTreeItem)
                                .treeOwner
                                .QueryInterface(Ci.nsIInterfaceRequestor)
                                .nsIBaseWindow;
        var native_handle = base_window.nativeHandle;

        var gdk_window = new Gdk.GdkWindow.ptr(ctypes.UInt64(native_handle));
        gdk_window = Gdk.Window.get_toplevel(gdk_window);

        var gdk_display = Gdk.Display.get_default();
        var x11_display = Gdk.X11Display.get_xdisplay(gdk_display);
        if (this.GDK_VERSION == 3) {
            var x11_window = Gdk.X11Window.get_xid(gdk_window);
        }
        else {
            var x11_window = Gdk.X11Window.get_xid(ctypes.cast(gdk_window, Gdk.GdkDrawable.ptr));
        }

        //Gdk.Window.hide(gdk_window);
        if (mode == "always") {
            Gdk.Window.set_decorations(gdk_window, (action == "set") ? Gdk.GDK_DECOR_BORDER : Gdk.GDK_DECOR_ALL);
        }
        else {
            if (this.GDK_VERSION == 3) {
                Gdk.X11Window.set_hide_titlebar_when_maximized(gdk_window, (action == "set"));
            }
            else {
                let x11_property = Gdk.x11_get_xatom_by_name_for_display(gdk_display, "_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED");
                if (action == "set") {
                    // let t = new Uint8Array([1]);
                    // let x11_data = ctypes.uint8_t.ptr(t);
                    let t = new Uint32Array([1]);
                    let x11_data = ctypes.uint32_t.ptr(t);
                    X11.XChangeProperty(x11_display, x11_window, x11_property, X11.XA_CARDINAL, 32, X11.PropModeReplace, x11_data, 1);
                }
                else {
                    X11.XDeleteProperty(x11_display, x11_window, x11_property);
                }
            }
        }
        //Gdk.Window.show(gdk_window);

        Libs.close(Gdk);
        Libs.close(X11);
    },

    setWindowProperty: function(window, mode) {
        try {
            this.changeWindowProperty(window, mode, "set");
        } catch (e) {
            return -1;
        }
        return 0;
    },

    removeWindowProperty: function(window, mode) {
        try {
            this.changeWindowProperty(window, mode, "remove");
        } catch (e) {
            return -1;
        }
        return 0;
    },

    lowerWindow: function(window) {
        var Gdk = Libs.open("Gdk", this.GDK_VERSION);
        var base_window = window.QueryInterface(Ci.nsIInterfaceRequestor)
                                .getInterface(Ci.nsIWebNavigation)
                                .QueryInterface(Ci.nsIDocShellTreeItem)
                                .treeOwner
                                .QueryInterface(Ci.nsIInterfaceRequestor)
                                .nsIBaseWindow;
        var native_handle = base_window.nativeHandle;
        var gdk_window = new Gdk.GdkWindow.ptr(ctypes.UInt64(native_handle));
        gdk_window = Gdk.Window.get_toplevel(gdk_window);
        Gdk.Window.lower(gdk_window);
        Libs.close(Gdk);
    },

    /* ::::: CSS stylesheets ::::: */

    loadStyle: function(name) {
        var sss = Cc["@mozilla.org/content/style-sheet-service;1"]
                    .getService(Ci.nsIStyleSheetService);
        var io = Cc["@mozilla.org/network/io-service;1"]
                   .getService(Ci.nsIIOService);
        var uri = io.newURI("chrome://htitle/skin/" + name + ".css", null, null);
        if (!sss.sheetRegistered(uri, sss.USER_SHEET))
            sss.loadAndRegisterSheet(uri, sss.USER_SHEET);
    },

    unloadStyle: function(name) {
        var sss = Cc["@mozilla.org/content/style-sheet-service;1"]
                    .getService(Ci.nsIStyleSheetService);
        var io = Cc["@mozilla.org/network/io-service;1"]
                   .getService(Ci.nsIIOService);
        var uri = io.newURI("chrome://htitle/skin/" + name + ".css", null, null);
        if (sss.sheetRegistered(uri, sss.USER_SHEET))
            sss.unregisterSheet(uri, sss.USER_SHEET);
    },

    /* ::::: Preferences ::::: */

    getWindowControlsLayout: function() {
        var layout = ":close"; // It's default for GNOME 3

        if (!this.prefs.getBoolPref("window_controls.get_layout_by_gsettings"))
            return layout;

        try {
            let gsettings = Cc["@mozilla.org/gsettings-service;1"]
                              .getService(Ci.nsIGSettingsService)
                              .getCollectionForSchema("org.gnome.shell.overrides");
            let button_layout = gsettings.getString("button-layout");
            if (/^([a-zA-Z0-9:,]*)$/.test(button_layout)) {
                layout = button_layout;
            }
            this.log("org.gnome.shell.overrides.button-layout = '" + button_layout + "'", "DEBUG");
        } catch(e) {
            this.log("GSettings isn't available", "WARNING");
            return layout;
        }

        return layout;
    },

    getTitlebarActions: function() {
        var actions = {double: "toggle-maximize",
                       middle: "lower",
                       right:  "menu"}; // It's default for GNOME 3

        if (!this.prefs.getBoolPref("titlebar.get_actions_by_gsettings"))
            return actions;

        try {
            let gsettings = Cc["@mozilla.org/gsettings-service;1"]
                              .getService(Ci.nsIGSettingsService)
                              .getCollectionForSchema("org.gnome.desktop.wm.preferences");

            actions.double = gsettings.getString("action-double-click-titlebar");
            actions.middle = gsettings.getString("action-middle-click-titlebar");
            actions.right = gsettings.getString("action-right-click-titlebar");

            this.log("org.gnome.desktop.wm.preferences.action-double-click-titlebar = '" + actions.double + "'", "DEBUG");
            this.log("org.gnome.desktop.wm.preferences.action-middle-click-titlebar = '" + actions.middle + "'", "DEBUG");
            this.log("org.gnome.desktop.wm.preferences.action-right-click-titlebar = '" + actions.right + "'", "DEBUG");
        } catch(e) {
            this.log("GSettings isn't available", "WARNING");
            return actions;
        }

        return actions;
    },

    /* ::::: Logging ::::: */

    log: function(message, level="ERROR") {
        if (this.DEBUG == false && level == "DEBUG")
            return;

        var console = Cc["@mozilla.org/consoleservice;1"]
                        .getService(Ci.nsIConsoleService);

        var flag;
        switch (level) {
            case "ERROR":
                flag = 0;
                break;
            case "WARNING":
                flag = 1;
                break;
            default:
                flag = 4;
        }

        if (flag == 4) {
            console.logStringMessage("HTitle DEBUG: " + message);
        }
        else {
            var console_message = Cc["@mozilla.org/scripterror;1"]
                                    .createInstance(Ci.nsIScriptError);
            console_message.init(message, "HTitle", null, null, null, flag, null);
            console.logMessage(console_message);
        }
    },
}

HTitleTools.init();
<|endoftext|>


<commit_before>(function () {
    'use strict';

    const DISABLED_FEATURES = [
        'header_screenshot',
        'header_symbol_search',
        'display_market_status'
    ];

    let counter = 0;

    /**
     *
     * @param {Base} Base
     * @param candlesService
     * @return {DexCandleChart}
     */
    const controller = function (Base, candlesService) {

        class DexCandleChart extends Base {

            constructor() {
                super();
                this.chart = null;
                this.chartReady = false;
                this.elementId = 'tradingview' + counter++;
                this.notLoaded = false;
                this._assetIdPairWasChanged = false;

                /**
                 * @type {{price: string, amount: string}}
                 * @private
                 */
                this._assetIdPair = null;

                this.observe('_assetIdPair', () => {

                    if (this.chartReady) {
                        this.chart.symbolInterval(({ interval }) => {
                            this.chart.setSymbol(`${this._assetIdPair.amount}/${this._assetIdPair.price}`, interval);
                        });
                    } else {
                        this._assetIdPairWasChanged = true;
                    }
                });

                this.syncSettings({
                    _assetIdPair: 'dex.assetIdPair'
                });
            }

            $postLink() {
                controller.load().then(() => {
                    this.chart = new TradingView.widget({
                        // debug: true,
                        symbol: `${this._assetIdPair.amount}/${this._assetIdPair.price}`,
                        interval: WavesApp.dex.defaultResolution,
                        container_id: this.elementId,
                        datafeed: candlesService,
                        library_path: 'trading-view/',
                        autosize: true,
                        disabled_features: DISABLED_FEATURES
                    });

                    this.chart.onChartReady(() => {
                        this.chartReady = true;
                        // this.chart.subscribe('onSymbolChange', (data) => console.log(data));
                        if (this._assetIdPairWasChanged) {
                            this.chart.symbolInterval(({ interval }) => {
                                this.chart.setSymbol(`${this._assetIdPair.amount}/${this._assetIdPair.price}`, interval);
                            });
                        }
                    });
                }, () => {
                    console.warn('Error 403!');
                    this.notLoaded = true;
                });
            }

        }

        return new DexCandleChart();
    };

    controller.$inject = ['Base', 'candlesService'];

    controller.load = function () {
        const script = document.createElement('script');
        const root = '/trading-view/';
        script.src = `${root}charting_library.min.js`;
        const promise = new Promise((resolve, reject) => {
            script.onload = resolve;
            script.onerror = reject;
            document.head.appendChild(script);
        });
        controller.load = () => promise;
        return promise;
    };

    angular.module('app.dex').component('wDexCandleChart', {
        bindings: {},
        templateUrl: 'modules/dex/directives/dexCandleChart/dex-candle-chart.html',
        transclude: false,
        controller
    });
})();
<commit_msg>CLIENT-382: revert jslib (remove jslib in other task)<commit_after>(function () {
    'use strict';

    const DISABLED_FEATURES = [
        'header_screenshot',
        'header_symbol_search',
        'display_market_status'
    ];

    let counter = 0;

    /**
     *
     * @param {Base} Base
     * @param candlesService
     * @return {DexCandleChart}
     */
    const controller = function (Base, candlesService) {

        class DexCandleChart extends Base {

            constructor() {
                super();
                this.chart = null;
                this.chartReady = false;
                this.elementId = 'tradingview' + counter++;
                this.notLoaded = false;
                this._assetIdPairWasChanged = false;

                /**
                 * @type {{price: string, amount: string}}
                 * @private
                 */
                this._assetIdPair = null;

                this.observe('_assetIdPair', () => {

                    if (this.chartReady) {
                        this.chart.symbolInterval(({ interval }) => {
                            this.chart.setSymbol(`${this._assetIdPair.amount}/${this._assetIdPair.price}`, interval);
                        });
                    } else {
                        this._assetIdPairWasChanged = true;
                    }
                });

                this.syncSettings({
                    _assetIdPair: 'dex.assetIdPair'
                });
            }

            $postLink() {
                controller.load().then(() => {
                    this.chart = new TradingView.widget({
                        // debug: true,
                        symbol: `${this._assetIdPair.amount}/${this._assetIdPair.price}`,
                        interval: WavesApp.dex.defaultResolution,
                        container_id: this.elementId,
                        datafeed: candlesService,
                        library_path: 'trading-view/',
                        autosize: true,
                        disabled_features: DISABLED_FEATURES
                    });

                    this.chart.onChartReady(() => {
                        this.chartReady = true;
                        // this.chart.subscribe('onSymbolChange', (data) => console.log(data));
                        if (this._assetIdPairWasChanged) {
                            this.chart.symbolInterval(({ interval }) => {
                                this.chart.setSymbol(`${this._assetIdPair.amount}/${this._assetIdPair.price}`, interval);
                            });
                        }
                    });
                }, () => {
                    console.warn('Error 403!');
                    this.notLoaded = true;
                });
            }

        }

        return new DexCandleChart();
    };

    controller.$inject = ['Base', 'candlesService'];

    controller.load = function () {
        const script = document.createElement('script');
        const root = WavesApp.isWeb() ? 'https://jslib.wavesnodes.com/' : '/trading-view/';
        script.src = `${root}charting_library.min.js`;
        const promise = new Promise((resolve, reject) => {
            script.onload = resolve;
            script.onerror = reject;
            document.head.appendChild(script);
        });
        controller.load = () => promise;
        return promise;
    };

    angular.module('app.dex').component('wDexCandleChart', {
        bindings: {},
        templateUrl: 'modules/dex/directives/dexCandleChart/dex-candle-chart.html',
        transclude: false,
        controller
    });
})();
<|endoftext|>


<commit_before>import PIXI from "pixi.js";
import $    from "jquery";

import {Vec2} from "@ignavia/ella";

import * as draph from "./draph.js";

export default class GraphView {
    constructor(graphObj, width = screen.width, height = screen.height) {
        const {
            renderer,
            stage,
            nodeContainer,
            edgeContainer
        } = draph.graphVisualizer.makeEnhancedViewWithDefaultConf();

this.renderer = renderer;
this.stage = stage;
this.nodeContainer = nodeContainer;
this.edgeContainer = edgeContainer;

        $("#container").html(renderer.view);

        this.width = width;
        this.height = height;

        this.graph = graphObj;
        this.nodes = new Map();
        this.edges = new Map();

        for (let nodeObj of graphObj.iterNodes()) {
            const displayObject = draph.nodeVisualizer.makeEnhancedSpriteWithDefaultConf();
            this.nodeContainer.addChild(displayObject);
            this.nodes.set(nodeObj.id, displayObject);

            displayObject.x = Math.random() * width;
            displayObject.y = Math.random() * height;
        }
        for (let edgeObj of graphObj.iterEdges()) {
            const source = edgeObj.sourceId;
            const target = edgeObj.targetId;
            const sourcePos = this.nodes.get(source);
            const targetPos = this.nodes.get(target);
            const displayObject = draph.edgeVisualizer.makeEnhancedSpriteWithDefaultConf(
                new Vec2(sourcePos.x, sourcePos.y),
                new Vec2(targetPos.x, targetPos.y)
            );
            this.edgeContainer.addChild(displayObject);
            this.edges.set(edgeObj.id, displayObject);
        }

        if (width !== window.innerWidth || height !== window.innerHeight) {
            this.resize();
        }

        this.animate();
    }

    /**
     * Returns the display object for the given node ID.
     *
     * @param {String} nodeId
     * The ID of the node to get the display object for.
     *
     * @return {DisplayObject}
     * The display object for the node.
     */
    getNodeDisplayObjectById(nodeId) {
        return this.nodes.get(nodeId);
    }

    /**
     * Returns the display object for the given edge ID.
     *
     * @param {String} edgeId
     * The ID of the edge to get the display object for.
     *
     * @return {DisplayObject}
     * The display object for the edge.
     */
    getEdgeDisplayObjectById(edgeId) {
        return this.edges.get(edgeId);
    }

    resize(width = window.innerWidth, height = window.innerHeight) {
        this.renderer.resize(width, height);
    }

    animate() {
        // this is the main render call that makes pixi draw your container and its children.
        this.renderer.render(this.stage);
        //console.log(this.renderer.plugins.interaction.mouse);
        requestAnimationFrame(() => this.animate());
    }

    addNode(visualizer) {

    }

    addEdge() {

    }
}<commit_msg>Documentation<commit_after>import PIXI from "pixi.js";
import $    from "jquery";

import {Vec2} from "@ignavia/ella";

import * as draph from "./draph.js";

export default class GraphView {
    constructor(graphObj) {
        const {
            renderer,
            stage,
            nodeContainer,
            edgeContainer
        } = draph.graphVisualizer.makeEnhancedViewWithDefaultConf();

        /**
         * The renderer used to draw the stage.
         *
         * @type {Renderer}
         */
        this.renderer = renderer;

        /**
         * The display object to draw with the renderer.
         *
         * @type {DisplayObject}
         */
        this.stage = stage;

        /**
         * The container for the node display objects.
         *
         * @type {DisplayObject}
         */
        this.nodeContainer = nodeContainer;

        /**
         * The container for the edge display object.
         *
         * @type {DisplayObject}
         */
        this.edgeContainer = edgeContainer;

        /**
         * The graph getting displayed.
         *
         * @type {Graph}
         */
        this.graph = graphObj;

        /**
         * Maps from node IDs to their display objects.
         *
         * @type {Map<String, DisplayObject>}
         */
        this.nodes = new Map();

        /**
         * Maps from edge IDs to their display objects.
         *
         * @type {Map<String, DisplayObject>}
         */
        this.edges = new Map();

        this.init();
        this.animate();
    }

    init() {

        // Add view to container
        $("#container").html(this.renderer.view); // TODO: pass id of container as param

        // Nodes
        for (let nodeObj of this.graph.iterNodes()) {
            const displayObject = draph.nodeVisualizer.makeEnhancedSpriteWithDefaultConf();
            this.nodeContainer.addChild(displayObject);
            this.nodes.set(nodeObj.id, displayObject);

            displayObject.x = Math.random() * this.renderer.width;
            displayObject.y = Math.random() * this.renderer.height;
        }

        // Edges
        for (let edgeObj of this.graph.iterEdges()) {
            const sourceG = this.nodes.get(edgeObj.sourceId);
            const targetG = this.nodes.get(edgeObj.targetId);
            const displayObject = draph.edgeVisualizer.makeEnhancedSpriteWithDefaultConf(
                new Vec2(sourceG.x, sourceG.y),
                new Vec2(targetG.x, targetG.y)
            );
            this.edgeContainer.addChild(displayObject);
            this.edges.set(edgeObj.id, displayObject);
        }

        // Resize
        if (this.renderer.width !== window.innerWidth || this.renderer.height !== window.innerHeight) {
            this.resize();
        }
    }

    /**
     * Returns the display object for the given node ID.
     *
     * @param {String} nodeId
     * The ID of the node to get the display object for.
     *
     * @return {DisplayObject}
     * The display object for the node.
     */
    getNodeDisplayObjectById(nodeId) {
        return this.nodes.get(nodeId);
    }

    /**
     * Returns the display object for the given edge ID.
     *
     * @param {String} edgeId
     * The ID of the edge to get the display object for.
     *
     * @return {DisplayObject}
     * The display object for the edge.
     */
    getEdgeDisplayObjectById(edgeId) {
        return this.edges.get(edgeId);
    }

    resize(width = window.innerWidth, height = window.innerHeight) {
        this.renderer.resize(width, height);
    }

    addNode(visualizer) {

    }

    addEdge() {

    }

    /**
     * Starts the render loop and repeatedly draws the stage.
     */
    animate() {
        this.renderer.render(this.stage);
        requestAnimationFrame(() => this.animate());
    }
}<|endoftext|>


<commit_before>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return move||getInput();
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    return move||randomPlay();
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    if ((playerMove==='paper' && computerMove==='rock')||
    (playerMove==='rock' && computerMove==='scissors')||
    (playerMove==='scissors' && computerMove==='paper'))
    winner = 'player';

    else if ((playerMove==='scissors' && computerMove==='rock')||
    (playerMove==='rock' && computerMove==='paper')||
    (playerMove==='paper' && computerMove==='scissors'))
    winner = 'computer';

    else
    winner = 'tie';

return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    /* YOUR CODE HERE */
    return [playerWins, computerWins];
}

<commit_msg>Provided code for body of playToFive() function<commit_after>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return move||getInput();
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    return move||randomPlay();
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    if ((playerMove==='paper' && computerMove==='rock')||
    (playerMove==='rock' && computerMove==='scissors')||
    (playerMove==='scissors' && computerMove==='paper'))
    winner = 'player';

    else if ((playerMove==='scissors' && computerMove==='rock')||
    (playerMove==='rock' && computerMove==='paper')||
    (playerMove==='paper' && computerMove==='scissors'))
    winner = 'computer';

    else
    winner = 'tie';

return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    while (playerWins < 5 && computerWins < 5) {
        var playerMove = getPlayerMove();
        var computerMove = getComputerMove();
        var winner = getWinner(playerMove, computerMove);
            if(winner === 'player')
            playerWins++;
            else if(winner === 'computer')
            computerWins++;
        console.log("Player chose " + playerMove + " while Computer chose " + computerMove);
        console.log("The score is currently " + playerWins + " to " + computerWins + '\n');
    }
    return [playerWins, computerWins];
}

<|endoftext|>