text: import $ from "jquery";
  
  import render_feedback_container from "../templates/feedback_container.hbs";
  
  import * as blueslip from "./blueslip";
  
  /*
  
  This code lets you show something like this:
  
      +-----
      | TOPIC MUTES [undo] [x]
      |
      | You muted stream Foo, topic Bar.
      +-----
  
  And then you configure the undo behavior, and
  everything else is controlled by the widget.
  
  Code-wise it's a singleton widget that controls the DOM inside
  #feedback_container, which gets served up by server.
  
  */
  
  const meta = {
      hide_me_time: null,
      alert_hover_state: false,
      $container: null,
      opened: false,
  };
  
  const animate = {
      maybe_close() {
          if (!meta.opened) {
              return;
          }
  
          if (meta.hide_me_time < Date.now() && !meta.alert_hover_state) {
              animate.fadeOut();
              return;
          }
  
          setTimeout(animate.maybe_close, 100);
      },
      fadeOut() {
          if (!meta.opened) {
              return;
          }
  
          if (meta.$container) {
              meta.$container.fadeOut(500).removeClass("show");
              meta.opened = false;
              meta.alert_hover_state = false;
          }
      },
      fadeIn() {
          if (meta.opened) {
              return;
          }
  
          if (meta.$container) {
              meta.$container.fadeIn(500).addClass("show");
              meta.opened = true;
              setTimeout(animate.maybe_close, 100);
          }
      },
  };
  
  function set_up_handlers() {
      if (meta.handlers_set) {
          return;
      }
  
      meta.handlers_set = true;
  
      // if the user mouses over the notification, don't hide it.
      meta.$container.on("mouseenter", () => {
          if (!meta.opened) {
              return;
          }
  
          meta.alert_hover_state = true;
      });
  
      // once the user's mouse leaves the notification, restart the countdown.
      meta.$container.on("mouseleave", () => {
          if (!meta.opened) {
              return;
          }
  
          meta.alert_hover_state = false;
          // add at least 2000ms but if more than that exists just keep the
          // current amount.
          meta.hide_me_time = Math.max(meta.hide_me_time, Date.now() + 2000);
      });
  
      meta.$container.on("click", ".exit-me", () => {
          animate.fadeOut();
      });
  
      meta.$container.on("click", ".feedback_undo", () => {
          if (meta.undo) {
              meta.undo();
          }
          animate.fadeOut();
      });
  }
  
  export function is_open() {
      return meta.opened;
  }
  
  export function dismiss() {
      animate.fadeOut();
  }
  
  export function show(opts) {
      if (!opts.populate) {
          blueslip.error("programmer needs to supply populate callback.");
          return;
      }
  
      meta.$container = $("#feedback_container");
  
      const html = render_feedback_container();
      meta.$container.html(html);
  
      set_up_handlers();
  
      meta.undo = opts.on_undo;
  
      // add a four second delay before closing up.
      meta.hide_me_time = Date.now() + 4000;
  
      meta.$container.find(".feedback_title").text(opts.title_text);
      meta.$container.find(".feedback_undo").text(opts.undo_button_text);
      opts.populate(meta.$container.find(".feedback_content"));
  
      animate.fadeIn();
  }
  