<commit_before>/* global django,ContentEditor */

django.jQuery(function ($) {
  const context = document.getElementById("content-editor-context");
  if (!context) return;

  function qs(sel, ctx = document) {
    return ctx.querySelector(sel);
  }
  function qsa(sel, ctx = document) {
    return Array.prototype.slice.call(ctx.querySelectorAll(sel));
  }

  window.ContentEditor = {
    addContent: function addContent(prefix) {
      $("#" + prefix + "-group .add-row a").click();
    },
    addPluginButton: function addPluginButton(prefix, html) {
      const plugin =
        ContentEditor.pluginsByPrefix[prefix] ||
        ContentEditor.pluginsByPrefix[prefix + "_set"];
      if (!plugin) return;

      let unit = qs(".control-unit.plugin-buttons");
      if (!unit) {
        unit = document.createElement("div");
        unit.className = "control-unit plugin-buttons";
        const mc = qs(".machine-control");
        mc.insertBefore(unit, mc.firstChild);
      }

      const button = document.createElement("a");
      button.setAttribute("data-plugin", plugin.prefix);
      button.className = "plugin-button";
      button.title = plugin.title;
      button.addEventListener("click", function () {
        ContentEditor.addContent(plugin.prefix);
      });
      button.innerHTML = html;

      unit.appendChild(button);

      hideNotAllowedPluginButtons([button]);
    },
  };

  $.extend(window.ContentEditor, JSON.parse(context.dataset.context));

  ContentEditor.pluginsByPrefix = {};
  ContentEditor.pluginsByKey = {};
  ContentEditor.prefixToKey = {};
  for (let i = 0; i < ContentEditor.plugins.length; ++i) {
    ContentEditor.pluginsByPrefix[ContentEditor.plugins[i].prefix] =
      ContentEditor.plugins[i];
  }
  ContentEditor.regionsByKey = {};
  for (let i = 0; i < ContentEditor.regions.length; ++i) {
    ContentEditor.regionsByKey[ContentEditor.regions[i].key] =
      ContentEditor.regions[i];
  }

  // Add basic structure. There is always at least one inline group if
  // we even have any plugins.
  $(".inline-group:first").before(
    '
' +
      '<input type="checkbox" /> ' +
      ContentEditor.messages.toggle +
      "" +
      "
" +
      '
' +
      '

' +
      "
"
  );

  const orderMachine = $(".order-machine"),
    machineEmptyMessage = $('
')
      .text(ContentEditor.messages.empty)
      .appendTo(orderMachine);

  // Pre map plugin regions
  const pluginRegions = (function () {
    const result = {};
    const plugins = ContentEditor.plugins;
    for (let i = 0; i < plugins.length; i++) {
      result[plugins[i].prefix] = plugins[i].regions;
    }
    return result;
  })();

  function ensureDraggable(arg) {
    if (arg.hasClass("empty-form") || arg.hasClass("fs-draggable")) return;

    const inline = arg[0];

    inline.addEventListener("dragstart", function (e) {
      // window.__fs_dragging = inline;
      window.__fs_dragging = e.target.closest(".inline-related");
      window.__fs_dragging.classList.add("fs-dragging");

      e.dataTransfer.dropEffect = "move";
      e.dataTransfer.effectAllowed = "move";
      try {
        e.dataTransfer.setData("text/plain", "");
      } catch (e) {
        // IE11 needs this.
      }
    });
    inline.addEventListener("dragend", function () {
      $(".fs-dragging").removeClass("fs-dragging");
      $(".fs-dragover").removeClass("fs-dragover");
    });
    inline.addEventListener(
      "dragover",
      function (e) {
        e.preventDefault();
        $(".fs-dragover").removeClass("fs-dragover");
        e.target.closest(".inline-related").classList.add("fs-dragover");
      },
      true
    );
    inline.addEventListener("drop", function (e) {
      e.preventDefault();
      insertBefore(window.__fs_dragging, e.target.closest(".inline-related"));
    });

    arg.find(">h3").attr("draggable", true);
    arg.addClass("fs-draggable");
  }

  function reorderInlines(context) {
    context = context || orderMachine;
    const inlines = context.find(".inline-related");
    inlines.not(".empty-form").each(function () {
      $(document).trigger("content-editor:deactivate", [$(this)]);

      ensureDraggable($(this));
    });

    inlines.detach();
    orderMachine.append(inlines);

    inlines.each(function () {
      const ordering = $(".field-ordering input", this).val() || 1e9;
      this.style.order = ordering;
      ensureDraggable($(this));
    });

    inlines.not(".empty-form").each(function () {
      $(document).trigger("content-editor:activate", [$(this)]);
    });
  }

  function buildDropdown(contents, title) {
    const select = document.createElement("select");
    let idx = 0;

    if (title) select.options[idx++] = new Option(title, "", true);

    for (let i = 0; i < contents.length; i++) {
      // Option _values_ may either be the prefix (for plugins) or keys (for
      // regions)
      select.options[idx++] = new Option(
        contents[i].title,
        contents[i].prefix || contents[i].key
      );
    }
    return select;
  }

  // Hides plugins that are not allowed in this region
  function hideNotAllowedDropdown() {
    $(ContentEditor.machineControlSelect)
      .find("option")
      .each(function () {
        const $option = $(this);
        const allowed = pluginRegions[$option.val()];
        if (!allowed || $.inArray(ContentEditor.currentRegion, allowed) >= 0) {
          $option.show();
        } else {
          $option.hide();
        }
      });
  }

  // Hide not allowed plugin buttons
  // If buttons only checks this buttons, else checks all
  function hideNotAllowedPluginButtons(buttons) {
    buttons = buttons
      ? buttons
      : qsa(".control-unit.plugin-buttons .plugin-button");

    const region = ContentEditor.currentRegion;

    buttons.forEach(function (button) {
      const plugin = button.dataset.plugin;
      const regions = pluginRegions[plugin];

      button.style.display =
        !regions || regions.includes(region) ? "inline" : "none";
    });
  }

  // Fetch the inline type from id
  function getInlineType($inline) {
    const match = /^([a-z0-9_]+)-\d+$/g.exec($inline.attr("id"));
    if (match) {
      return match[1];
    }
    return null;
  }

  function attachMoveToRegionDropdown($inline) {
    // Filter allowed regions
    const inlineType = getInlineType($inline);
    const regions = [];
    for (let i = 0; i < ContentEditor.regions.length; i++) {
      if (
        (!inlineType ||
          !pluginRegions[inlineType] ||
          $.inArray(ContentEditor.regions[i].key, pluginRegions[inlineType]) >=
            0) &&
        ContentEditor.regions[i].key !== "_unknown_"
      ) {
        regions.push(ContentEditor.regions[i]);
      }
    }

    if (regions.length < 2) return;

    const controls = document.createElement("div"),
      select = buildDropdown(regions),
      regionInput = $inline.find(".field-region input");

    select.value = regionInput.val();
    controls.className = "inline-controls";
    controls.appendChild(select);
    $inline.append(controls);

    select.addEventListener("change", function () {
      $inline.attr("data-region", select.value);
      regionInput.val(select.value);
      hideInlinesFromOtherRegions();
      setBiggestOrdering($inline);
      reorderInlines();
    });
  }

  // Assing data-region to all inlines.
  // We also want to the data attribute to be visible to selectors (that's why we're using $.attr)
  function assignRegionDataAttribute() {
    orderMachine.find(".inline-related:not(.empty-form)").each(function () {
      const $this = $(this);
      let region = $this.find(".field-region input").val();

      if (!ContentEditor.regionsByKey[region]) {
        const spec = {
          key: "_unknown_",
          title: ContentEditor.messages.unknownRegion,
          inherited: false,
        };
        ContentEditor.regions.push(spec);
        ContentEditor.regionsByKey[spec.key] = spec;
        region = spec.key;
      }

      $this.attr("data-region", region);
      attachMoveToRegionDropdown($this);
    });
  }

  function setBiggestOrdering($row) {
    const orderings = [];
    orderMachine.find(".field-ordering input").each(function () {
      if (!isNaN(+this.value)) orderings.push(+this.value);
    });
    const ordering = 10 + Math.max.apply(null, orderings);
    $row.find(".field-ordering input").val(ordering);
    $row.css("order", ordering);
  }

  function insertBefore(row, before) {
    const beforeOrdering = +qs(".field-ordering input", before).value,
      beforeRows = [],
      afterRows = [];
    orderMachine.find(".inline-related:not(.empty-form)").each(function () {
      const thisOrderingField = qs(".field-ordering input", this);
      if (this != row && !isNaN(+thisOrderingField.value)) {
        if (+thisOrderingField.value >= beforeOrdering) {
          afterRows.push([this, thisOrderingField]);
        } else {
          beforeRows.push([this, thisOrderingField]);
        }
      }
    });
    beforeRows.sort(function (a, b) {
      return a[1].value - b[1].value;
    });
    afterRows.sort(function (a, b) {
      return a[1].value - b[1].value;
    });
    let rows = [].concat(beforeRows);
    rows.push([row, qs(".field-ordering input", row)]);
    rows = rows.concat(afterRows);
    for (let i = 0; i < rows.length; ++i) {
      const thisRow = rows[i];
      thisRow[1].value = thisRow[0].style.order = 10 * (1 + i);
    }
  }

  function hideInlinesFromOtherRegions() {
    const inlines = orderMachine.find(".inline-related:not(.empty-form)");
    inlines.addClass("content-editor-hidden");
    const shown = inlines.filter(
      '[data-region="' + ContentEditor.currentRegion + '"]'
    );
    machineEmptyMessage.addClass("hidden");
    if (shown.length) {
      shown.removeClass("content-editor-hidden");
    } else {
      machineEmptyMessage.removeClass("hidden");
    }
    machineEmptyMessage.text(
      ContentEditor.messages[
        ContentEditor.regionsByKey[ContentEditor.currentRegion].inherited
          ? "emptyInherited"
          : "empty"
      ]
    );
  }

  const pluginInlineGroups = (function selectPluginInlineGroups() {
    const selector = [];
    for (let i = 0; i < ContentEditor.plugins.length; i++) {
      selector.push("#" + ContentEditor.plugins[i].prefix + "-group");
    }
    return $(selector.join(", "));
  })();

  reorderInlines(pluginInlineGroups);
  pluginInlineGroups.hide();
  assignRegionDataAttribute();

  // Always move empty forms to the end, because new plugins are inserted
  // just before its empty form. Also, assign region data.
  $(document).on("formset:added", function newForm(event, $row, formsetName) {
    // Not one of our managed inlines?
    if (!ContentEditor.pluginsByPrefix[formsetName]) return;

    $row.find(".field-region input").val(ContentEditor.currentRegion);
    $row.find("h3 .inline_label").text(ContentEditor.messages.newItem);
    $row.attr("data-region", ContentEditor.currentRegion);

    setBiggestOrdering($row);
    attachMoveToRegionDropdown($row);
    ensureDraggable($row);

    machineEmptyMessage.addClass("hidden");

    $(document).trigger("content-editor:activate", [$row]);

    $row.find("input, select, textarea").first().focus();
  });

  $(document).on("formset:removed", function resetInlines(
    _event,
    _row,
    formsetName
  ) {
    // Not one of our managed inlines?
    if (!ContentEditor.pluginsByPrefix[formsetName]) return;

    if (
      !orderMachine.find(
        '.inline-related[data-region="' + ContentEditor.currentRegion + '"]'
      ).length
    ) {
      machineEmptyMessage.removeClass("hidden");
    }
    orderMachine
      .find(".inline-related.last-related:not(.empty-form)")
      .each(function () {
        $(document).trigger("content-editor:deactivate", [$(this)]);
      });

    // As soon as possible, but not sooner (let the inline.js code run to the end first)
    setTimeout(function () {
      orderMachine
        .find(".inline-related.last-related:not(.empty-form)")
        .each(function () {
          $(document).trigger("content-editor:activate", [$(this)]);
        });
    }, 0);
  });

  // Initialize tabs and currentRegion.
  (function () {
    const tabContainer = $(".tabs.regions");
    for (let i = 0; i < ContentEditor.regions.length; i++) {
      const t = document.createElement("h2");
      t.className = "tab";
      t.textContent = ContentEditor.regions[i].title;
      t.setAttribute("data-region", ContentEditor.regions[i].key);
      tabContainer.append(t);
    }

    const tabs = tabContainer.find("h2");
    tabs.on("click", function () {
      ContentEditor.currentRegion = $(this).data("region");
      tabs
        .removeClass("active")
        .filter('[data-region="' + ContentEditor.currentRegion + '"]')
        .addClass("active");
      hideInlinesFromOtherRegions();
      window.location.hash = "tab_" + ContentEditor.currentRegion;

      // Make sure only allowed plugins are in select
      hideNotAllowedDropdown();
      hideNotAllowedPluginButtons();
    });

    // Restore tab if location hash matches.
    let tab;
    if (
      window.location.hash &&
      (tab = tabs.filter(
        '[data-region="' + window.location.hash.substr(5) + '"]'
      )) &&
      tab.length
    ) {
      tab.click();
    } else {
      tabs.eq(0).click();
    }

    tabContainer.find(".toggle input").on("change", function () {
      $(".order-machine .inline-related").toggleClass(
        "collapsed",
        this.checked
      );
    });
  })();

  $(document)
    .on("content-editor:deactivate", function (event, row) {
      row.find("fieldset").addClass("content-editor-hidden");
    })
    .on("content-editor:activate", function (event, row) {
      row.find("fieldset").removeClass("content-editor-hidden");
    });

  // Hide fieldsets of to-be-deleted inlines.
  orderMachine.on(
    "click",
    ".delete>input[type=checkbox]",
    function toggleForDeletionClass( {
      this.closest(".inline-related").classList.toggle(
        "for-deletion",
        this.checked
      );
    }
  );

  orderMachine.on("dblclick", "h3", function toggleCollapsed(e) {
    e.preventDefault();
    this.closest(".inline-related").classList.toggle("collapsed");
  });

  // Try to keep the current region tab (location hash).
  $("form").submit(function () {
    const form = $(this);
    form.attr("action", (form.attr("action") || "") + window.location.hash);
    return true;
  });

  (function buildPluginDropdown() {
    const select = buildDropdown(
      ContentEditor.plugins,
      ContentEditor.messages.createNew
    );
    select.addEventListener("change", function () {
      ContentEditor.addContent(select.value);
      select.value = "";
    });
    ContentEditor.machineControlSelect = select;
    hideNotAllowedDropdown();
    $(select)
      .appendTo(".machine-control")
      .wrap('

');
  })();

  $(document).trigger("content-editor:ready");
});
<commit_msg>Add a missing parenthesis<commit_after>/* global django,ContentEditor */

django.jQuery(function ($) {
  const context = document.getElementById("content-editor-context");
  if (!context) return;

  function qs(sel, ctx = document) {
    return ctx.querySelector(sel);
  }
  function qsa(sel, ctx = document) {
    return Array.prototype.slice.call(ctx.querySelectorAll(sel));
  }

  window.ContentEditor = {
    addContent: function addContent(prefix) {
      $("#" + prefix + "-group .add-row a").click();
    },
    addPluginButton: function addPluginButton(prefix, html) {
      const plugin =
        ContentEditor.pluginsByPrefix[prefix] ||
        ContentEditor.pluginsByPrefix[prefix + "_set"];
      if (!plugin) return;

      let unit = qs(".control-unit.plugin-buttons");
      if (!unit) {
        unit = document.createElement("div");
        unit.className = "control-unit plugin-buttons";
        const mc = qs(".machine-control");
        mc.insertBefore(unit, mc.firstChild);
      }

      const button = document.createElement("a");
      button.setAttribute("data-plugin", plugin.prefix);
      button.className = "plugin-button";
      button.title = plugin.title;
      button.addEventListener("click", function () {
        ContentEditor.addContent(plugin.prefix);
      });
      button.innerHTML = html;

      unit.appendChild(button);

      hideNotAllowedPluginButtons([button]);
    },
  };

  $.extend(window.ContentEditor, JSON.parse(context.dataset.context));

  ContentEditor.pluginsByPrefix = {};
  ContentEditor.pluginsByKey = {};
  ContentEditor.prefixToKey = {};
  for (let i = 0; i < ContentEditor.plugins.length; ++i) {
    ContentEditor.pluginsByPrefix[ContentEditor.plugins[i].prefix] =
      ContentEditor.plugins[i];
  }
  ContentEditor.regionsByKey = {};
  for (let i = 0; i < ContentEditor.regions.length; ++i) {
    ContentEditor.regionsByKey[ContentEditor.regions[i].key] =
      ContentEditor.regions[i];
  }

  // Add basic structure. There is always at least one inline group if
  // we even have any plugins.
  $(".inline-group:first").before(
    '
' +
      '<input type="checkbox" /> ' +
      ContentEditor.messages.toggle +
      "" +
      "
" +
      '
' +
      '

' +
      "
"
  );

  const orderMachine = $(".order-machine"),
    machineEmptyMessage = $('
')
      .text(ContentEditor.messages.empty)
      .appendTo(orderMachine);

  // Pre map plugin regions
  const pluginRegions = (function () {
    const result = {};
    const plugins = ContentEditor.plugins;
    for (let i = 0; i < plugins.length; i++) {
      result[plugins[i].prefix] = plugins[i].regions;
    }
    return result;
  })();

  function ensureDraggable(arg) {
    if (arg.hasClass("empty-form") || arg.hasClass("fs-draggable")) return;

    const inline = arg[0];

    inline.addEventListener("dragstart", function (e) {
      // window.__fs_dragging = inline;
      window.__fs_dragging = e.target.closest(".inline-related");
      window.__fs_dragging.classList.add("fs-dragging");

      e.dataTransfer.dropEffect = "move";
      e.dataTransfer.effectAllowed = "move";
      try {
        e.dataTransfer.setData("text/plain", "");
      } catch (e) {
        // IE11 needs this.
      }
    });
    inline.addEventListener("dragend", function () {
      $(".fs-dragging").removeClass("fs-dragging");
      $(".fs-dragover").removeClass("fs-dragover");
    });
    inline.addEventListener(
      "dragover",
      function (e) {
        e.preventDefault();
        $(".fs-dragover").removeClass("fs-dragover");
        e.target.closest(".inline-related").classList.add("fs-dragover");
      },
      true
    );
    inline.addEventListener("drop", function (e) {
      e.preventDefault();
      insertBefore(window.__fs_dragging, e.target.closest(".inline-related"));
    });

    arg.find(">h3").attr("draggable", true);
    arg.addClass("fs-draggable");
  }

  function reorderInlines(context) {
    context = context || orderMachine;
    const inlines = context.find(".inline-related");
    inlines.not(".empty-form").each(function () {
      $(document).trigger("content-editor:deactivate", [$(this)]);

      ensureDraggable($(this));
    });

    inlines.detach();
    orderMachine.append(inlines);

    inlines.each(function () {
      const ordering = $(".field-ordering input", this).val() || 1e9;
      this.style.order = ordering;
      ensureDraggable($(this));
    });

    inlines.not(".empty-form").each(function () {
      $(document).trigger("content-editor:activate", [$(this)]);
    });
  }

  function buildDropdown(contents, title) {
    const select = document.createElement("select");
    let idx = 0;

    if (title) select.options[idx++] = new Option(title, "", true);

    for (let i = 0; i < contents.length; i++) {
      // Option _values_ may either be the prefix (for plugins) or keys (for
      // regions)
      select.options[idx++] = new Option(
        contents[i].title,
        contents[i].prefix || contents[i].key
      );
    }
    return select;
  }

  // Hides plugins that are not allowed in this region
  function hideNotAllowedDropdown() {
    $(ContentEditor.machineControlSelect)
      .find("option")
      .each(function () {
        const $option = $(this);
        const allowed = pluginRegions[$option.val()];
        if (!allowed || $.inArray(ContentEditor.currentRegion, allowed) >= 0) {
          $option.show();
        } else {
          $option.hide();
        }
      });
  }

  // Hide not allowed plugin buttons
  // If buttons only checks this buttons, else checks all
  function hideNotAllowedPluginButtons(buttons) {
    buttons = buttons
      ? buttons
      : qsa(".control-unit.plugin-buttons .plugin-button");

    const region = ContentEditor.currentRegion;

    buttons.forEach(function (button) {
      const plugin = button.dataset.plugin;
      const regions = pluginRegions[plugin];

      button.style.display =
        !regions || regions.includes(region) ? "inline" : "none";
    });
  }

  // Fetch the inline type from id
  function getInlineType($inline) {
    const match = /^([a-z0-9_]+)-\d+$/g.exec($inline.attr("id"));
    if (match) {
      return match[1];
    }
    return null;
  }

  function attachMoveToRegionDropdown($inline) {
    // Filter allowed regions
    const inlineType = getInlineType($inline);
    const regions = [];
    for (let i = 0; i < ContentEditor.regions.length; i++) {
      if (
        (!inlineType ||
          !pluginRegions[inlineType] ||
          $.inArray(ContentEditor.regions[i].key, pluginRegions[inlineType]) >=
            0) &&
        ContentEditor.regions[i].key !== "_unknown_"
      ) {
        regions.push(ContentEditor.regions[i]);
      }
    }

    if (regions.length < 2) return;

    const controls = document.createElement("div"),
      select = buildDropdown(regions),
      regionInput = $inline.find(".field-region input");

    select.value = regionInput.val();
    controls.className = "inline-controls";
    controls.appendChild(select);
    $inline.append(controls);

    select.addEventListener("change", function () {
      $inline.attr("data-region", select.value);
      regionInput.val(select.value);
      hideInlinesFromOtherRegions();
      setBiggestOrdering($inline);
      reorderInlines();
    });
  }

  // Assing data-region to all inlines.
  // We also want to the data attribute to be visible to selectors (that's why we're using $.attr)
  function assignRegionDataAttribute() {
    orderMachine.find(".inline-related:not(.empty-form)").each(function () {
      const $this = $(this);
      let region = $this.find(".field-region input").val();

      if (!ContentEditor.regionsByKey[region]) {
        const spec = {
          key: "_unknown_",
          title: ContentEditor.messages.unknownRegion,
          inherited: false,
        };
        ContentEditor.regions.push(spec);
        ContentEditor.regionsByKey[spec.key] = spec;
        region = spec.key;
      }

      $this.attr("data-region", region);
      attachMoveToRegionDropdown($this);
    });
  }

  function setBiggestOrdering($row) {
    const orderings = [];
    orderMachine.find(".field-ordering input").each(function () {
      if (!isNaN(+this.value)) orderings.push(+this.value);
    });
    const ordering = 10 + Math.max.apply(null, orderings);
    $row.find(".field-ordering input").val(ordering);
    $row.css("order", ordering);
  }

  function insertBefore(row, before) {
    const beforeOrdering = +qs(".field-ordering input", before).value,
      beforeRows = [],
      afterRows = [];
    orderMachine.find(".inline-related:not(.empty-form)").each(function () {
      const thisOrderingField = qs(".field-ordering input", this);
      if (this != row && !isNaN(+thisOrderingField.value)) {
        if (+thisOrderingField.value >= beforeOrdering) {
          afterRows.push([this, thisOrderingField]);
        } else {
          beforeRows.push([this, thisOrderingField]);
        }
      }
    });
    beforeRows.sort(function (a, b) {
      return a[1].value - b[1].value;
    });
    afterRows.sort(function (a, b) {
      return a[1].value - b[1].value;
    });
    let rows = [].concat(beforeRows);
    rows.push([row, qs(".field-ordering input", row)]);
    rows = rows.concat(afterRows);
    for (let i = 0; i < rows.length; ++i) {
      const thisRow = rows[i];
      thisRow[1].value = thisRow[0].style.order = 10 * (1 + i);
    }
  }

  function hideInlinesFromOtherRegions() {
    const inlines = orderMachine.find(".inline-related:not(.empty-form)");
    inlines.addClass("content-editor-hidden");
    const shown = inlines.filter(
      '[data-region="' + ContentEditor.currentRegion + '"]'
    );
    machineEmptyMessage.addClass("hidden");
    if (shown.length) {
      shown.removeClass("content-editor-hidden");
    } else {
      machineEmptyMessage.removeClass("hidden");
    }
    machineEmptyMessage.text(
      ContentEditor.messages[
        ContentEditor.regionsByKey[ContentEditor.currentRegion].inherited
          ? "emptyInherited"
          : "empty"
      ]
    );
  }

  const pluginInlineGroups = (function selectPluginInlineGroups() {
    const selector = [];
    for (let i = 0; i < ContentEditor.plugins.length; i++) {
      selector.push("#" + ContentEditor.plugins[i].prefix + "-group");
    }
    return $(selector.join(", "));
  })();

  reorderInlines(pluginInlineGroups);
  pluginInlineGroups.hide();
  assignRegionDataAttribute();

  // Always move empty forms to the end, because new plugins are inserted
  // just before its empty form. Also, assign region data.
  $(document).on("formset:added", function newForm(event, $row, formsetName) {
    // Not one of our managed inlines?
    if (!ContentEditor.pluginsByPrefix[formsetName]) return;

    $row.find(".field-region input").val(ContentEditor.currentRegion);
    $row.find("h3 .inline_label").text(ContentEditor.messages.newItem);
    $row.attr("data-region", ContentEditor.currentRegion);

    setBiggestOrdering($row);
    attachMoveToRegionDropdown($row);
    ensureDraggable($row);

    machineEmptyMessage.addClass("hidden");

    $(document).trigger("content-editor:activate", [$row]);

    $row.find("input, select, textarea").first().focus();
  });

  $(document).on("formset:removed", function resetInlines(
    _event,
    _row,
    formsetName
  ) {
    // Not one of our managed inlines?
    if (!ContentEditor.pluginsByPrefix[formsetName]) return;

    if (
      !orderMachine.find(
        '.inline-related[data-region="' + ContentEditor.currentRegion + '"]'
      ).length
    ) {
      machineEmptyMessage.removeClass("hidden");
    }
    orderMachine
      .find(".inline-related.last-related:not(.empty-form)")
      .each(function () {
        $(document).trigger("content-editor:deactivate", [$(this)]);
      });

    // As soon as possible, but not sooner (let the inline.js code run to the end first)
    setTimeout(function () {
      orderMachine
        .find(".inline-related.last-related:not(.empty-form)")
        .each(function () {
          $(document).trigger("content-editor:activate", [$(this)]);
        });
    }, 0);
  });

  // Initialize tabs and currentRegion.
  (function () {
    const tabContainer = $(".tabs.regions");
    for (let i = 0; i < ContentEditor.regions.length; i++) {
      const t = document.createElement("h2");
      t.className = "tab";
      t.textContent = ContentEditor.regions[i].title;
      t.setAttribute("data-region", ContentEditor.regions[i].key);
      tabContainer.append(t);
    }

    const tabs = tabContainer.find("h2");
    tabs.on("click", function () {
      ContentEditor.currentRegion = $(this).data("region");
      tabs
        .removeClass("active")
        .filter('[data-region="' + ContentEditor.currentRegion + '"]')
        .addClass("active");
      hideInlinesFromOtherRegions();
      window.location.hash = "tab_" + ContentEditor.currentRegion;

      // Make sure only allowed plugins are in select
      hideNotAllowedDropdown();
      hideNotAllowedPluginButtons();
    });

    // Restore tab if location hash matches.
    let tab;
    if (
      window.location.hash &&
      (tab = tabs.filter(
        '[data-region="' + window.location.hash.substr(5) + '"]'
      )) &&
      tab.length
    ) {
      tab.click();
    } else {
      tabs.eq(0).click();
    }

    tabContainer.find(".toggle input").on("change", function () {
      $(".order-machine .inline-related").toggleClass(
        "collapsed",
        this.checked
      );
    });
  })();

  $(document)
    .on("content-editor:deactivate", function (event, row) {
      row.find("fieldset").addClass("content-editor-hidden");
    })
    .on("content-editor:activate", function (event, row) {
      row.find("fieldset").removeClass("content-editor-hidden");
    });

  // Hide fieldsets of to-be-deleted inlines.
  orderMachine.on(
    "click",
    ".delete>input[type=checkbox]",
    function toggleForDeletionClass() {
      this.closest(".inline-related").classList.toggle(
        "for-deletion",
        this.checked
      );
    }
  );

  orderMachine.on("dblclick", "h3", function toggleCollapsed(e) {
    e.preventDefault();
    this.closest(".inline-related").classList.toggle("collapsed");
  });

  // Try to keep the current region tab (location hash).
  $("form").submit(function () {
    const form = $(this);
    form.attr("action", (form.attr("action") || "") + window.location.hash);
    return true;
  });

  (function buildPluginDropdown() {
    const select = buildDropdown(
      ContentEditor.plugins,
      ContentEditor.messages.createNew
    );
    select.addEventListener("change", function () {
      ContentEditor.addContent(select.value);
      select.value = "";
    });
    ContentEditor.machineControlSelect = select;
    hideNotAllowedDropdown();
    $(select)
      .appendTo(".machine-control")
      .wrap('

');
  })();

  $(document).trigger("content-editor:ready");
});
<|endoftext|>


<commit_before>import * as path from 'path';

import { env } from '../../src/base/';
import * as FileSystem from '../../src/base/shared/FileSystem';

let files;

if (env === 'development') {
  files = {
    app: { js: '/app.js' },
    vendor: { js: '/dlls/vendor.dll.js' },
  };
} else {
  const assetsManifest = path.resolve(__dirname, '../../dist/webpack-assets.json');
  files = JSON.parse(FileSystem.readFile(assetsManifest, 'utf8'));
}

export function getScripts(file) {
  const scriptPath = `/assets/${files[file].js}`;
  return `<script src="${scriptPath}"></script>`;
}

export function getStyles(file) {
  const cssPath = files[file].css;
  return (env === 'production') ? `<link rel="stylesheet" href="${cssPath}">` : '';
}
<commit_msg>Fix style path<commit_after>import * as path from 'path';

import { env } from '../../src/base/';
import * as FileSystem from '../../src/base/shared/FileSystem';

let files;

if (env === 'development') {
  files = {
    app: { js: '/app.js' },
    vendor: { js: '/dlls/vendor.dll.js' },
  };
} else {
  const assetsManifest = path.resolve(__dirname, '../../dist/webpack-assets.json');
  files = JSON.parse(FileSystem.readFile(assetsManifest, 'utf8'));
}

export function getScripts(file) {
  const scriptPath = `/assets/${files[file].js}`;
  return `<script src="${scriptPath}"></script>`;
}

export function getStyles(file) {
  const cssPath = files[file].css;
  return (env === 'production') ? `<link rel="stylesheet" href="/assets/${cssPath}">` : '';
}
<|endoftext|>


<commit_before>function Tag(attributes) {
  this.id = attributes.id
  this.name = attributes.name
}
<commit_msg>Render tags list.<commit_after>function Tag(attributes) {
  this.id = attributes.id
  this.name = attributes.name
}

Tag.renderLI = function (tag) {
  return `<li><a href="/tags/${tag.id}">${tag.name}</a></li>`
}
<|endoftext|>


<commit_before>iD.ui.preset.localized = function(field, context) {
    var dispatch = d3.dispatch('change', 'input'),
        wikipedia = iD.wikipedia(),
        input, localizedInputs, wikiTitles,
        entity;

    function i(selection) {
        input = selection.selectAll('.localized-main')
            .data([0]);

        input.enter().append('input')
            .attr('type', 'text')
            .attr('id', 'preset-input-' + field.id)
            .attr('class', 'localized-main')
            .attr('placeholder', field.placeholder());

        if (field.id === 'name') {
            var preset = context.presets().match(entity, context.graph());
            input.call(d3.combobox().fetcher(
                iD.util.SuggestNames(preset, iD.data.suggestions)
            ));
        }

        input
            .on('input', change(true))
            .on('blur', change())
            .on('change', change());

        var translateButton = selection.selectAll('.localized-add')
            .data([0]);

        translateButton.enter()
            .append('button')
            .attr('class', 'button-input-action localized-add minor')
            .call(iD.svg.Icon('#icon-plus'))
            .call(bootstrap.tooltip()
                .title(t('translate.translate'))
                .placement('left'));

        translateButton
            .on('click', addBlank);

        localizedInputs = selection.selectAll('.localized-wrap')
            .data([0]);

        localizedInputs.enter().append('div')
            .attr('class', 'localized-wrap');
    }

    function addBlank() {
        d3.event.preventDefault();
        var data = localizedInputs.selectAll('div.entry').data();
        data.push({ lang: '', value: '' });
        localizedInputs.call(render, data);
    }

    function change(onInput) {
        return function() {
            var t = {};
            t[field.key] = d3.select(this).value() || undefined;
            dispatch.change(t, onInput);
        };
    }

    function key(lang) { return field.key + ':' + lang; }

    function changeLang(d) {
        var lang = d3.select(this).value(),
            t = {},
            language = _.find(iD.data.wikipedia, function(d) {
                return d[0].toLowerCase() === lang.toLowerCase() ||
                    d[1].toLowerCase() === lang.toLowerCase();
            });

        if (language) lang = language[2];

        if (d.lang && d.lang !== lang) {
            t[key(d.lang)] = undefined;
        }

        var value = d3.select(this.parentNode)
            .selectAll('.localized-value')
            .value();

        if (lang && value) {
            t[key(lang)] = value;
        } else if (lang && wikiTitles && wikiTitles[d.lang]) {
            t[key(lang)] = wikiTitles[d.lang];
        }

        d.lang = lang;
        dispatch.change(t);
    }

    function changeValue(d) {
        if (!d.lang) return;
        var t = {};
        t[key(d.lang)] = d3.select(this).value() || undefined;
        dispatch.change(t);
    }

    function fetcher(value, cb) {
        var v = value.toLowerCase();

        cb(iD.data.wikipedia.filter(function(d) {
            return d[0].toLowerCase().indexOf(v) >= 0 ||
            d[1].toLowerCase().indexOf(v) >= 0 ||
            d[2].toLowerCase().indexOf(v) >= 0;
        }).map(function(d) {
            return { value: d[1] };
        }));
    }

    function render(selection, data) {
        var wraps = selection.selectAll('div.entry').
            data(data, function(d) { return d.lang; });

        var innerWrap = wraps.enter()
            .insert('div', ':first-child');

        innerWrap.attr('class', 'entry')
            .each(function() {
                var wrap = d3.select(this);
                var langcombo = d3.combobox().fetcher(fetcher);

                var label = wrap.append('label')
                    .attr('class','form-label')
                    .text(t('translate.localized_translation_label'))
                    .attr('for','localized-lang');

                label.append('button')
                    .attr('class', 'minor remove')
                    .on('click', function(d){
                        d3.event.preventDefault();
                        var t = {};
                        t[key(d.lang)] = undefined;
                        dispatch.change(t);
                        d3.select(this.parentNode.parentNode)
                            .style('top','0')
                            .style('max-height','240px')
                            .transition()
                            .style('opacity', '0')
                            .style('max-height','0px')
                            .remove();
                    })
                    .call(iD.svg.Icon('#operation-delete'));

                wrap.append('input')
                    .attr('class', 'localized-lang')
                    .attr('type', 'text')
                    .attr('placeholder',t('translate.localized_translation_language'))
                    .on('blur', changeLang)
                    .on('change', changeLang)
                    .call(langcombo);

                wrap.append('input')
                    .on('blur', changeValue)
                    .on('change', changeValue)
                    .attr('type', 'text')
                    .attr('placeholder', t('translate.localized_translation_name'))
                    .attr('class', 'localized-value');
            });

        innerWrap
            .style('margin-top', '0px')
            .style('max-height', '0px')
            .style('opacity', '0')
            .transition()
            .duration(200)
            .style('margin-top', '10px')
            .style('max-height', '240px')
            .style('opacity', '1')
            .each('end', function() {
                d3.select(this)
                    .style('max-height', '')
                    .style('overflow', 'visible');
            });

        wraps.exit()
            .transition()
            .duration(200)
            .style('max-height','0px')
            .style('opacity', '0')
            .style('top','-10px')
            .remove();

        var entry = selection.selectAll('.entry');

        entry.select('.localized-lang')
            .value(function(d) {
                var lang = _.find(iD.data.wikipedia, function(lang) { return lang[2] === d.lang; });
                return lang ? lang[1] : d.lang;
            });

        entry.select('.localized-value')
            .value(function(d) { return d.value; });
    }

    i.tags = function(tags) {
        // Fetch translations from wikipedia
        if (tags.wikipedia && !wikiTitles) {
            wikiTitles = {};
            var wm = tags.wikipedia.match(/([^:]+):(.+)/);
            if (wm && wm[0] && wm[1]) {
                wikipedia.translations(wm[1], wm[2], function(d) {
                    wikiTitles = d;
                });
            }
        }

        input.value(tags[field.key] || '');

        var postfixed = [], k, m;
        for (k in tags) {
            m = k.match(/^(.*):([a-zA-Z_-]+)$/);
            if (m && m[1] === field.key && m[2]) {
                postfixed.push({ lang: m[2], value: tags[k] });
            }
        }

        localizedInputs.call(render, postfixed.reverse());
    };

    i.focus = function() {
        input.node().focus();
    };

    i.entity = function(_) {
        entity = _;
    };

    return d3.rebind(i, dispatch, 'on');
};
<commit_msg>Use user language for default translated names<commit_after>iD.ui.preset.localized = function(field, context) {
    var dispatch = d3.dispatch('change', 'input'),
        wikipedia = iD.wikipedia(),
        input, localizedInputs, wikiTitles,
        entity;

    function i(selection) {
        input = selection.selectAll('.localized-main')
            .data([0]);

        input.enter().append('input')
            .attr('type', 'text')
            .attr('id', 'preset-input-' + field.id)
            .attr('class', 'localized-main')
            .attr('placeholder', field.placeholder());

        if (field.id === 'name') {
            var preset = context.presets().match(entity, context.graph());
            input.call(d3.combobox().fetcher(
                iD.util.SuggestNames(preset, iD.data.suggestions)
            ));
        }

        input
            .on('input', change(true))
            .on('blur', change())
            .on('change', change());

        var translateButton = selection.selectAll('.localized-add')
            .data([0]);

        translateButton.enter()
            .append('button')
            .attr('class', 'button-input-action localized-add minor')
            .call(iD.svg.Icon('#icon-plus'))
            .call(bootstrap.tooltip()
                .title(t('translate.translate'))
                .placement('left'));

        translateButton
            .on('click', addNew);

        localizedInputs = selection.selectAll('.localized-wrap')
            .data([0]);

        localizedInputs.enter().append('div')
            .attr('class', 'localized-wrap');
    }

    function addNew() {
        d3.event.preventDefault();
        var data = localizedInputs.selectAll('div.entry').data();
        var defaultLang = iD.detect().locale.toLowerCase().split('-')[0];
        var langExists = _.find(data, function(datum) { return datum.lang === defaultLang;});
        var isLangEn = defaultLang.indexOf('en') > -1;
        if (isLangEn || langExists) {
          defaultLang = '';
        }
        data.push({ lang: defaultLang, value: '' });
        localizedInputs.call(render, data);
    }

    function change(onInput) {
        return function() {
            var t = {};
            t[field.key] = d3.select(this).value() || undefined;
            dispatch.change(t, onInput);
        };
    }

    function key(lang) { return field.key + ':' + lang; }

    function changeLang(d) {
        var lang = d3.select(this).value(),
            t = {},
            language = _.find(iD.data.wikipedia, function(d) {
                return d[0].toLowerCase() === lang.toLowerCase() ||
                    d[1].toLowerCase() === lang.toLowerCase();
            });

        if (language) lang = language[2];

        if (d.lang && d.lang !== lang) {
            t[key(d.lang)] = undefined;
        }

        var value = d3.select(this.parentNode)
            .selectAll('.localized-value')
            .value();

        if (lang && value) {
            t[key(lang)] = value;
        } else if (lang && wikiTitles && wikiTitles[d.lang]) {
            t[key(lang)] = wikiTitles[d.lang];
        }

        d.lang = lang;
        dispatch.change(t);
    }

    function changeValue(d) {
        if (!d.lang) return;
        var t = {};
        t[key(d.lang)] = d3.select(this).value() || undefined;
        dispatch.change(t);
    }

    function fetcher(value, cb) {
        var v = value.toLowerCase();

        cb(iD.data.wikipedia.filter(function(d) {
            return d[0].toLowerCase().indexOf(v) >= 0 ||
            d[1].toLowerCase().indexOf(v) >= 0 ||
            d[2].toLowerCase().indexOf(v) >= 0;
        }).map(function(d) {
            return { value: d[1] };
        }));
    }

    function render(selection, data) {
        var wraps = selection.selectAll('div.entry').
            data(data, function(d) { return d.lang; });

        var innerWrap = wraps.enter()
            .insert('div', ':first-child');

        innerWrap.attr('class', 'entry')
            .each(function() {
                var wrap = d3.select(this);
                var langcombo = d3.combobox().fetcher(fetcher);

                var label = wrap.append('label')
                    .attr('class','form-label')
                    .text(t('translate.localized_translation_label'))
                    .attr('for','localized-lang');

                label.append('button')
                    .attr('class', 'minor remove')
                    .on('click', function(d){
                        d3.event.preventDefault();
                        var t = {};
                        t[key(d.lang)] = undefined;
                        dispatch.change(t);
                        d3.select(this.parentNode.parentNode)
                            .style('top','0')
                            .style('max-height','240px')
                            .transition()
                            .style('opacity', '0')
                            .style('max-height','0px')
                            .remove();
                    })
                    .call(iD.svg.Icon('#operation-delete'));

                wrap.append('input')
                    .attr('class', 'localized-lang')
                    .attr('type', 'text')
                    .attr('placeholder',t('translate.localized_translation_language'))
                    .on('blur', changeLang)
                    .on('change', changeLang)
                    .call(langcombo);

                wrap.append('input')
                    .on('blur', changeValue)
                    .on('change', changeValue)
                    .attr('type', 'text')
                    .attr('placeholder', t('translate.localized_translation_name'))
                    .attr('class', 'localized-value');
            });

        innerWrap
            .style('margin-top', '0px')
            .style('max-height', '0px')
            .style('opacity', '0')
            .transition()
            .duration(200)
            .style('margin-top', '10px')
            .style('max-height', '240px')
            .style('opacity', '1')
            .each('end', function() {
                d3.select(this)
                    .style('max-height', '')
                    .style('overflow', 'visible');
            });

        wraps.exit()
            .transition()
            .duration(200)
            .style('max-height','0px')
            .style('opacity', '0')
            .style('top','-10px')
            .remove();

        var entry = selection.selectAll('.entry');

        entry.select('.localized-lang')
            .value(function(d) {
                var lang = _.find(iD.data.wikipedia, function(lang) { return lang[2] === d.lang; });
                return lang ? lang[1] : d.lang;
            });

        entry.select('.localized-value')
            .value(function(d) { return d.value; });
    }

    i.tags = function(tags) {
        // Fetch translations from wikipedia
        if (tags.wikipedia && !wikiTitles) {
            wikiTitles = {};
            var wm = tags.wikipedia.match(/([^:]+):(.+)/);
            if (wm && wm[0] && wm[1]) {
                wikipedia.translations(wm[1], wm[2], function(d) {
                    wikiTitles = d;
                });
            }
        }

        input.value(tags[field.key] || '');

        var postfixed = [], k, m;
        for (k in tags) {
            m = k.match(/^(.*):([a-zA-Z_-]+)$/);
            if (m && m[1] === field.key && m[2]) {
                postfixed.push({ lang: m[2], value: tags[k] });
            }
        }

        localizedInputs.call(render, postfixed.reverse());
    };

    i.focus = function() {
        input.node().focus();
    };

    i.entity = function(_) {
        entity = _;
    };

    return d3.rebind(i, dispatch, 'on');
};
<|endoftext|>


<commit_before>/* global django,ContentEditor */

/* Polyfilling a bit */
if (!Element.prototype.matches)
  Element.prototype.matches =
    Element.prototype.msMatchesSelector ||
    Element.prototype.webkitMatchesSelector;

if (!Element.prototype.closest) {
  Element.prototype.closest = function (s) {
    var el = this;
    if (!document.documentElement.contains(el)) return null;
    do {
      if (el.matches(s)) return el;
      el = el.parentElement || el.parentNode;
    } while (el !== null && el.nodeType === 1);
    return null;
  };
}
/* Polyfill end */

django.jQuery(function ($) {
  var context = document.getElementById("content-editor-context");
  if (!context) return;

  window.ContentEditor = {
    addContent: function addContent(prefix) {
      $("#" + prefix + "-group .add-row a").click();
    },
    addPluginButton: function addPluginButton(prefix, html) {
      var plugin = ContentEditor.pluginsByPrefix[prefix];
      if (!plugin) return;

      var unit = document.querySelector(".control-unit.plugin-buttons");
      if (!unit) {
        unit = document.createElement("div");
        unit.className = "control-unit plugin-buttons";
        var mc = document.querySelector(".machine-control");
        mc.insertBefore(unit, mc.firstChild);
      }

      var button = document.createElement("a");
      var $button = $(button);
      $button.data("plugin", plugin.prefix);
      button.className = "plugin-button";
      button.title = plugin.title;
      button.addEventListener("click", function () {
        ContentEditor.addContent(plugin.prefix);
      });
      button.innerHTML = html;

      unit.appendChild(button);

      hideNotAllowedPluginButtons($button);
    },
  };

  // .dataset.context instead of getAttribute would be nicer
  $.extend(
    window.ContentEditor,
    JSON.parse(context.getAttribute("data-context"))
  );

  var i;
  ContentEditor.pluginsByPrefix = {}
  ContentEditor.pluginsByKey = {};
  ContentEditor.prefixToKey = {};
  for (i = 0; i < ContentEditor.plugins.length; ++i) {
    ContentEditor.pluginsByPrefix[ContentEditor.plugins[i].prefix] =
      ContentEditor.plugins[i]
  }
  ContentEditor.regionsByKey = {};
  for (i = 0; i < ContentEditor.regions.length; ++i) {
    ContentEditor.regionsByKey[ContentEditor.regions[i].key] =
      ContentEditor.regions[i];
  }

  // Add basic structure. There is always at least one inline group if
  // we even have any plugins.
  $(".inline-group:first").before(
    '
' +
      '<input type="checkbox" /> ' +
      ContentEditor.messages.toggle +
      "" +
      "
" +
      '
' +
      '

' +
      "
"
  );

  var orderMachine = $(".order-machine"),
    machineEmptyMessage = $('
')
      .text(ContentEditor.messages.empty)
      .appendTo(orderMachine);

  // Pre map plugin regions
  var pluginRegions = (function () {
    var result = {};
    var plugins = ContentEditor.plugins;
    for (var i = 0; i < plugins.length; i++) {
      result[plugins[i].prefix] = plugins[i].regions;
    }
    return result;
  })();

  function ensureDraggable(arg) {
    if (arg.hasClass("empty-form") || arg.hasClass("fs-draggable")) return;

    var inline = arg[0];

    inline.addEventListener("dragstart", function (e) {
      // window.__fs_dragging = inline;
      window.__fs_dragging = e.target.closest(".inline-related");
      window.__fs_dragging.classList.add("fs-dragging");

      e.dataTransfer.dropEffect = "move";
      e.dataTransfer.effectAllowed = "move";
      try {
        e.dataTransfer.setData("text/plain", "");
      } catch (e) {
        // IE11 needs this.
      }
    });
    inline.addEventListener("dragend", function () {
      $(".fs-dragging").removeClass("fs-dragging");
      $(".fs-dragover").removeClass("fs-dragover");
    });
    inline.addEventListener(
      "dragover",
      function (e) {
        e.preventDefault();
        $(".fs-dragover").removeClass("fs-dragover");
        e.target.closest(".inline-related").classList.add("fs-dragover");
      },
      true
    );
    inline.addEventListener("drop", function (e) {
      e.preventDefault();
      insertBefore(window.__fs_dragging, e.target.closest(".inline-related"));
    });

    arg.find(">h3").attr("draggable", true);
    arg.addClass("fs-draggable");
  }

  function reorderInlines(context) {
    context = context || orderMachine;
    var inlines = context.find(".inline-related");
    inlines.not(".empty-form").each(function () {
      $(document).trigger("content-editor:deactivate", [$(this)]);

      ensureDraggable($(this));
    });

    inlines.detach();
    orderMachine.append(inlines);

    inlines.each(function () {
      var ordering = $(".field-ordering input", this).val() || 1e9;
      this.style.order = ordering;
      ensureDraggable($(this));
    });

    inlines.not(".empty-form").each(function () {
      $(document).trigger("content-editor:activate", [$(this)]);
    });
  }

  function buildDropdown(contents, title) {
    var select = document.createElement("select"),
      idx = 0;

    if (title) select.options[idx++] = new Option(title, "", true);

    for (var i = 0; i < contents.length; i++) {
      select.options[idx++] = new Option(contents[i].title, contents[i].prefix);
    }
    return select;
  }

  // Hides plugins that are not allowed in this region
  function hideNotAllowedDropdown() {
    $(ContentEditor.machineControlSelect)
      .find("option")
      .each(function () {
        var $option = $(this);
        var allowed = pluginRegions[$option.val()];
        if (!allowed || $.inArray(ContentEditor.currentRegion, allowed) >= 0) {
          $option.show();
        } else {
          $option.hide();
        }
      });
  }

  // Hide not allowed plugin buttons
  // If $buttons only checks this buttons, else checks all
  function hideNotAllowedPluginButtons($buttons) {
    $buttons = $buttons
      ? $buttons
      : $(".control-unit.plugin-buttons .plugin-button");

    var region = ContentEditor.currentRegion;

    $buttons.each(function () {
      var $button = $(this);
      var plugin = $button.data("plugin");
      var allowed = pluginRegions[plugin];

      if (!allowed || $.inArray(region, allowed) >= 0) {
        // Allowed
        $button.show();
      } else {
        // Not allowed
        $button.hide();
      }
    });
  }

  // Fetch the inline type from id
  function getInlineType(inline) {
    var match = /^([a-z0-9_]+)-\d+$/g.exec($(inline).attr("id"));
    if (match) {
      return match[1];
    }
    return null;
  }

  function attachMoveToRegionDropdown(inline) {
    // Filter allowed regions
    var inlineType = getInlineType(inline);
    var regions = [];
    for (var i = 0; i < ContentEditor.regions.length; i++) {
      if (
        (!inlineType ||
          !pluginRegions[inlineType] ||
          $.inArray(ContentEditor.regions[i].key, pluginRegions[inlineType]) >=
            0) &&
        ContentEditor.regions[i].key !== "_unknown_"
      ) {
        regions.push(ContentEditor.regions[i]);
      }
    }

    if (regions.length < 2) return;

    var controls = document.createElement("div"),
      select = buildDropdown(regions),
      regionInput = inline.find(".field-region input");

    select.value = regionInput.val();
    controls.className = "inline-controls";
    controls.appendChild(select);
    inline.append(controls);

    select.addEventListener("change", function () {
      inline.attr("data-region", select.value);
      regionInput.val(select.value);
      hideInlinesFromOtherRegions();
      setBiggestOrdering(inline);
      reorderInlines();
    });
  }

  // Assing data-region to all inlines.
  // We also want to the data attribute to be visible to selectors (that's why we're using $.attr)
  function assignRegionDataAttribute() {
    orderMachine.find(".inline-related:not(.empty-form)").each(function () {
      var $this = $(this),
        region = $this.find(".field-region input").val();

      if (!ContentEditor.regionsByKey[region]) {
        var spec = {
          key: "_unknown_",
          title: ContentEditor.messages.unknownRegion,
          inherited: false,
        };
        ContentEditor.regions.push(spec);
        ContentEditor.regionsByKey[spec.key] = spec;
        region = spec.key;
      }

      $this.attr("data-region", region);
      attachMoveToRegionDropdown($this);
    });
  }

  function setBiggestOrdering(row) {
    var orderings = [];
    orderMachine.find(".field-ordering input").each(function () {
      if (!isNaN(+this.value)) orderings.push(+this.value);
    });
    var ordering = 10 + Math.max.apply(null, orderings);
    row.find(".field-ordering input").val(ordering);
    row.css("order", ordering);
  }

  function insertBefore(row, before) {
    var beforeOrdering = +before.querySelector(".field-ordering input").value,
      beforeRows = [],
      afterRows = [];
    orderMachine.find(".inline-related:not(.empty-form)").each(function () {
      var thisOrderingField = this.querySelector(".field-ordering input");
      if (this != row && !isNaN(+thisOrderingField.value)) {
        if (+thisOrderingField.value >= beforeOrdering) {
          afterRows.push([this, thisOrderingField]);
        } else {
          beforeRows.push([this, thisOrderingField]);
        }
      }
    });
    beforeRows.sort(function (a, b) {
      return a[1].value - b[1].value;
    });
    afterRows.sort(function (a, b) {
      return a[1].value - b[1].value;
    });
    var rows = [].concat(beforeRows);
    rows.push([row, row.querySelector(".field-ordering input")]);
    rows = rows.concat(afterRows);
    for (var i = 0; i < rows.length; ++i) {
      var thisRow = rows[i];
      thisRow[1].value = thisRow[0].style.order = 10 * (1 + i);
    }
  }

  function hideInlinesFromOtherRegions() {
    var inlines = orderMachine.find(".inline-related:not(.empty-form)");
    inlines.addClass("content-editor-hidden");
    var shown = inlines.filter(
      '[data-region="' + ContentEditor.currentRegion + '"]'
    );
    machineEmptyMessage.addClass("hidden");
    if (shown.length) {
      shown.removeClass("content-editor-hidden");
    } else {
      machineEmptyMessage.removeClass("hidden");
    }
    machineEmptyMessage.text(
      ContentEditor.messages[
        ContentEditor.regionsByKey[ContentEditor.currentRegion].inherited
          ? "emptyInherited"
          : "empty"
      ]
    );
  }

  var pluginInlineGroups = (function selectPluginInlineGroups() {
    var selector = [];
    for (var i = 0; i < ContentEditor.plugins.length; i++) {
      selector.push("#" + ContentEditor.plugins[i].prefix + "-group");
    }
    return $(selector.join(", "));
  })();

  reorderInlines(pluginInlineGroups);
  pluginInlineGroups.hide();
  assignRegionDataAttribute();

  // Always move empty forms to the end, because new plugins are inserted
  // just before its empty form. Also, assign region data.
  $(document).on("formset:added", function newForm(event, row, formsetName) {
    // Not one of our managed inlines?
    if (!ContentEditor.pluginsByPrefix[formsetName]) return;

    row.find(".field-region input").val(ContentEditor.currentRegion);
    row.find("h3 .inline_label").text(ContentEditor.messages.newItem);
    row.attr("data-region", ContentEditor.currentRegion);

    setBiggestOrdering(row);
    attachMoveToRegionDropdown(row);
    ensureDraggable(row);

    machineEmptyMessage.addClass("hidden");

    $(document).trigger("content-editor:activate", [row]);

    row.find("input, select, textarea").first().focus();
  });

  $(document).on("formset:removed", function resetInlines(
    _event,
    _row,
    formsetName
  ) {
    // Not one of our managed inlines?
    if (!ContentEditor.pluginsByPrefix[formsetName]) return;

    if (
      !orderMachine.find(
        '.inline-related[data-region="' + ContentEditor.currentRegion + '"]'
      ).length
    ) {
      machineEmptyMessage.removeClass("hidden");
    }
    orderMachine
      .find(".inline-related.last-related:not(.empty-form)")
      .each(function () {
        $(document).trigger("content-editor:deactivate", [$(this)]);
      });

    // As soon as possible, but not sooner (let the inline.js code run to the end first)
    setTimeout(function () {
      orderMachine
        .find(".inline-related.last-related:not(.empty-form)")
        .each(function () {
          $(document).trigger("content-editor:activate", [$(this)]);
        });
    }, 0);
  });

  // Initialize tabs and currentRegion.
  (function () {
    var tabContainer = $(".tabs.regions");
    for (var i = 0; i < ContentEditor.regions.length; i++) {
      var t = document.createElement("h2");
      t.className = "tab";
      t.textContent = ContentEditor.regions[i].title;
      t.setAttribute("data-region", ContentEditor.regions[i].key);
      tabContainer.append(t);
    }

    var tabs = tabContainer.find("h2"),
      tab;
    tabs.on("click", function () {
      ContentEditor.currentRegion = $(this).data("region");
      tabs
        .removeClass("active")
        .filter('[data-region="' + ContentEditor.currentRegion + '"]')
        .addClass("active");
      hideInlinesFromOtherRegions();
      window.location.hash = "tab_" + ContentEditor.currentRegion;

      // Make sure only allowed plugins are in select
      hideNotAllowedDropdown();
      hideNotAllowedPluginButtons();
    });

    // Restore tab if location hash matches.
    if (
      window.location.hash &&
      (tab = tabs.filter(
        '[data-region="' + window.location.hash.substr(5) + '"]'
      )) &&
      tab.length
    ) {
      tab.click();
    } else {
      tabs.eq(0).click();
    }

    tabContainer.find(".toggle input").on("change", function () {
      $(".order-machine .inline-related").toggleClass(
        "collapsed",
        this.checked
      );
    });
  })();

  $(document)
    .on("content-editor:deactivate", function (event, row) {
      row.find("fieldset").addClass("content-editor-hidden");
    })
    .on("content-editor:activate", function (event, row) {
      row.find("fieldset").removeClass("content-editor-hidden");
    });

  // Hide fieldsets of to-be-deleted inlines.
  orderMachine.on(
    "click",
    ".delete>input[type=checkbox]",
    function toggleForDeletionClass() {
      var module = $(this).closest(".inline-related");
      if (this.checked) {
        module.addClass("for-deletion");
      } else {
        module.removeClass("for-deletion");
      }
    }
  );

  orderMachine.on("dblclick", "h3", function toggleCollapsed() {
    $(this).parents(".inline-related").toggleClass("collapsed");
  });

  // Try to keep the current region tab (location hash).
  $("form").submit(function () {
    var form = $(this);
    form.attr("action", (form.attr("action") || "") + window.location.hash);
    return true;
  });

  (function buildPluginDropdown() {
    var select = buildDropdown(
      ContentEditor.plugins,
      ContentEditor.messages.createNew
    );
    select.addEventListener("change", function () {
      ContentEditor.addContent(select.value);
      select.value = "";
    });
    ContentEditor.machineControlSelect = select;
    hideNotAllowedDropdown();
    $(select)
      .appendTo(".machine-control")
      .wrap('

');
  })();

  $(document).trigger("content-editor:ready");
});
<commit_msg>Fix that<commit_after>/* global django,ContentEditor */

/* Polyfilling a bit */
if (!Element.prototype.matches)
  Element.prototype.matches =
    Element.prototype.msMatchesSelector ||
    Element.prototype.webkitMatchesSelector;

if (!Element.prototype.closest) {
  Element.prototype.closest = function (s) {
    var el = this;
    if (!document.documentElement.contains(el)) return null;
    do {
      if (el.matches(s)) return el;
      el = el.parentElement || el.parentNode;
    } while (el !== null && el.nodeType === 1);
    return null;
  };
}
/* Polyfill end */

django.jQuery(function ($) {
  var context = document.getElementById("content-editor-context");
  if (!context) return;

  window.ContentEditor = {
    addContent: function addContent(prefix) {
      $("#" + prefix + "-group .add-row a").click();
    },
    addPluginButton: function addPluginButton(prefix, html) {
      var plugin = ContentEditor.pluginsByPrefix[prefix];
      if (!plugin) return;

      var unit = document.querySelector(".control-unit.plugin-buttons");
      if (!unit) {
        unit = document.createElement("div");
        unit.className = "control-unit plugin-buttons";
        var mc = document.querySelector(".machine-control");
        mc.insertBefore(unit, mc.firstChild);
      }

      var button = document.createElement("a");
      var $button = $(button);
      $button.data("plugin", plugin.prefix);
      button.className = "plugin-button";
      button.title = plugin.title;
      button.addEventListener("click", function () {
        ContentEditor.addContent(plugin.prefix);
      });
      button.innerHTML = html;

      unit.appendChild(button);

      hideNotAllowedPluginButtons($button);
    },
  };

  // .dataset.context instead of getAttribute would be nicer
  $.extend(
    window.ContentEditor,
    JSON.parse(context.getAttribute("data-context"))
  );

  var i;
  ContentEditor.pluginsByPrefix = {}
  ContentEditor.pluginsByKey = {};
  ContentEditor.prefixToKey = {};
  for (i = 0; i < ContentEditor.plugins.length; ++i) {
    ContentEditor.pluginsByPrefix[ContentEditor.plugins[i].prefix] =
      ContentEditor.plugins[i]
  }
  ContentEditor.regionsByKey = {};
  for (i = 0; i < ContentEditor.regions.length; ++i) {
    ContentEditor.regionsByKey[ContentEditor.regions[i].key] =
      ContentEditor.regions[i];
  }

  // Add basic structure. There is always at least one inline group if
  // we even have any plugins.
  $(".inline-group:first").before(
    '
' +
      '<input type="checkbox" /> ' +
      ContentEditor.messages.toggle +
      "" +
      "
" +
      '
' +
      '

' +
      "
"
  );

  var orderMachine = $(".order-machine"),
    machineEmptyMessage = $('
')
      .text(ContentEditor.messages.empty)
      .appendTo(orderMachine);

  // Pre map plugin regions
  var pluginRegions = (function () {
    var result = {};
    var plugins = ContentEditor.plugins;
    for (var i = 0; i < plugins.length; i++) {
      result[plugins[i].prefix] = plugins[i].regions;
    }
    return result;
  })();

  function ensureDraggable(arg) {
    if (arg.hasClass("empty-form") || arg.hasClass("fs-draggable")) return;

    var inline = arg[0];

    inline.addEventListener("dragstart", function (e) {
      // window.__fs_dragging = inline;
      window.__fs_dragging = e.target.closest(".inline-related");
      window.__fs_dragging.classList.add("fs-dragging");

      e.dataTransfer.dropEffect = "move";
      e.dataTransfer.effectAllowed = "move";
      try {
        e.dataTransfer.setData("text/plain", "");
      } catch (e) {
        // IE11 needs this.
      }
    });
    inline.addEventListener("dragend", function () {
      $(".fs-dragging").removeClass("fs-dragging");
      $(".fs-dragover").removeClass("fs-dragover");
    });
    inline.addEventListener(
      "dragover",
      function (e) {
        e.preventDefault();
        $(".fs-dragover").removeClass("fs-dragover");
        e.target.closest(".inline-related").classList.add("fs-dragover");
      },
      true
    );
    inline.addEventListener("drop", function (e) {
      e.preventDefault();
      insertBefore(window.__fs_dragging, e.target.closest(".inline-related"));
    });

    arg.find(">h3").attr("draggable", true);
    arg.addClass("fs-draggable");
  }

  function reorderInlines(context) {
    context = context || orderMachine;
    var inlines = context.find(".inline-related");
    inlines.not(".empty-form").each(function () {
      $(document).trigger("content-editor:deactivate", [$(this)]);

      ensureDraggable($(this));
    });

    inlines.detach();
    orderMachine.append(inlines);

    inlines.each(function () {
      var ordering = $(".field-ordering input", this).val() || 1e9;
      this.style.order = ordering;
      ensureDraggable($(this));
    });

    inlines.not(".empty-form").each(function () {
      $(document).trigger("content-editor:activate", [$(this)]);
    });
  }

  function buildDropdown(contents, title) {
    var select = document.createElement("select"),
      idx = 0;

    if (title) select.options[idx++] = new Option(title, "", true);

    for (var i = 0; i < contents.length; i++) {
      select.options[idx++] = new Option(contents[i].title, contents[i].prefix || contents[i].key);
    }
    return select;
  }

  // Hides plugins that are not allowed in this region
  function hideNotAllowedDropdown() {
    $(ContentEditor.machineControlSelect)
      .find("option")
      .each(function () {
        var $option = $(this);
        var allowed = pluginRegions[$option.val()];
        if (!allowed || $.inArray(ContentEditor.currentRegion, allowed) >= 0) {
          $option.show();
        } else {
          $option.hide();
        }
      });
  }

  // Hide not allowed plugin buttons
  // If $buttons only checks this buttons, else checks all
  function hideNotAllowedPluginButtons($buttons) {
    $buttons = $buttons
      ? $buttons
      : $(".control-unit.plugin-buttons .plugin-button");

    var region = ContentEditor.currentRegion;

    $buttons.each(function () {
      var $button = $(this);
      var plugin = $button.data("plugin");
      var allowed = pluginRegions[plugin];

      if (!allowed || $.inArray(region, allowed) >= 0) {
        // Allowed
        $button.show();
      } else {
        // Not allowed
        $button.hide();
      }
    });
  }

  // Fetch the inline type from id
  function getInlineType(inline) {
    var match = /^([a-z0-9_]+)-\d+$/g.exec($(inline).attr("id"));
    if (match) {
      return match[1];
    }
    return null;
  }

  function attachMoveToRegionDropdown(inline) {
    // Filter allowed regions
    var inlineType = getInlineType(inline);
    var regions = [];
    for (var i = 0; i < ContentEditor.regions.length; i++) {
      if (
        (!inlineType ||
          !pluginRegions[inlineType] ||
          $.inArray(ContentEditor.regions[i].key, pluginRegions[inlineType]) >=
            0) &&
        ContentEditor.regions[i].key !== "_unknown_"
      ) {
        regions.push(ContentEditor.regions[i]);
      }
    }

    if (regions.length < 2) return;

    var controls = document.createElement("div"),
      select = buildDropdown(regions),
      regionInput = inline.find(".field-region input");

    select.value = regionInput.val();
    controls.className = "inline-controls";
    controls.appendChild(select);
    inline.append(controls);

    select.addEventListener("change", function () {
      inline.attr("data-region", select.value);
      regionInput.val(select.value);
      hideInlinesFromOtherRegions();
      setBiggestOrdering(inline);
      reorderInlines();
    });
  }

  // Assing data-region to all inlines.
  // We also want to the data attribute to be visible to selectors (that's why we're using $.attr)
  function assignRegionDataAttribute() {
    orderMachine.find(".inline-related:not(.empty-form)").each(function () {
      var $this = $(this),
        region = $this.find(".field-region input").val();

      if (!ContentEditor.regionsByKey[region]) {
        var spec = {
          key: "_unknown_",
          title: ContentEditor.messages.unknownRegion,
          inherited: false,
        };
        ContentEditor.regions.push(spec);
        ContentEditor.regionsByKey[spec.key] = spec;
        region = spec.key;
      }

      $this.attr("data-region", region);
      attachMoveToRegionDropdown($this);
    });
  }

  function setBiggestOrdering(row) {
    var orderings = [];
    orderMachine.find(".field-ordering input").each(function () {
      if (!isNaN(+this.value)) orderings.push(+this.value);
    });
    var ordering = 10 + Math.max.apply(null, orderings);
    row.find(".field-ordering input").val(ordering);
    row.css("order", ordering);
  }

  function insertBefore(row, before) {
    var beforeOrdering = +before.querySelector(".field-ordering input").value,
      beforeRows = [],
      afterRows = [];
    orderMachine.find(".inline-related:not(.empty-form)").each(function () {
      var thisOrderingField = this.querySelector(".field-ordering input");
      if (this != row && !isNaN(+thisOrderingField.value)) {
        if (+thisOrderingField.value >= beforeOrdering) {
          afterRows.push([this, thisOrderingField]);
        } else {
          beforeRows.push([this, thisOrderingField]);
        }
      }
    });
    beforeRows.sort(function (a, b) {
      return a[1].value - b[1].value;
    });
    afterRows.sort(function (a, b) {
      return a[1].value - b[1].value;
    });
    var rows = [].concat(beforeRows);
    rows.push([row, row.querySelector(".field-ordering input")]);
    rows = rows.concat(afterRows);
    for (var i = 0; i < rows.length; ++i) {
      var thisRow = rows[i];
      thisRow[1].value = thisRow[0].style.order = 10 * (1 + i);
    }
  }

  function hideInlinesFromOtherRegions() {
    var inlines = orderMachine.find(".inline-related:not(.empty-form)");
    inlines.addClass("content-editor-hidden");
    var shown = inlines.filter(
      '[data-region="' + ContentEditor.currentRegion + '"]'
    );
    machineEmptyMessage.addClass("hidden");
    if (shown.length) {
      shown.removeClass("content-editor-hidden");
    } else {
      machineEmptyMessage.removeClass("hidden");
    }
    machineEmptyMessage.text(
      ContentEditor.messages[
        ContentEditor.regionsByKey[ContentEditor.currentRegion].inherited
          ? "emptyInherited"
          : "empty"
      ]
    );
  }

  var pluginInlineGroups = (function selectPluginInlineGroups() {
    var selector = [];
    for (var i = 0; i < ContentEditor.plugins.length; i++) {
      selector.push("#" + ContentEditor.plugins[i].prefix + "-group");
    }
    return $(selector.join(", "));
  })();

  reorderInlines(pluginInlineGroups);
  pluginInlineGroups.hide();
  assignRegionDataAttribute();

  // Always move empty forms to the end, because new plugins are inserted
  // just before its empty form. Also, assign region data.
  $(document).on("formset:added", function newForm(event, row, formsetName) {
    // Not one of our managed inlines?
    if (!ContentEditor.pluginsByPrefix[formsetName]) return;

    row.find(".field-region input").val(ContentEditor.currentRegion);
    row.find("h3 .inline_label").text(ContentEditor.messages.newItem);
    row.attr("data-region", ContentEditor.currentRegion);

    setBiggestOrdering(row);
    attachMoveToRegionDropdown(row);
    ensureDraggable(row);

    machineEmptyMessage.addClass("hidden");

    $(document).trigger("content-editor:activate", [row]);

    row.find("input, select, textarea").first().focus();
  });

  $(document).on("formset:removed", function resetInlines(
    _event,
    _row,
    formsetName
  ) {
    // Not one of our managed inlines?
    if (!ContentEditor.pluginsByPrefix[formsetName]) return;

    if (
      !orderMachine.find(
        '.inline-related[data-region="' + ContentEditor.currentRegion + '"]'
      ).length
    ) {
      machineEmptyMessage.removeClass("hidden");
    }
    orderMachine
      .find(".inline-related.last-related:not(.empty-form)")
      .each(function () {
        $(document).trigger("content-editor:deactivate", [$(this)]);
      });

    // As soon as possible, but not sooner (let the inline.js code run to the end first)
    setTimeout(function () {
      orderMachine
        .find(".inline-related.last-related:not(.empty-form)")
        .each(function () {
          $(document).trigger("content-editor:activate", [$(this)]);
        });
    }, 0);
  });

  // Initialize tabs and currentRegion.
  (function () {
    var tabContainer = $(".tabs.regions");
    for (var i = 0; i < ContentEditor.regions.length; i++) {
      var t = document.createElement("h2");
      t.className = "tab";
      t.textContent = ContentEditor.regions[i].title;
      t.setAttribute("data-region", ContentEditor.regions[i].key);
      tabContainer.append(t);
    }

    var tabs = tabContainer.find("h2"),
      tab;
    tabs.on("click", function () {
      ContentEditor.currentRegion = $(this).data("region");
      tabs
        .removeClass("active")
        .filter('[data-region="' + ContentEditor.currentRegion + '"]')
        .addClass("active");
      hideInlinesFromOtherRegions();
      window.location.hash = "tab_" + ContentEditor.currentRegion;

      // Make sure only allowed plugins are in select
      hideNotAllowedDropdown();
      hideNotAllowedPluginButtons();
    });

    // Restore tab if location hash matches.
    if (
      window.location.hash &&
      (tab = tabs.filter(
        '[data-region="' + window.location.hash.substr(5) + '"]'
      )) &&
      tab.length
    ) {
      tab.click();
    } else {
      tabs.eq(0).click();
    }

    tabContainer.find(".toggle input").on("change", function () {
      $(".order-machine .inline-related").toggleClass(
        "collapsed",
        this.checked
      );
    });
  })();

  $(document)
    .on("content-editor:deactivate", function (event, row) {
      row.find("fieldset").addClass("content-editor-hidden");
    })
    .on("content-editor:activate", function (event, row) {
      row.find("fieldset").removeClass("content-editor-hidden");
    });

  // Hide fieldsets of to-be-deleted inlines.
  orderMachine.on(
    "click",
    ".delete>input[type=checkbox]",
    function toggleForDeletionClass() {
      var module = $(this).closest(".inline-related");
      if (this.checked) {
        module.addClass("for-deletion");
      } else {
        module.removeClass("for-deletion");
      }
    }
  );

  orderMachine.on("dblclick", "h3", function toggleCollapsed() {
    $(this).parents(".inline-related").toggleClass("collapsed");
  });

  // Try to keep the current region tab (location hash).
  $("form").submit(function () {
    var form = $(this);
    form.attr("action", (form.attr("action") || "") + window.location.hash);
    return true;
  });

  (function buildPluginDropdown() {
    var select = buildDropdown(
      ContentEditor.plugins,
      ContentEditor.messages.createNew
    );
    select.addEventListener("change", function () {
      ContentEditor.addContent(select.value);
      select.value = "";
    });
    ContentEditor.machineControlSelect = select;
    hideNotAllowedDropdown();
    $(select)
      .appendTo(".machine-control")
      .wrap('

');
  })();

  $(document).trigger("content-editor:ready");
});
<|endoftext|>


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

  $('#expense_description').keyup(function () {
    var max = 300;
    var len = $(this).val().length;
    var char = max - len;
    if (len >= max) {
      $('#charNum').text(char + ' chars left');
      $('#charNum').css('color', 'red');
      $('.new_expense input[type=submit]').attr('disabled','disabled');
    } else {
      $('#charNum').text(char + ' chars left');
      $('#charNum').css('color', 'grey');
      $('.new_expense input[type=submit]').removeAttr('disabled');
    }
  });

  $("#menu-toggle").click(function(e) {
      e.preventDefault();
      console.log("hello")
      $("#wrapper").toggleClass("active");
  });

  $('#expense_form').hide();

  $('#trip_form').on('click', 'input[type=submit]', function(event){
    $('#trip_form').hide();
    $('#expense_form').show();
  });

  $('input#expense_location_id').geocomplete();

  $('form').on('click','.add_fields', function(event){
    event.preventDefault();
    time = new Date().getTime();
    regexp = new RegExp($(this).data('id'), 'g');
    $(this).before($(this).data('fields').replace(regexp, time));
  });
  // $('#add-location').click(function(e){
  //   e.preventDefault();
  //   addLegForm();
  // })

$('body').on('click','.location',function(e){
  $(this).geocomplete();
});

$('#expenses_grid').on('click','#add-expense', function(e){
  e.preventDefault();
  console.log("clicked");
  $('#new_expense').show();
  $('#add-expense').hide();
});

$('#expenses_grid').on('submit','#new_expense',function(e){
  e.preventDefault();
  var old_balance = parseFloat($('#balance-field').text().replace(/[A-Za-z$-,]/g, ""));
  $.ajax ({
    url: $(e.target).attr('action'),
    type: 'POST',
    data: $(e.target).serialize()
  }).done(function(data){
    $('.event-list').append(data);
    var usd = parseFloat($('.event-list li:last-child #usd-cost-field').text().replace(/[A-Za-z$-,]/g, ""));
    var new_balance = (old_balance - usd).toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,');
    $('#balance-field').text('$' + new_balance)
    clearInputs();
  });
});

clearInputs = function(){
  $("input[name='expense[usd_cost]'").val("");
  $("input[name='expense[location_id]'").val("");
  $("input[name='expense[cost]'").val("");
  $("input[name='expense[category_id]'").val("");
  $("textarea[name='expense[description]'").val("");
  $("input[name='expense[title]'").val("");
  };
});

<commit_msg>Reset char count and category dropdown at add expense<commit_after>$(document).ready(function(){
    var max = 300;

  $('#expense_description').keyup(function () {
    var len = $(this).val().length;
    var char = max - len;
    if (len >= max) {
      $('#charNum').text(char + ' chars left');
      $('#charNum').css('color', 'red');
      $('.new_expense input[type=submit]').attr('disabled','disabled');
    } else {
      $('#charNum').text(char + ' chars left');
      $('#charNum').css('color', 'grey');
      $('.new_expense input[type=submit]').removeAttr('disabled');
    }
  });

  $("#menu-toggle").click(function(e) {
      e.preventDefault();
      console.log("hello")
      $("#wrapper").toggleClass("active");
  });

  $('#expense_form').hide();

  $('#trip_form').on('click', 'input[type=submit]', function(event){
    $('#trip_form').hide();
    $('#expense_form').show();
  });

  $('input#expense_location_id').geocomplete();

  $('form').on('click','.add_fields', function(event){
    event.preventDefault();
    time = new Date().getTime();
    regexp = new RegExp($(this).data('id'), 'g');
    $(this).before($(this).data('fields').replace(regexp, time));
  });
  // $('#add-location').click(function(e){
  //   e.preventDefault();
  //   addLegForm();
  // })

$('body').on('click','.location',function(e){
  $(this).geocomplete();
});

$('#expenses_grid').on('click','#add-expense', function(e){
  e.preventDefault();
  console.log("clicked");
  $('#new_expense').show();
  $('#add-expense').hide();
});

$('#expenses_grid').on('submit','#new_expense',function(e){
  e.preventDefault();
  var old_balance = parseFloat($('#balance-field').text().replace(/[A-Za-z$-,]/g, ""));
  $.ajax ({
    url: $(e.target).attr('action'),
    type: 'POST',
    data: $(e.target).serialize()
  }).done(function(data){
    $('.event-list').append(data);
    var usd = parseFloat($('.event-list li:last-child #usd-cost-field').text().replace(/[A-Za-z$-,]/g, ""));
    var new_balance = (old_balance - usd).toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,');
    $('#balance-field').text('$' + new_balance)
    clearInputs();
  });
});

clearInputs = function(){
  $("input[name='expense[usd_cost]'").val("");
  $("input[name='expense[location_id]'").val("");
  $("input[name='expense[cost]'").val("");
  $("input[name='expense[category_id]'").val("");
  $("textarea[name='expense[description]'").val("");
  $("input[name='expense[title]'").val("");
  $('select option:contains("Category")').prop('selected',true);
  $('#charNum').text(max + ' chars left');
  };
});

<|endoftext|>


<commit_before>describe('Control.LayerSwitcher', function () {

    var container;
    var map;
    var center = new maptalks.Coordinate(118.846825, 32.046534);

    beforeEach(function () {
        container = document.createElement('div');
        container.style.width = '800px';
        container.style.height = '600px';
        document.body.appendChild(container);
        var option = {
            zoomAnimation: false,
            zoom: 5,
            center: center
        };
        map = new maptalks.Map(container, option);
    });

    afterEach(function () {
        map.remove();
        REMOVE_CONTAINER(container);
    });

    it('baseTitle and overlayTitle', function () {
        var tile1 = new maptalks.TileLayer('tile1', {
            urlTemplate : '/resources/tile.png'
        });
        var tile2 = new maptalks.TileLayer('tile2', {
            urlTemplate : '/resources/tile.png'
        });
        map.setBaseLayer(tile1);
        map.addLayer(tile2);
        var control = new maptalks.control.LayerSwitcher({
            baseTitle: 'baseTitle',
            overlayTitle : 'overlayTitle'
        });
        map.addControl(control);
        happen.mouseover(control.button, {
            'clientX' : 100,
            'clientY' : 100
        });

        var labels = document.querySelectorAll('.maptalks-layer-switcher label', this);
        expect(labels[0].innerText).to.be.eql('baseTitle');
        expect(labels[1].innerText).to.be.eql('tile1');
        expect(labels[2].innerText).to.be.eql('overlayTitle');
        expect(labels[3].innerText).to.be.eql('tile2');
    });

    it('excludeLayers', function () {
        var control = new maptalks.control.LayerSwitcher({
            excludeLayers: ['tile1']
        });
        map.addControl(control);
        var tile1 = new maptalks.TileLayer('tile1', {
            urlTemplate : '/resources/tile.png'
        });
        var tile2 = new maptalks.TileLayer('tile2', {
            urlTemplate : '/resources/tile.png'
        });
        map.addLayer([tile1, tile2]);
        happen.mouseover(control.button, {
            'clientX' : 100,
            'clientY' : 100
        });
        var labels = document.querySelectorAll('.layer label', this);
        for (var i = 0, len = labels.length; i < len; i++) {
             expect(labels[i].innerText).not.to.eql('tile1');
        }
    });

    it('base layers switch', function () {
        var control = new maptalks.control.LayerSwitcher();
        map.addControl(control);
        var group = new maptalks.GroupTileLayer('group', [
            new maptalks.TileLayer('tile1', {
                urlTemplate : '/resources/tile.png'
            }),
            new maptalks.TileLayer('tile2', {
                urlTemplate : '/resources/tile.png',
                visible : false
            })
        ]);
        map.setBaseLayer(group);
        happen.mouseover(control.button, {
            'clientX' : 100,
            'clientY' : 100
        });
        var radios = document.querySelectorAll('.layer input',this);
        expect(radios[0].checked).to.be.ok();
        expect(radios[1].checked).not.to.be.ok();
        expect(group.layers[0].isVisible()).to.be.ok();
        expect(group.layers[1].isVisible()).not.to.be.ok();
        radios[1].addEventListener("click", function() {
            expect(radios[0].checked).not.to.be.ok();
            expect(radios[1].checked).to.be.ok();
            expect(group.layers[0].isVisible()).not.to.be.ok();
            expect(group.layers[1].isVisible()).to.be.ok();
        });
    });

    it('overlay layers switch', function () {
        var control = new maptalks.control.LayerSwitcher();
        map.addControl(control);
        var tile1 = new maptalks.TileLayer('tile1', {
            urlTemplate : '/resources/tile.png'
        });
        map.addLayer(tile1);
        happen.mouseover(control.button, {
            'clientX' : 100,
            'clientY' : 100
        });
        var checkbox = document.querySelector('.layer input',this);
        expect(checkbox.checked).to.be.ok();
        expect(tile1.isVisible()).to.be.ok();
        checkbox.addEventListener("click", function() {
            expect(checkbox.checked).not.to.be.ok();
            expect(tile1.isVisible()).not.to.be.ok();
        });
    });

    it('show and hide', function () {
        var control = new maptalks.control.LayerSwitcher();
        map.addControl(control);
        var tile1 = new maptalks.TileLayer('tile1', {
            urlTemplate : '/resources/tile.png'
        });
        map.addLayer(tile1);
        happen.mouseover(control.button, {
            'clientX' : 100,
            'clientY' : 100
        });
        expect(control.container.className).to.be.eql(control.options.containerClass + ' shown');
        happen.once(control.panel, {
            'type' : 'mouseleave',
            'clientX' : 100,
            'clientY' : 100,
            'toElement' : container,
            'relatedTarget' : container
        });
        expect(control.container.className).to.be.eql(control.options.containerClass);
    });

    it('remove from map', function () {
        var control = new maptalks.control.LayerSwitcher();
        map.addControl(control);
        var tile1 = new maptalks.TileLayer('tile1', {
            urlTemplate : '/resources/tile.png'
        });
        map.addLayer(tile1);
        happen.mouseover(control.button, {
            'clientX' : 100,
            'clientY' : 100
        });
        control.remove();
    });
});
<commit_msg>delete parameter this<commit_after>describe('Control.LayerSwitcher', function () {

    var container;
    var map;
    var center = new maptalks.Coordinate(118.846825, 32.046534);

    beforeEach(function () {
        container = document.createElement('div');
        container.style.width = '800px';
        container.style.height = '600px';
        document.body.appendChild(container);
        var option = {
            zoomAnimation: false,
            zoom: 5,
            center: center
        };
        map = new maptalks.Map(container, option);
    });

    afterEach(function () {
        map.remove();
        REMOVE_CONTAINER(container);
    });

    it('baseTitle and overlayTitle', function () {
        var tile1 = new maptalks.TileLayer('tile1', {
            urlTemplate : '/resources/tile.png'
        });
        var tile2 = new maptalks.TileLayer('tile2', {
            urlTemplate : '/resources/tile.png'
        });
        map.setBaseLayer(tile1);
        map.addLayer(tile2);
        var control = new maptalks.control.LayerSwitcher({
            baseTitle: 'baseTitle',
            overlayTitle : 'overlayTitle'
        });
        map.addControl(control);
        happen.mouseover(control.button, {
            'clientX' : 100,
            'clientY' : 100
        });

        var labels = document.querySelectorAll('label');
        expect(labels[0].innerText).to.be.eql('baseTitle');
        expect(labels[1].innerText).to.be.eql('tile1');
        expect(labels[2].innerText).to.be.eql('overlayTitle');
        expect(labels[3].innerText).to.be.eql('tile2');
    });

    it('excludeLayers', function () {
        var control = new maptalks.control.LayerSwitcher({
            excludeLayers: ['tile1']
        });
        map.addControl(control);
        var tile1 = new maptalks.TileLayer('tile1', {
            urlTemplate : '/resources/tile.png'
        });
        var tile2 = new maptalks.TileLayer('tile2', {
            urlTemplate : '/resources/tile.png'
        });
        map.addLayer([tile1, tile2]);
        happen.mouseover(control.button, {
            'clientX' : 100,
            'clientY' : 100
        });
        var labels = document.querySelectorAll('.layer label');
        for (var i = 0, len = labels.length; i < len; i++) {
             expect(labels[i].innerText).not.to.eql('tile1');
        }
    });

    it('base layers switch', function () {
        var control = new maptalks.control.LayerSwitcher();
        map.addControl(control);
        var group = new maptalks.GroupTileLayer('group', [
            new maptalks.TileLayer('tile1', {
                urlTemplate : '/resources/tile.png'
            }),
            new maptalks.TileLayer('tile2', {
                urlTemplate : '/resources/tile.png',
                visible : false
            })
        ]);
        map.setBaseLayer(group);
        happen.mouseover(control.button, {
            'clientX' : 100,
            'clientY' : 100
        });
        var radios = document.querySelectorAll('.layer input');
        expect(radios[0].checked).to.be.ok();
        expect(radios[1].checked).not.to.be.ok();
        expect(group.layers[0].isVisible()).to.be.ok();
        expect(group.layers[1].isVisible()).not.to.be.ok();
        radios[1].addEventListener("click", function() {
            expect(radios[0].checked).not.to.be.ok();
            expect(radios[1].checked).to.be.ok();
            expect(group.layers[0].isVisible()).not.to.be.ok();
            expect(group.layers[1].isVisible()).to.be.ok();
        });
    });

    it('overlay layers switch', function () {
        var control = new maptalks.control.LayerSwitcher();
        map.addControl(control);
        var tile1 = new maptalks.TileLayer('tile1', {
            urlTemplate : '/resources/tile.png'
        });
        map.addLayer(tile1);
        happen.mouseover(control.button, {
            'clientX' : 100,
            'clientY' : 100
        });
        var checkbox = document.querySelector('.layer input');
        expect(checkbox.checked).to.be.ok();
        expect(tile1.isVisible()).to.be.ok();
        checkbox.addEventListener("click", function() {
            expect(checkbox.checked).not.to.be.ok();
            expect(tile1.isVisible()).not.to.be.ok();
        });
    });

    it('show and hide', function () {
        var control = new maptalks.control.LayerSwitcher();
        map.addControl(control);
        var tile1 = new maptalks.TileLayer('tile1', {
            urlTemplate : '/resources/tile.png'
        });
        map.addLayer(tile1);
        happen.mouseover(control.button, {
            'clientX' : 100,
            'clientY' : 100
        });
        expect(control.container.className).to.be.eql(control.options.containerClass + ' shown');
        happen.once(control.panel, {
            'type' : 'mouseleave',
            'clientX' : 100,
            'clientY' : 100,
            'toElement' : container,
            'relatedTarget' : container
        });
        expect(control.container.className).to.be.eql(control.options.containerClass);
    });

    it('remove from map', function () {
        var control = new maptalks.control.LayerSwitcher();
        map.addControl(control);
        var tile1 = new maptalks.TileLayer('tile1', {
            urlTemplate : '/resources/tile.png'
        });
        map.addLayer(tile1);
        happen.mouseover(control.button, {
            'clientX' : 100,
            'clientY' : 100
        });
        control.remove();
    });
});
<|endoftext|>