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

/**
 *  Set document language and direction based on browser language
 */
document.documentElement.lang = navigator.language;
switch (navigator.language) {
  case "ar":    // Arabic
  case "he":    // Hebrew
  case "fa-IR": // Farsi
    document.documentElement.classList.add("rtl");  // Right to left
}

function  $(aSelector, aNode) (aNode || document).querySelector(aSelector);
function $$(aSelector, aNode) (aNode || document).querySelectorAll(aSelector);
function style(aName) aName === "Dark" ? document.styleSheets[1] : document.styleSheets[0];
function jsm(aURL) Components.utils.import(aURL, {});

const {LightweightThemeManager} = jsm("resource://gre/modules/LightweightThemeManager.jsm");
var {usedThemes: _themes, currentTheme: _currentTheme} = LightweightThemeManager;

const {Services} = jsm("resource://gre/modules/Services.jsm");

var _chromeWin = Services.wm.getMostRecentWindow("navigator:browser") ||
                 Services.wm.getMostRecentWindow("mail:3pane");

const PREF_ROOT = "extensions.lwthemes-manager@loucypher.";
const prefs = Services.prefs.getBranch(PREF_ROOT);

var _style = prefs.getBoolPref("darkTheme") ? "Dark" : "Light";
var _devMode = prefs.getBoolPref("devmode");
var _jsonView = prefs.getIntPref("jsonview");

/**
 *  Apply style
 */
if (_style === "Dark") {
  style("Dark").disabled = false;
  style("Light").disabled = true;
}
else {
  style("Light").disabled = false;
  style("Dark").disabled = true;
}

function jsBeautify(aJS) {
  try {
    const {js_beautify} = jsm("resource:///modules/devtools/Jsbeautify.jsm");
    return js_beautify(aJS, { indent_size: 2, indent_char: " " });
  } catch (ex) {
    return aJS;
  }
}

function sort(aArray) {
  aArray.sort(function(a, b) {
    a = a.name.toLowerCase();
    b = b.name.toLowerCase();
    if (a < b) return -1;
    if (a > b) return 1;
    return 0;
  })
}

function donation() {
  var gifts = ["beer", "coffee", "donut", "drink", "hot dog", "Ferrari"];
  var num = parseInt(Math.random() * gifts.length);
  $(".paypal a").textContent = "Buy me a " + gifts[num];
  $(".paypal a").href = "https://www.paypal.com/cgi-bin/webscr" +
                        "?cmd=_s-xclick&hosted_button_id=WDQL25BGYS3C2" +
                        "&amount=3%2e14&currency_code=USD" +
                        "&item_name=Light%20Weight%20Themes%20Manager";
}

function getThemeBox(aNode) {
  while (aNode && !aNode.hasAttribute("data-browsertheme"))
    aNode = aNode.parentNode;
  return aNode;
}

function getEntityFromDTD(aChromeURL, aEntity, aDefVal) {
  const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1",
                                                "nsIXMLHttpRequest");
  var xhr = new XMLHttpRequest();
  xhr.open("GET", aChromeURL, false);
  xhr.send(null);
  try {
    return xhr.responseText.match("ENTITY.*" + aEntity + "[^\>]+").toString()
                           .match(/\".*/).toString().replace(/\"/g, "");
  } catch (ex) {
    return aDefVal;
  }
}

function applyThemeToNode(aNode) {
  aNode.style.color = _currentTheme.textColor;
  aNode.style.backgroundColor = _currentTheme.accentcolor;
  aNode.style.backgroundImage = "url(" + _currentTheme.headerURL + ")";
}

/**
 *  Set a theme
 *  @param aNode Node that triggers the action
 *  @param aAction "wear"     Wear a theme
 *                 "stop"     Stop wearing a theme
 *                 "dump"     Uninstall a theme
 *                 "preview"  Preview a theme
 *                 "reset"    Reset preview
 */
function setTheme(aNode, aAction) {
  var themeBox = getThemeBox(aNode);
  var theme = LightweightThemeManager.parseTheme(themeBox.dataset.browsertheme);
  if (!theme)
    theme = JSON.parse(themeBox.dataset.browsertheme);

  switch (aAction) {
    case "preview":
      LightweightThemeManager.previewTheme(theme);
      return;

    case "reset":
      LightweightThemeManager.resetPreview();
      return;

    case "stop":
      LightweightThemeManager.setLocalTheme();
      themeBox.classList.remove("current");
      _currentTheme = null;
      break;

    case "dump":
      LightweightThemeManager.forgetUsedTheme(theme.id);
      if (themeBox.classList.contains("current")) {
        themeBox.classList.remove("current");
        _currentTheme = null;
      }
      break;

    default:
      LightweightThemeManager.setLocalTheme(theme);
      if ($(".current"))
        $(".current").classList.remove("current");
      themeBox.classList.add("current");
      _currentTheme = theme;
  }
  _themes = LightweightThemeManager.usedThemes;
}

/**
 *  Get theme home page. Use AMO or getpersonas.com URL if no home page.
 */
function getThemeURL(aTheme) {
  const { id: id, homepageURL: homepageURL, updateURL: updateURL } = aTheme;

  if (homepageURL)
    return homepageURL;

  if (updateURL) {
    if (updateURL.match(/getpersonas.com/))
      return "https://getpersonas.com/persona/" + id;
    if (updateURL.match(/addons.mozilla.org/))
      return "https://addons.mozilla.org/addon/" + id;
  }

  return null;
}

/**
 *  Generate boxes for installed themes
 */
function themeBox(aTheme) {
  const {
    id: id, name: name, author: author, description: description,
    homepageURL: homepageURL, previewURL: previewURL, headerURL: headerURL
  } = aTheme;

  var themeData = JSON.stringify(aTheme);

  var box = $("#template").cloneNode(true); // Clone from template
  box.removeAttribute("id");
  box.dataset.browsertheme = themeData;
  if (_currentTheme && aTheme.id === _currentTheme.id)
    box.classList.add("current");

  if (aTheme.id === "1")
    box.classList.add("persona");

  if (/^solid\-color/.test(aTheme.id)) {
    $(".image", box).classList.add("solid-color");
    $("img", box).src = "preview.png";
  }
  else if (previewURL)
    $("img", box).src = previewURL.replace(/\?\d+/, "");
  else
    $("img", box).src = headerURL.replace(/\?\d+/, "");

  $("img", box).style.backgroundColor = aTheme.accentcolor;
  $("img", box).style.color = aTheme.textcolor;
  $("img", box).alt = name;

  var themeURL = getThemeURL(aTheme);
  if (themeURL) {
    $(".theme-title a", box).href = $("header a", box).href = themeURL;
    $(".theme-title a", box).textContent = name;
  }
  else {
    $(".theme-title", box).textContent = name;
    $(".theme .image a", box).removeAttribute("title");
  }

  if (author)
    $(".theme-author", box).textContent += author;

  if (description)
    $(".theme-description", box).innerHTML = description;

  return box;
}

function openAddonsManager(aNode) {
  var themeBox = getThemeBox(aNode);
  var theme = LightweightThemeManager.parseTheme(themeBox.dataset.browsertheme);
  if (!theme)
    theme = JSON.parse(themeBox.dataset.browsertheme);

  var addonId = theme.id + "@personas.mozilla.org";
  var view = "addons://detail/" + encodeURIComponent(addonId) + "/preferences";

  if ("toEM" in _chromeWin) {
    _chromeWin.toEM(view);
  } else if ("openAddonsMgr" in _chromeWin) {
    _chromeWin.openAddonsMgr(view);
  } else {
    _chromeWin.BrowserOpenAddonsMgr(view);
  }
}

var _personas = {
  ID: "personas@christopher.beard",
  addon: null,
  status: null,

  install: function installPersonas() {
    location.assign("https://addons.mozilla.org/firefox/downloads/latest/10900/" +
                    "addon-10900-latest.xpi?src=external-addon-472283");
  },

  enable: function enablePersonas(aNode) {
    this.addon.userDisabled = false;
    aNode.classList.add("hidden");
    aNode.nextSibling.nextSibling.classList.remove("hidden");
  },

  disable: function enablePersonas(aNode) {
    this.addon.userDisabled = true;
    aNode.parentNode.classList.add("hidden");
    aNode.parentNode.previousSibling.previousSibling.classList.remove("hidden");
  },

  edit: function editPersona(aNode) {
    var editorURL = "chrome://personas/content/customPersonaEditor.xul";
    var browser = _chromeWin.gBrowser;
    var container = browser.mTabContainer;
    //console.log(container.localName);
    container.addEventListener("TabClose", function(aEvent) {
      aEvent.currentTarget.removeEventListener(aEvent.type, arguments.callee, true);
      //console.log(aEvent.currentTarget.localName);
      if (browser.currentURI.spec === editorURL &&
          LightweightThemeManager.currentTheme.id === "1") {
        _currentTheme = LightweightThemeManager.currentTheme;  // Update _currentTheme
        var themeBox = getThemeBox(aNode);
        themeBox.dataset.browsertheme = JSON.stringify(_currentTheme);
        $("img", themeBox).src = _currentTheme.headerURL;
        $("img", themeBox).removeAttribute("style");
        $("img", themeBox).alt = $(".theme-title", themeBox).textContent = _currentTheme.name;
        $("img", themeBox).style.color = _currentTheme.textcolor;
        $("img", themeBox).style.backgroundColor = _currentTheme.accentcolor;
        if (!themeBox.classList.contains("current")) {
          $(".current").classList.remove("current");
          themeBox.classList.add("current");
        }
      }
    }, true);
    browser.selectedTab = browser.addTab(editorURL);
  },

  init: function checkForPersonas() {
    var list;
    var obj = jsm("resource://gre/modules/AddonManager.jsm", {});
    var {getAddonByID} = obj.AddonManager;
    getAddonByID(this.ID, function(personas) {
      if (personas) {
        _personas.addon = personas;
        if (personas.isActive) {
          _personas.status = "enabled";
          list = $(".personas-enabled");
        }
        else {
          _personas.status = "disabled";
          list = $(".personas-disabled");
        }
        var editLabel = getEntityFromDTD("chrome://personas/locale/", "contextEdit.label",
                                         "Edit");
        //console.log(editLabel);
        $(".persona .edit").textContent = editLabel;
      }
      else {
        _personas.status = "not installed";
        list = $(".personas-not-installed");
      }
      list.classList.remove("hidden");
    })
  }
}

function inspect(aNode) {
  var themeBox = getThemeBox(aNode);
  var theme = LightweightThemeManager.parseTheme(themeBox.dataset.browsertheme);
  if (!theme)
    theme = JSON.parse(themeBox.dataset.browsertheme);
  inspectObject(theme);
}

function toggleViewer() {
  $(".viewer").classList.toggle("hidden");
}

function jsonView(aNode) {
  var themeBox = getThemeBox(aNode);
  var json = jsBeautify(themeBox.dataset.browsertheme);
  var viewOption = prefs.getIntPref("jsonview");
  if (viewOption === 1 && "Scratchpad" in _chromeWin) {
    _chromeWin.Scratchpad.ScratchpadManager.openScratchpad({text: json});
    return;
  }

  $(".viewer textarea").value = json;
  toggleViewer();
  $(".viewer textarea").focus();
}

function toggleDevMode() {
  _devMode = !_devMode;
  prefs.setBoolPref("devmode", _devMode);
  if (_devMode)
    document.documentElement.classList.add("devmode");
  else
    document.documentElement.classList.remove("devmode");
}

function load() {
  donation();
  _personas.init();

  if (_devMode)
    document.documentElement.classList.add("devmode");

  if (typeof inspectObject === "function")
    $(".inspect").classList.remove("hidden");

  if (!_themes.length) {                        // If no installed themes
    $(".no-themes").classList.remove("hidden"); // show 'No themes installed"
    $("footer").classList.add("bottom");
    return;
  }

  sort(_themes);  // Sort by name

  // Generate boxes for installed themes
  for (var i in _themes)
    $("section").insertBefore(themeBox(_themes[i]), $("#template"));

  // Move current theme to top
  if (_currentTheme)
    $(".current").parentNode.insertBefore($(".current"), $("section").firstChild);

  _themes = LightweightThemeManager.usedThemes; // Restore sort order
}

function unload() {
  prefs.setBoolPref("darkTheme", !style("Dark").disabled);
}
<commit_msg>Show number of themes; refactored<commit_after>/*
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *  Contributor(s):
 *  - LouCypher (original code)
 */

/**
 *  Set document language and direction based on browser language
 */
document.documentElement.lang = navigator.language;
switch (navigator.language) {
  case "ar":    // Arabic
  case "he":    // Hebrew
  case "fa-IR": // Farsi
    document.documentElement.classList.add("rtl");  // Right to left
}

function  $(aSelector, aNode) (aNode || document).querySelector(aSelector);
function $$(aSelector, aNode) (aNode || document).querySelectorAll(aSelector);
function style(aName) aName === "Dark" ? document.styleSheets[1] : document.styleSheets[0];
function jsm(aURL) Components.utils.import(aURL, {});

const {LightweightThemeManager} = jsm("resource://gre/modules/LightweightThemeManager.jsm");
var {usedThemes: _themes, currentTheme: _currentTheme} = LightweightThemeManager;

const {Services} = jsm("resource://gre/modules/Services.jsm");

var _chromeWin = Services.wm.getMostRecentWindow("navigator:browser") ||
                 Services.wm.getMostRecentWindow("mail:3pane");

const PREF_ROOT = "extensions.lwthemes-manager@loucypher.";
const prefs = Services.prefs.getBranch(PREF_ROOT);

var _style = prefs.getBoolPref("darkTheme") ? "Dark" : "Light";
var _devMode = prefs.getBoolPref("devmode");
var _jsonView = prefs.getIntPref("jsonview");

/**
 *  Apply style
 */
if (_style === "Dark") {
  style("Dark").disabled = false;
  style("Light").disabled = true;
}
else {
  style("Light").disabled = false;
  style("Dark").disabled = true;
}

function jsBeautify(aJS) {
  try {
    const {js_beautify} = jsm("resource:///modules/devtools/Jsbeautify.jsm");
    return js_beautify(aJS, { indent_size: 2, indent_char: " " });
  } catch (ex) {
    return aJS;
  }
}

function sort(aArray) {
  aArray.sort(function(a, b) {
    a = a.name.toLowerCase();
    b = b.name.toLowerCase();
    if (a < b) return -1;
    if (a > b) return 1;
    return 0;
  })
}

function donation() {
  var gifts = ["beer", "coffee", "donut", "drink", "hot dog", "Ferrari"];
  var num = parseInt(Math.random() * gifts.length);
  $(".paypal a").textContent = "Buy me a " + gifts[num];
  $(".paypal a").href = "https://www.paypal.com/cgi-bin/webscr" +
                        "?cmd=_s-xclick&hosted_button_id=WDQL25BGYS3C2" +
                        "&amount=3%2e14&currency_code=USD" +
                        "&item_name=Light%20Weight%20Themes%20Manager";
}

function getThemeBox(aNode) {
  while (aNode && !aNode.hasAttribute("data-browsertheme"))
    aNode = aNode.parentNode;
  return aNode;
}

function getEntityFromDTD(aChromeURL, aEntity, aDefVal) {
  const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1",
                                                "nsIXMLHttpRequest");
  var xhr = new XMLHttpRequest();
  xhr.open("GET", aChromeURL, false);
  xhr.send(null);
  try {
    return xhr.responseText.match("ENTITY.*" + aEntity + "[^\>]+").toString()
                           .match(/\".*/).toString().replace(/\"/g, "");
  } catch (ex) {
    return aDefVal;
  }
}

function applyThemeToNode(aNode) {
  aNode.style.color = _currentTheme.textColor;
  aNode.style.backgroundColor = _currentTheme.accentcolor;
  aNode.style.backgroundImage = "url(" + _currentTheme.headerURL + ")";
}

function showTotalThemes(aNumber) {
  var text = "Total themes: " + aNumber;
  console.log(document.title + "\n" + text);
  Services.console.logStringMessage(document.title + "\n" + text);
  _chromeWin.XULBrowserWindow.setOverLink(text);
}

/**
 *  Set a theme
 *  @param aNode Node that triggers the action
 *  @param aAction "wear"     Wear a theme
 *                 "stop"     Stop wearing a theme
 *                 "dump"     Uninstall a theme
 *                 "preview"  Preview a theme
 *                 "reset"    Reset preview
 */
function setTheme(aNode, aAction) {
  var themeBox = getThemeBox(aNode);
  var theme = LightweightThemeManager.parseTheme(themeBox.dataset.browsertheme);
  if (!theme)
    theme = JSON.parse(themeBox.dataset.browsertheme);

  switch (aAction) {
    case "preview":
      LightweightThemeManager.previewTheme(theme);
      return;

    case "reset":
      LightweightThemeManager.resetPreview();
      return;

    case "stop":
      LightweightThemeManager.setLocalTheme();
      themeBox.classList.remove("current");
      _currentTheme = null;
      break;

    case "dump":
      LightweightThemeManager.forgetUsedTheme(theme.id);
      if (themeBox.classList.contains("current")) {
        themeBox.classList.remove("current");
        _currentTheme = null;
      }
      showTotalThemes(_themes.length);
      break;

    default:
      LightweightThemeManager.setLocalTheme(theme);
      if ($(".current"))
        $(".current").classList.remove("current");
      themeBox.classList.add("current");
      _currentTheme = theme;
  }
  _themes = LightweightThemeManager.usedThemes;
}

/**
 *  Get theme home page. Use AMO or getpersonas.com URL if no home page.
 */
function getThemeURL(aTheme) {
  const { id: id, homepageURL: homepageURL, updateURL: updateURL } = aTheme;
  const amoURL = "https://addons.mozilla.org/";

  if (homepageURL)
    return homepageURL;

  if (updateURL) {
    if (updateURL.match(/getpersonas.com/))
      return amoURL + "persona/" + id;
    if (updateURL.match(/addons.mozilla.org/))
      return amoURL + "addon/" + id;
  }

  return null;
}

/**
 *  Generate boxes for installed themes
 */
function themeBox(aTheme) {
  const {
    id: id, name: name, author: author, description: description,
    homepageURL: homepageURL, previewURL: previewURL, headerURL: headerURL
  } = aTheme;

  var themeData = JSON.stringify(aTheme);

  var box = $("#template").cloneNode(true); // Clone from template
  box.removeAttribute("id");
  box.dataset.browsertheme = themeData;
  if (_currentTheme && aTheme.id === _currentTheme.id)
    box.classList.add("current");

  if (aTheme.id === "1")
    box.classList.add("persona");

  if (/^solid\-color/.test(aTheme.id)) {
    $(".image", box).classList.add("solid-color");
    $("img", box).src = "preview.png";
  }
  else if (previewURL)
    $("img", box).src = previewURL.replace(/\?\d+/, "");
  else
    $("img", box).src = headerURL.replace(/\?\d+/, "");

  $("img", box).style.backgroundColor = aTheme.accentcolor;
  $("img", box).style.color = aTheme.textcolor;
  $("img", box).alt = name;

  var themeURL = getThemeURL(aTheme);
  if (themeURL) {
    $(".theme-title a", box).href = $("header a", box).href = themeURL;
    $(".theme-title a", box).textContent = name;
  }
  else {
    $(".theme-title", box).textContent = name;
    $(".theme .image a", box).removeAttribute("title");
  }

  if (author)
    $(".theme-author", box).textContent += author;

  if (description)
    $(".theme-description", box).innerHTML = description;

  return box;
}

function openAddonsManager(aNode) {
  var themeBox = getThemeBox(aNode);
  var theme = LightweightThemeManager.parseTheme(themeBox.dataset.browsertheme);
  if (!theme)
    theme = JSON.parse(themeBox.dataset.browsertheme);

  var addonId = theme.id + "@personas.mozilla.org";
  var view = "addons://detail/" + encodeURIComponent(addonId) + "/preferences";

  if ("toEM" in _chromeWin) {
    _chromeWin.toEM(view);
  } else if ("openAddonsMgr" in _chromeWin) {
    _chromeWin.openAddonsMgr(view);
  } else {
    _chromeWin.BrowserOpenAddonsMgr(view);
  }
}

var _personas = {
  ID: "personas@christopher.beard",
  addon: null,
  status: null,

  install: function installPersonas() {
    location.assign("https://addons.mozilla.org/firefox/downloads/latest/10900/" +
                    "addon-10900-latest.xpi?src=external-addon-472283");
  },

  enable: function enablePersonas(aNode) {
    this.addon.userDisabled = false;
    aNode.classList.add("hidden");
    aNode.nextSibling.nextSibling.classList.remove("hidden");
  },

  disable: function enablePersonas(aNode) {
    this.addon.userDisabled = true;
    aNode.parentNode.classList.add("hidden");
    aNode.parentNode.previousSibling.previousSibling.classList.remove("hidden");
  },

  edit: function editPersona(aNode) {
    var editorURL = "chrome://personas/content/customPersonaEditor.xul";
    var browser = _chromeWin.gBrowser;
    var container = browser.mTabContainer;
    //console.log(container.localName);
    container.addEventListener("TabClose", function(aEvent) {
      aEvent.currentTarget.removeEventListener(aEvent.type, arguments.callee, true);
      //console.log(aEvent.currentTarget.localName);
      if (browser.currentURI.spec === editorURL &&
          LightweightThemeManager.currentTheme.id === "1") {
        _currentTheme = LightweightThemeManager.currentTheme;  // Update _currentTheme
        var themeBox = getThemeBox(aNode);
        themeBox.dataset.browsertheme = JSON.stringify(_currentTheme);
        $("img", themeBox).src = _currentTheme.headerURL;
        $("img", themeBox).removeAttribute("style");
        $("img", themeBox).alt = $(".theme-title", themeBox).textContent = _currentTheme.name;
        $("img", themeBox).style.color = _currentTheme.textcolor;
        $("img", themeBox).style.backgroundColor = _currentTheme.accentcolor;
        if (!themeBox.classList.contains("current")) {
          $(".current").classList.remove("current");
          themeBox.classList.add("current");
        }
      }
    }, true);
    browser.selectedTab = browser.addTab(editorURL);
  },

  init: function checkForPersonas() {
    var list;
    var obj = jsm("resource://gre/modules/AddonManager.jsm", {});
    var {getAddonByID} = obj.AddonManager;
    getAddonByID(this.ID, function(personas) {
      if (personas) {
        _personas.addon = personas;
        if (personas.isActive) {
          _personas.status = "enabled";
          list = $(".personas-enabled");
        }
        else {
          _personas.status = "disabled";
          list = $(".personas-disabled");
        }
        var editLabel = getEntityFromDTD("chrome://personas/locale/", "contextEdit.label",
                                         "Edit");
        //console.log(editLabel);
        $(".persona .edit").textContent = editLabel;
      }
      else {
        _personas.status = "not installed";
        list = $(".personas-not-installed");
      }
      list.classList.remove("hidden");
    })
  }
}

function inspect(aNode) {
  var themeBox = getThemeBox(aNode);
  var theme = LightweightThemeManager.parseTheme(themeBox.dataset.browsertheme);
  if (!theme)
    theme = JSON.parse(themeBox.dataset.browsertheme);
  inspectObject(theme);
}

function toggleViewer() {
  $(".viewer").classList.toggle("hidden");
}

function jsonView(aNode) {
  var themeBox = getThemeBox(aNode);
  var json = jsBeautify(themeBox.dataset.browsertheme);
  var viewOption = prefs.getIntPref("jsonview");
  if (viewOption === 1 && "Scratchpad" in _chromeWin) {
    _chromeWin.Scratchpad.ScratchpadManager.openScratchpad({text: json});
    return;
  }

  $(".viewer textarea").value = json;
  toggleViewer();
  $(".viewer textarea").focus();
}

function toggleDevMode() {
  _devMode = !_devMode;
  prefs.setBoolPref("devmode", _devMode);
  if (_devMode)
    document.documentElement.classList.add("devmode");
  else
    document.documentElement.classList.remove("devmode");
}

function load() {
  donation();
  _personas.init();

  if (_devMode)
    document.documentElement.classList.add("devmode");

  if (typeof inspectObject === "function")
    $(".inspect").classList.remove("hidden");

  if (!_themes.length) {                        // If no installed themes
    $(".no-themes").classList.remove("hidden"); // show 'No themes installed"
    $("footer").classList.add("bottom");
    return;
  }

  sort(_themes);  // Sort by name

  // Generate boxes for installed themes
  for (var i in _themes)
    $("section").insertBefore(themeBox(_themes[i]), $("#template"));

  // Move current theme to top
  if (_currentTheme)
    $(".current").parentNode.insertBefore($(".current"), $("section").firstChild);

  _themes = LightweightThemeManager.usedThemes; // Restore sort order

  showTotalThemes(_themes.length);
}

function unload() {
  prefs.setBoolPref("darkTheme", !style("Dark").disabled);
}
<|endoftext|>


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

    var website = openerp.website;
    var _t = openerp._t;
    website.is_editable_button = true;

    website.EditorBar.include({
        start: function() {
            var res = this._super();
            this.$("a[data-action=new_page]").parents("li").removeClass("hidden");
            this.$(".oe_content_menu li.divider").removeClass("hidden");
            return res;
        },
        edit: function () {
            this.on('rte:ready', this, function () {
                $('a:has(span[data-oe-model="website.menu"])').tooltip({
                    title: _t('Save this page and use the top "Content" menu to edit the menu.'),
                    placement: "bottom",
                    trigger: "hover",
                    show: 50,
                    hide: 100,
                    container: 'body'
                });
            });
            return this._super();
        },
        events: _.extend({}, website.EditorBar.prototype.events, {
            'click a[data-action=new_page]': function (ev) {
                ev.preventDefault();
                website.prompt({
                    id: "editor_new_page",
                    window_title: _t("New Page"),
                    input: _t("Page Title"),
                    init: function () {
                        var $group = this.$dialog.find("div.form-group");
                        $group.removeClass("mb0");

                        var $add = $(
                            '
'+
                                ''+
                                '    <input type="checkbox" checked="checked" required="required"/> '+
                                ''+
                            '
');
                        $add.find('label').append(_t("Add page in menu"));
                        $group.after($add);
                    }
                }).then(function (val, field, $dialog) {
                    if (val) {
                        var url = '/website/add/' + encodeURI(val);
                        if ($dialog.find('input[type="checkbox"]').is(':checked')) url +="?add_menu=1";
                        document.location = url;
                    }
                });
            }
        }),
    });
})();
<commit_msg>Use encodeURIComponent in place of encodeURI for website new page title, in order to escape special chars like question mark<commit_after>(function() {
    "use strict";

    var website = openerp.website;
    var _t = openerp._t;
    website.is_editable_button = true;

    website.EditorBar.include({
        start: function() {
            var res = this._super();
            this.$("a[data-action=new_page]").parents("li").removeClass("hidden");
            this.$(".oe_content_menu li.divider").removeClass("hidden");
            return res;
        },
        edit: function () {
            this.on('rte:ready', this, function () {
                $('a:has(span[data-oe-model="website.menu"])').tooltip({
                    title: _t('Save this page and use the top "Content" menu to edit the menu.'),
                    placement: "bottom",
                    trigger: "hover",
                    show: 50,
                    hide: 100,
                    container: 'body'
                });
            });
            return this._super();
        },
        events: _.extend({}, website.EditorBar.prototype.events, {
            'click a[data-action=new_page]': function (ev) {
                ev.preventDefault();
                website.prompt({
                    id: "editor_new_page",
                    window_title: _t("New Page"),
                    input: _t("Page Title"),
                    init: function () {
                        var $group = this.$dialog.find("div.form-group");
                        $group.removeClass("mb0");

                        var $add = $(
                            '
'+
                                ''+
                                '    <input type="checkbox" checked="checked" required="required"/> '+
                                ''+
                            '
');
                        $add.find('label').append(_t("Add page in menu"));
                        $group.after($add);
                    }
                }).then(function (val, field, $dialog) {
                    if (val) {
                        var url = '/website/add/' + encodeURIComponent(val);
                        if ($dialog.find('input[type="checkbox"]').is(':checked')) url +="?add_menu=1";
                        document.location = url;
                    }
                });
            }
        }),
    });
})();
<|endoftext|>


<commit_before>/* See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Esri Inc. licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
define(["dojo/_base/declare",
        "dojo/_base/lang",
        "dojo/_base/array",
        "dojo/topic",
        "app/context/app-topics",
        "dojo/dom-class",
        "dojo/dom-construct",
        "dijit/_WidgetBase",
        "dijit/_TemplatedMixin",
        "dijit/_WidgetsInTemplateMixin",
        "dojo/text!./templates/ItemCard.html",
        "dojo/i18n!app/nls/resources",
        "app/context/AppClient",
        "app/etc/util",
        "app/common/ConfirmationDialog",
        "app/content/ChangeOwner",
        "app/content/MetadataEditor",
        "app/context/metadata-editor",
        "app/content/UploadMetadata"],
function(declare, lang, array, topic, appTopics, domClass, domConstruct,
    _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, template, i18n,
    AppClient, util, ConfirmationDialog, ChangeOwner, MetadataEditor, gxeConfig,
    UploadMetadata) {

  var oThisClass = declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {

    i18n: i18n,
    templateString: template,

    isItemCard: true,
    item: null,
    itemsNode: null,
    searchPane: null,

    postCreate: function() {
      this.inherited(arguments);
      var self = this;
      topic.subscribe(appTopics.ItemOwnerChanged,function(params){
        if (self.item && self.item === params.item) {
          self._renderOwnerAndDate(self.item);
        }
      });
    },

    render: function(hit) {
      var item = this.item = hit._source;
      item._id = hit._id;
      var links = this._uniqueLinks(item);
      util.setNodeText(this.titleNode,item.title);
      this._renderOwnerAndDate(item);
      util.setNodeText(this.descriptionNode,item.description);
      this._renderThumbnail(item);
      this._renderItemLinks(hit._id,item);
      this._renderLinksDropdown(item,links);
      this._renderOptionsDropdown(hit._id,item);
      this._renderAddToMap(item,links);
    },

    _canEditMetadata: function(item,isOwner,isAdmin,isPublisher) {
      var v;
      if ((isOwner && isPublisher) || isAdmin) {
        v = item.sys_metadatatype_s;
        if (typeof v === "string") {
          if (gxeConfig.editable.geoportalTypes.indexOf(v) !== -1) {
            if (gxeConfig.editable.allowNonGxeDocs) {
              return true;
            }
            v = item.app_editor_s;
            if (typeof v === "string" && v === "gxe") {
              return true;
            }
          }
        }
      }
      return false;
    },

    _isOwner: function(item) {
      var username = AppContext.appUser.getUsername();
      if (typeof username === "string" && username.length > 0) {
        return (username === item.sys_owner_s);
      }
      return false;
    },

    _mitigateDropdownClip: function(dd,ddul) {
      // Bootstrap dropdown menus clipped by scrollable container
      var self = this;
      var reposition = function() {
        //console.warn($(dd).offset());
        var t = $(dd).offset().top + 15 - $(window).scrollTop();
        var l = $(dd).offset().left;
        $(ddul).css('top',t);
        $(ddul).css('left',l);

        var position = dd.getBoundingClientRect().top;
        var buttonHeight = dd.getBoundingClientRect().height;
        var menuHeight = $(ddul).outerHeight();
        var winHeight = $(window).height();
        if (position > menuHeight && winHeight - position < buttonHeight + menuHeight) {
          //console.warn("dropup","position:",position,"t",t,"buttonHeight",buttonHeight,"menuHeight",menuHeight);
          t = t - menuHeight - buttonHeight - 4;
          $(ddul).css('top',t);
        }
      };
      $(ddul).css("position","fixed");
      $(dd).on('click', function() {reposition();});
      //$(window).scroll(function() {reposition();});
      //$(this.itemsNode).scroll(function() {reposition();});
      //$(window).resize(function() {reposition();});
      //$(window).resize(function() {$(dd).removeClass('open');});
    },

    _renderAddToMap: function(item,links) {
      if (links.length === 0) return;
      var endsWith = function(v,sfx) {return (v.indexOf(sfx,(v.length-sfx.length)) !== -1);};
      var actionsNode = this.actionsNode;
      array.some(links, function(u){
        // "mapserver" "featureserver" "imageserver" "kml" "wms" "agsrest" "ags" "webmap"
        var lc, linkType = null, linkUrl = null;
        if (typeof u === "string" && (u.indexOf("http://") === 0 || u.indexOf("https://") === 0)) {
          lc = u.toLowerCase();
          if (lc.indexOf("service=") > 0) {
            if (lc.indexOf("?service=wms") > 0 || lc.indexOf("&service=wms") > 0) {
              linkType = "wms";
              linkUrl = u;
            }
          } else if (lc.indexOf("/rest/services") > 0) {
            if (endsWith(lc,"/mapserver")) {
              linkType = "MapServer";
              linkUrl = u;
            } else if (endsWith(lc,"/featureserver")) {
              linkType = "FeatureServer";
              linkUrl = u;
            } else if (endsWith(lc,"/imageserver")) {
              linkType = "ImageServer";
              linkUrl = u;
            }
          }
          if (linkType === null) {
            if (endsWith(lc,".kml") || endsWith(lc,".kmz") ||
                lc.indexOf("?f=kml") > 0 || lc.indexOf("&f=kml") > 0 ||
                lc.indexOf("?f=kmz") > 0 || lc.indexOf("&f=kmz") > 0) {
              linkType = "kml";
              linkUrl = u;
            }
          }
        }

        if (typeof linkUrl === "string") {
          //console.warn(linkType,linkUrl);
          domConstruct.create("a",{
            href: "javascript:void(0)",
            innerHTML: i18n.item.actions.addToMap,
            onclick: function() {
              topic.publish(appTopics.AddToMapClicked,{
                type: linkType,
                url: linkUrl
              });
            }
          },actionsNode);
          return true;
        }
      });
    },

    _renderItemLinks: function(itemId,item) {
      var actionsNode = this.actionsNode;
      var uri = "./rest/metadata/item/"+encodeURIComponent(itemId);
      var htmlNode = domConstruct.create("a",{
        href: uri+"/html",
        target: "_blank",
        innerHTML: i18n.item.actions.html
      },actionsNode);
      var xmlNode = domConstruct.create("a",{
        href: uri+"/xml",
        target: "_blank",
        innerHTML: i18n.item.actions.xml
      },actionsNode);
      domConstruct.create("a",{
        href: uri+"?pretty=true",
        target: "_blank",
        innerHTML: i18n.item.actions.json
      },actionsNode);
      var v = item.sys_metadatatype_s;
      if (typeof v === "string" && v === "json") {
        htmlNode.style.visibility = "hidden";
        xmlNode.style.visibility = "hidden";
      }
    },

    _renderLinksDropdown: function(item,links) {
      if (links.length === 0) return;
      var dd = domConstruct.create("div",{
        "class": "dropdown",
        "style": "display:inline-block;"
      },this.actionsNode);
      var ddbtn = domConstruct.create("a",{
        "class": "dropdown-toggle",
        "href": "#",
        "data-toggle": "dropdown",
        "aria-haspopup": true,
        "aria-expanded": true,
        innerHTML: i18n.item.actions.links
      },dd);
      domConstruct.create("span",{
        "class": "caret"
      },ddbtn);
      var ddul = domConstruct.create("ul",{
        "class": "dropdown-menu",
      },dd);
      array.forEach(links, function(u){
        var ddli = domConstruct.create("li",{},ddul);
        domConstruct.create("a",{
          "class": "small",
          href: u,
          target: "_blank",
          innerHTML: u
        },ddli);
      });
      this._mitigateDropdownClip(dd,ddul);
    },

    _renderOptionsDropdown: function(itemId,item) {
      var self = this;
      var isOwner = this._isOwner(item);
      var isAdmin = AppContext.appUser.isAdmin();
      var isPublisher = AppContext.appUser.isPublisher();
      var links = [];

      if (this._canEditMetadata(item,isOwner,isAdmin,isPublisher)) {
        links.push(domConstruct.create("a",{
          "class": "small",
          href: "javascript:void(0)",
          innerHTML: i18n.item.actions.options.editMetadata,
          onclick: function() {
            var editor = new MetadataEditor({itemId:itemId});
            editor.show();
          }
        }));
      }

      if ((isOwner && isPublisher) || isAdmin) {

        links.push(domConstruct.create("a",{
          "class": "small",
          href: "javascript:void(0)",
          innerHTML: i18n.item.actions.options.uploadMetadata,
          onclick: function() {
            (new UploadMetadata({itemId:itemId})).show();
          }
        }));

        links.push(domConstruct.create("a",{
          "class": "small",
          href: "javascript:void(0)",
          innerHTML: i18n.item.actions.options.deleteItem,
          onclick: function() {
            var dialog = new ConfirmationDialog({
              title: i18n.item.actions.options.deleteItem,
              content: item.title,
              okLabel: i18n.general.del,
              status: "danger"
            });
            dialog.show().then(function(ok){
              if (ok) {
                dialog.okCancelBar.showWorking(i18n.general.deleting,false);
                var client = new AppClient();
                client.deleteItem(itemId).then(function(response){
                  topic.publish(appTopics.ItemDeleted,{
                    itemId: itemId,
                    searchPane: self.searchPane
                  });
                  self.domNode.style.display = "none";
                  dialog.hide();
                }).otherwise(function(error){
                  var msg = i18n.general.error;
                  console.warn("deleteItem.error",error);
                  dialog.okCancelBar.showError(msg,false);
                });
              }
            });
          }
        }));
      }

      if (isAdmin) {
        links.push(domConstruct.create("a",{
          "class": "small",
          href: "javascript:void(0)",
          innerHTML: i18n.item.actions.options.changeOwner,
          onclick: function() {
            var dialog = new ChangeOwner({item:item});
            dialog.show();
          }
        }));
      }

      if (links.length === 0) return;

      var dd = domConstruct.create("div",{
        "class": "dropdown",
        "style": "display:inline-block;"
      },this.actionsNode);
      var ddbtn = domConstruct.create("a",{
        "class": "dropdown-toggle",
        "href": "#",
        "data-toggle": "dropdown",
        "aria-haspopup": true,
        "aria-expanded": true,
        innerHTML: i18n.item.actions.options.caption
      },dd);
      domConstruct.create("span",{
        "class": "caret"
      },ddbtn);
      var ddul = domConstruct.create("ul",{
        "class": "dropdown-menu",
      },dd);
      array.forEach(links,function(link){
        var ddli = domConstruct.create("li",{},ddul);
        ddli.appendChild(link);
      });
      this._mitigateDropdownClip(dd,ddul);
    },

    _renderOwnerAndDate: function(item) {
      var owner = item.sys_owner_s;
      var date = item.sys_modified_dt;
      var idx, text = "";
      if (AppContext.appConfig.searchResults.showDate && typeof date === "string" && date.length > 0) {
        idx = date.indexOf("T");
        if (idx > 0) date =date.substring(0,idx);
        text = date;
      }
      if (AppContext.appConfig.searchResults.showOwner && typeof owner === "string" && owner.length > 0) {
        if (text.length > 0) text += " ";
        text += owner;
      }
      if (text.length > 0) {
        util.setNodeText(this.ownerAndDateNode,text);
      }
    },

    _renderThumbnail: function(item) {
      var show = AppContext.appConfig.searchResults.showThumbnails;
      var thumbnailNode = this.thumbnailNode;
      if (show && typeof item.thumbnail_s === "string" && item.thumbnail_s.indexOf("http") === 0) {
        setTimeout(function(){thumbnailNode.src = item.thumbnail_s;},1);
      } else {
        thumbnailNode.style.display = "none";
      }
      //thumbnailNode.src = "http://placehold.it/80x60";
    },

    _uniqueLinks: function(item) {
      var links = [];
      if (typeof item.links_s === "string") {
        links = [item.links_s];
      } else if (lang.isArray(item.links_s)) {
        array.forEach(item.links_s, function(u){
          if (links.indexOf(u) === -1) links.push(u);
        });
      }
      return links;
    }

  });

  return oThisClass;
});<commit_msg>Dropdowns<commit_after>/* See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Esri Inc. licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
define(["dojo/_base/declare",
        "dojo/_base/lang",
        "dojo/_base/array",
        "dojo/topic",
        "app/context/app-topics",
        "dojo/dom-class",
        "dojo/dom-construct",
        "dijit/_WidgetBase",
        "dijit/_TemplatedMixin",
        "dijit/_WidgetsInTemplateMixin",
        "dojo/text!./templates/ItemCard.html",
        "dojo/i18n!app/nls/resources",
        "app/context/AppClient",
        "app/etc/util",
        "app/common/ConfirmationDialog",
        "app/content/ChangeOwner",
        "app/content/MetadataEditor",
        "app/context/metadata-editor",
        "app/content/UploadMetadata"],
function(declare, lang, array, topic, appTopics, domClass, domConstruct,
    _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, template, i18n,
    AppClient, util, ConfirmationDialog, ChangeOwner, MetadataEditor, gxeConfig,
    UploadMetadata) {

  var oThisClass = declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {

    i18n: i18n,
    templateString: template,

    isItemCard: true,
    item: null,
    itemsNode: null,
    searchPane: null,

    postCreate: function() {
      this.inherited(arguments);
      var self = this;
      topic.subscribe(appTopics.ItemOwnerChanged,function(params){
        if (self.item && self.item === params.item) {
          self._renderOwnerAndDate(self.item);
        }
      });
    },

    render: function(hit) {
      var item = this.item = hit._source;
      item._id = hit._id;
      var links = this._uniqueLinks(item);
      util.setNodeText(this.titleNode,item.title);
      this._renderOwnerAndDate(item);
      util.setNodeText(this.descriptionNode,item.description);
      this._renderThumbnail(item);
      this._renderItemLinks(hit._id,item);
      this._renderLinksDropdown(item,links);
      this._renderOptionsDropdown(hit._id,item);
      this._renderAddToMap(item,links);
    },

    _canEditMetadata: function(item,isOwner,isAdmin,isPublisher) {
      var v;
      if ((isOwner && isPublisher) || isAdmin) {
        v = item.sys_metadatatype_s;
        if (typeof v === "string") {
          if (gxeConfig.editable.geoportalTypes.indexOf(v) !== -1) {
            if (gxeConfig.editable.allowNonGxeDocs) {
              return true;
            }
            v = item.app_editor_s;
            if (typeof v === "string" && v === "gxe") {
              return true;
            }
          }
        }
      }
      return false;
    },

    _isOwner: function(item) {
      var username = AppContext.appUser.getUsername();
      if (typeof username === "string" && username.length > 0) {
        return (username === item.sys_owner_s);
      }
      return false;
    },

    _mitigateDropdownClip: function(dd,ddul) {
      // Bootstrap dropdown menus clipped by scrollable container
      var self = this;
      var reposition = function() {
        //console.warn($(dd).offset());
        var t = $(dd).offset().top + 15 - $(window).scrollTop();
        var l = $(dd).offset().left;
        $(ddul).css('top',t);
        $(ddul).css('left',l);

        var position = dd.getBoundingClientRect().top;
        var buttonHeight = dd.getBoundingClientRect().height;
        var menuHeight = $(ddul).outerHeight();
        var winHeight = $(window).height();
        if (position > menuHeight && winHeight - position < buttonHeight + menuHeight) {
          //console.warn("dropup","position:",position,"t",t,"buttonHeight",buttonHeight,"menuHeight",menuHeight);
          t = t - menuHeight - buttonHeight - 4;
          $(ddul).css('top',t);
        }
      };
      $(ddul).css("position","fixed");
      $(dd).on('click', function() {reposition();});
      //$(window).scroll(function() {reposition();});
      //$(this.itemsNode).scroll(function() {reposition();});
      //$(window).resize(function() {reposition();});
    },

    _renderAddToMap: function(item,links) {
      if (links.length === 0) return;
      var endsWith = function(v,sfx) {return (v.indexOf(sfx,(v.length-sfx.length)) !== -1);};
      var actionsNode = this.actionsNode;
      array.some(links, function(u){
        // "mapserver" "featureserver" "imageserver" "kml" "wms" "agsrest" "ags" "webmap"
        var lc, linkType = null, linkUrl = null;
        if (typeof u === "string" && (u.indexOf("http://") === 0 || u.indexOf("https://") === 0)) {
          lc = u.toLowerCase();
          if (lc.indexOf("service=") > 0) {
            if (lc.indexOf("?service=wms") > 0 || lc.indexOf("&service=wms") > 0) {
              linkType = "wms";
              linkUrl = u;
            }
          } else if (lc.indexOf("/rest/services") > 0) {
            if (endsWith(lc,"/mapserver")) {
              linkType = "MapServer";
              linkUrl = u;
            } else if (endsWith(lc,"/featureserver")) {
              linkType = "FeatureServer";
              linkUrl = u;
            } else if (endsWith(lc,"/imageserver")) {
              linkType = "ImageServer";
              linkUrl = u;
            }
          }
          if (linkType === null) {
            if (endsWith(lc,".kml") || endsWith(lc,".kmz") ||
                lc.indexOf("?f=kml") > 0 || lc.indexOf("&f=kml") > 0 ||
                lc.indexOf("?f=kmz") > 0 || lc.indexOf("&f=kmz") > 0) {
              linkType = "kml";
              linkUrl = u;
            }
          }
        }

        if (typeof linkUrl === "string") {
          //console.warn(linkType,linkUrl);
          domConstruct.create("a",{
            href: "javascript:void(0)",
            innerHTML: i18n.item.actions.addToMap,
            onclick: function() {
              topic.publish(appTopics.AddToMapClicked,{
                type: linkType,
                url: linkUrl
              });
            }
          },actionsNode);
          return true;
        }
      });
    },

    _renderItemLinks: function(itemId,item) {
      var actionsNode = this.actionsNode;
      var uri = "./rest/metadata/item/"+encodeURIComponent(itemId);
      var htmlNode = domConstruct.create("a",{
        href: uri+"/html",
        target: "_blank",
        innerHTML: i18n.item.actions.html
      },actionsNode);
      var xmlNode = domConstruct.create("a",{
        href: uri+"/xml",
        target: "_blank",
        innerHTML: i18n.item.actions.xml
      },actionsNode);
      domConstruct.create("a",{
        href: uri+"?pretty=true",
        target: "_blank",
        innerHTML: i18n.item.actions.json
      },actionsNode);
      var v = item.sys_metadatatype_s;
      if (typeof v === "string" && v === "json") {
        htmlNode.style.visibility = "hidden";
        xmlNode.style.visibility = "hidden";
      }
    },

    _renderLinksDropdown: function(item,links) {
      if (links.length === 0) return;
      var dd = domConstruct.create("div",{
        "class": "dropdown",
        "style": "display:inline-block;"
      },this.actionsNode);
      var ddbtn = domConstruct.create("a",{
        "class": "dropdown-toggle",
        "href": "#",
        "data-toggle": "dropdown",
        "aria-haspopup": true,
        "aria-expanded": true,
        innerHTML: i18n.item.actions.links
      },dd);
      domConstruct.create("span",{
        "class": "caret"
      },ddbtn);
      var ddul = domConstruct.create("ul",{
        "class": "dropdown-menu",
      },dd);
      array.forEach(links, function(u){
        var ddli = domConstruct.create("li",{},ddul);
        domConstruct.create("a",{
          "class": "small",
          href: u,
          target: "_blank",
          innerHTML: u
        },ddli);
      });
      this._mitigateDropdownClip(dd,ddul);
    },

    _renderOptionsDropdown: function(itemId,item) {
      var self = this;
      var isOwner = this._isOwner(item);
      var isAdmin = AppContext.appUser.isAdmin();
      var isPublisher = AppContext.appUser.isPublisher();
      var links = [];

      if (this._canEditMetadata(item,isOwner,isAdmin,isPublisher)) {
        links.push(domConstruct.create("a",{
          "class": "small",
          href: "javascript:void(0)",
          innerHTML: i18n.item.actions.options.editMetadata,
          onclick: function() {
            var editor = new MetadataEditor({itemId:itemId});
            editor.show();
          }
        }));
      }

      if ((isOwner && isPublisher) || isAdmin) {

        links.push(domConstruct.create("a",{
          "class": "small",
          href: "javascript:void(0)",
          innerHTML: i18n.item.actions.options.uploadMetadata,
          onclick: function() {
            (new UploadMetadata({itemId:itemId})).show();
          }
        }));

        links.push(domConstruct.create("a",{
          "class": "small",
          href: "javascript:void(0)",
          innerHTML: i18n.item.actions.options.deleteItem,
          onclick: function() {
            var dialog = new ConfirmationDialog({
              title: i18n.item.actions.options.deleteItem,
              content: item.title,
              okLabel: i18n.general.del,
              status: "danger"
            });
            dialog.show().then(function(ok){
              if (ok) {
                dialog.okCancelBar.showWorking(i18n.general.deleting,false);
                var client = new AppClient();
                client.deleteItem(itemId).then(function(response){
                  topic.publish(appTopics.ItemDeleted,{
                    itemId: itemId,
                    searchPane: self.searchPane
                  });
                  self.domNode.style.display = "none";
                  dialog.hide();
                }).otherwise(function(error){
                  var msg = i18n.general.error;
                  console.warn("deleteItem.error",error);
                  dialog.okCancelBar.showError(msg,false);
                });
              }
            });
          }
        }));
      }

      if (isAdmin) {
        links.push(domConstruct.create("a",{
          "class": "small",
          href: "javascript:void(0)",
          innerHTML: i18n.item.actions.options.changeOwner,
          onclick: function() {
            var dialog = new ChangeOwner({item:item});
            dialog.show();
          }
        }));
      }

      if (links.length === 0) return;

      var dd = domConstruct.create("div",{
        "class": "dropdown",
        "style": "display:inline-block;"
      },this.actionsNode);
      var ddbtn = domConstruct.create("a",{
        "class": "dropdown-toggle",
        "href": "#",
        "data-toggle": "dropdown",
        "aria-haspopup": true,
        "aria-expanded": true,
        innerHTML: i18n.item.actions.options.caption
      },dd);
      domConstruct.create("span",{
        "class": "caret"
      },ddbtn);
      var ddul = domConstruct.create("ul",{
        "class": "dropdown-menu",
      },dd);
      array.forEach(links,function(link){
        var ddli = domConstruct.create("li",{},ddul);
        ddli.appendChild(link);
      });
      this._mitigateDropdownClip(dd,ddul);
    },

    _renderOwnerAndDate: function(item) {
      var owner = item.sys_owner_s;
      var date = item.sys_modified_dt;
      var idx, text = "";
      if (AppContext.appConfig.searchResults.showDate && typeof date === "string" && date.length > 0) {
        idx = date.indexOf("T");
        if (idx > 0) date =date.substring(0,idx);
        text = date;
      }
      if (AppContext.appConfig.searchResults.showOwner && typeof owner === "string" && owner.length > 0) {
        if (text.length > 0) text += " ";
        text += owner;
      }
      if (text.length > 0) {
        util.setNodeText(this.ownerAndDateNode,text);
      }
    },

    _renderThumbnail: function(item) {
      var show = AppContext.appConfig.searchResults.showThumbnails;
      var thumbnailNode = this.thumbnailNode;
      if (show && typeof item.thumbnail_s === "string" && item.thumbnail_s.indexOf("http") === 0) {
        setTimeout(function(){thumbnailNode.src = item.thumbnail_s;},1);
      } else {
        thumbnailNode.style.display = "none";
      }
      //thumbnailNode.src = "http://placehold.it/80x60";
    },

    _uniqueLinks: function(item) {
      var links = [];
      if (typeof item.links_s === "string") {
        links = [item.links_s];
      } else if (lang.isArray(item.links_s)) {
        array.forEach(item.links_s, function(u){
          if (links.indexOf(u) === -1) links.push(u);
        });
      }
      return links;
    }

  });

  return oThisClass;
});<|endoftext|>


<commit_before>"use strict";
const MatrixAction = require("../../lib/models/MatrixAction");

describe("MatrixAction", function() {
    it("should not highlight mentions to text without mentions", () => {
        let action = new MatrixAction("message", "Some text", "Some text", null);
        action.formatMentions({
            "Some Person": "@foobar:localhost"
        });
        expect(action.text).toEqual("Some text");
        expect(action.text).toEqual("Some text");
    });
    it("should highlight a user", () => {
        let action = new MatrixAction("message", "JCDenton, it's a bomb!", "JCDenton, it's a bomb!", null);
        action.formatMentions({
            "JCDenton": "@jc.denton:unatco.gov"
        });
        expect(action.text).toEqual("JCDenton, it's a bomb!");
        expect(action.htmlText).toEqual("JCDenton, it's a bomb!");
    });
    it("should highlight a user, regardless of case", () => {
        let action = new MatrixAction("message", "JCDenton, it's a bomb!", "JCDenton, it's a bomb!", null);
        action.formatMentions({
            "jcdenton": "@jc.denton:unatco.gov"
        });
        expect(action.text).toEqual("JCDenton, it's a bomb!");
        expect(action.htmlText).toEqual("jcdenton, it's a bomb!");
    });
    it("should highlight a user, with plain text", () => {
        let action = new MatrixAction("message", "JCDenton, it's a bomb!");
        action.formatMentions({
            "JCDenton": "@jc.denton:unatco.gov"
        });
        expect(action.text).toEqual("JCDenton, it's a bomb!");
        expect(action.htmlText).toEqual("JCDenton, it's a bomb!");
    });
    it("should highlight a user, with weird characters", () => {
        let action = new MatrixAction("message", "`||JCDenton[m], it's a bomb!");
        action.formatMentions({
            "`||JCDenton[m]": "@jc.denton:unatco.gov"
        });
        expect(action.text).toEqual("`||JCDenton[m], it's a bomb!");
        expect(action.htmlText).toEqual("`||JCDenton[m], it's a bomb!");
    });
    it("should highlight multiple users", () => {
        let action = new MatrixAction("message", "JCDenton is sent to assassinate PaulDenton", "JCDenton is sent to assassinate PaulDenton", null);
        action.formatMentions({
            "JCDenton": "@jc.denton:unatco.gov",
            "PaulDenton": "@paul.denton:unatco.gov"
        });
        expect(action.text).toEqual("JCDenton is sent to assassinate PaulDenton");
        expect(action.htmlText).toEqual(
            "JCDenton is sent" +
            " to assassinate PaulDenton");
    });
    it("should highlight multiple mentions of the same user", () => {
        let action = new MatrixAction("message", "JCDenton, meet JCDenton", "JCDenton, meet JCDenton", null);
        action.formatMentions({
            "JCDenton": "@jc.denton:unatco.gov"
        });
        expect(action.text).toEqual("JCDenton, meet JCDenton");
        expect(action.htmlText).toEqual("JCDenton, meet JCDenton");
    });
});
<commit_msg>Check we don't generate html on non-matches<commit_after>"use strict";
const MatrixAction = require("../../lib/models/MatrixAction");

describe("MatrixAction", function() {
    it("should not highlight mentions to text without mentions", () => {
        let action = new MatrixAction("message", "Some text");
        action.formatMentions({
            "Some Person": "@foobar:localhost"
        });
        expect(action.text).toEqual("Some text");
        expect(action.htmlText).toBeUndefined();
    });
    it("should highlight a user", () => {
        let action = new MatrixAction("message", "JCDenton, it's a bomb!", "JCDenton, it's a bomb!", null);
        action.formatMentions({
            "JCDenton": "@jc.denton:unatco.gov"
        });
        expect(action.text).toEqual("JCDenton, it's a bomb!");
        expect(action.htmlText).toEqual("JCDenton, it's a bomb!");
    });
    it("should highlight a user, regardless of case", () => {
        let action = new MatrixAction("message", "JCDenton, it's a bomb!", "JCDenton, it's a bomb!", null);
        action.formatMentions({
            "jcdenton": "@jc.denton:unatco.gov"
        });
        expect(action.text).toEqual("JCDenton, it's a bomb!");
        expect(action.htmlText).toEqual("jcdenton, it's a bomb!");
    });
    it("should highlight a user, with plain text", () => {
        let action = new MatrixAction("message", "JCDenton, it's a bomb!");
        action.formatMentions({
            "JCDenton": "@jc.denton:unatco.gov"
        });
        expect(action.text).toEqual("JCDenton, it's a bomb!");
        expect(action.htmlText).toEqual("JCDenton, it's a bomb!");
    });
    it("should highlight a user, with weird characters", () => {
        let action = new MatrixAction("message", "`||JCDenton[m], it's a bomb!");
        action.formatMentions({
            "`||JCDenton[m]": "@jc.denton:unatco.gov"
        });
        expect(action.text).toEqual("`||JCDenton[m], it's a bomb!");
        expect(action.htmlText).toEqual("`||JCDenton[m], it's a bomb!");
    });
    it("should highlight multiple users", () => {
        let action = new MatrixAction("message", "JCDenton is sent to assassinate PaulDenton", "JCDenton is sent to assassinate PaulDenton", null);
        action.formatMentions({
            "JCDenton": "@jc.denton:unatco.gov",
            "PaulDenton": "@paul.denton:unatco.gov"
        });
        expect(action.text).toEqual("JCDenton is sent to assassinate PaulDenton");
        expect(action.htmlText).toEqual(
            "JCDenton is sent" +
            " to assassinate PaulDenton");
    });
    it("should highlight multiple mentions of the same user", () => {
        let action = new MatrixAction("message", "JCDenton, meet JCDenton", "JCDenton, meet JCDenton", null);
        action.formatMentions({
            "JCDenton": "@jc.denton:unatco.gov"
        });
        expect(action.text).toEqual("JCDenton, meet JCDenton");
        expect(action.htmlText).toEqual("JCDenton, meet JCDenton");
    });
});
<|endoftext|>


<commit_before>/*jshint asi: true */
var UNDEFINED = {}
var FALSE = {}

function lz(list) {
  this.fn = []
  this.i = 0
  this.length = list.length

  this.list = list

  if (!(this instanceof lz)) {
    return new lz(list)
  }
}

Object.defineProperty(Array.prototype, 'lz', {
  value: function () {
    return new lz(this)
  },
  enumerable: false
})

lz.prototype.$ = lz.prototype.toArray = function () {
  if (this._value) {
    return this._value
  }

  var results = []
  var item
  var n = this.length

  while (n > 0) {
    item = this.next()
    if (item === UNDEFINED) break
    results.push(item)
    n -= 1
  }

  this._value = results

  return results
}

lz.prototype.cycle = function () {
  return lz.cycle(this.list)
}

lz.prototype.drop = function (n) {
  this._value = null
  var item

  while (n > 0) {
    item = this.next()
    if (item === UNDEFINED) {
      this._value = []
      return this
    }
    n -= 1
  }

  this.list = this.list.slice(this.i)

  // partial reset
  this.i = 0
  this.length = this.list.length

  return this
}

lz.prototype.dropWhile = function (fn) {
  this._value = null
  var item

  while (true) {
    item = this.next()
    if (item === UNDEFINED) {
      this._value = []
      return this
    }
    if (fn(item) === false) break
  }

  this.list = this.list.slice(this.i - 1)

  // partial reset
  this.i = 0
  this.length = this.list.length

  return this
}

lz.prototype.filter = function (f) {
  this._value = null
  this.fn.push(function (x) {
    if (f(x) === true) return x
    else return FALSE
  })
  return this
}

lz.prototype.init = function () {
  var results = []
  var item
  var n = this.length

  while (n > 0) {
    item = this.next()
    if (item === UNDEFINED) break
    results.push(item)
    n -= 1
  }

  results.pop()

  this.list = this._value = results

  // reset
  this.fn = []
  this.i = 0
  this.length = this.list.length

  return this
}

lz.prototype.map = function (f) {
  this._value = null
  this.fn.push(function (x) { return f(x) })
  return this
}

lz.prototype.next = function () {
  var item = this.list[this.i++]
  if (this.i > this.length) return UNDEFINED
  for (var j = 0; j < this.fn.length; j += 1) {
    item = this.fn[j](item)
    if (item === FALSE) return this.next()
  }
  return item
}

lz.prototype.nil = function () {
  if (this.length === 0) return true

  while (true) {
    item = this.next()
    if (item != null) return false
    if (item === UNDEFINED) break
  }

  return true
}

lz.prototype.prev = function () {
  var item = this.list[--this.i]
  if (this.i === -1) return UNDEFINED
  for (var j = 0; j < this.fn.length; j += 1) {
    item = this.fn[j](item)
    if (item === FALSE) return this.prev()
  }
  return item
}

lz.prototype.tail = function () {
  var results = []
  var item
  var n = this.length

  while (n > 0) {
    item = this.next()
    if (item === UNDEFINED) break
    results.push(item)
    n -= 1
  }

  results.shift()

  this.list = this._value = results

  // reset
  this.fn = []
  this.i = 0
  this.length = this.list.length

  return this
}

lz.prototype.take = function (n) {
  var results = []
  var item

  while (n > 0) {
    item = this.next()
    if (item === UNDEFINED) break
    results.push(item)
    n -= 1
  }

  this.list = this._value = results

  // reset
  this.fn = []
  this.i = 0
  this.length = this.list.length

  return this
}

lz.prototype.takeWhile = function (fn) {
  var results = []
  var result
  var item

  while (true) {
    item = this.next()
    if (item === UNDEFINED) break
    result = fn(item)
    if (result === true) results.push(item)
    else break
  }

  this.list = this._value = results

  // reset
  this.fn = []
  this.i = 0
  this.length = this.list.length

  return this
}

lz.prototype.zipWith = function (fn, list) {
  return lz.zipWith(fn, list, this.list)
}

// @value
lz.prototype.and = function () {
  var item

  while (true) {
    item = this.next()
    if (item === false) return false
    if (item === UNDEFINED) break
  }

  return true
}

// @value
lz.prototype.any = function (fn) {
  var item

  while (true) {
    item = this.next()
    if (fn(item) === true) return true
    if (item === UNDEFINED) return false
  }

  return false
}

// @value
lz.prototype.foldl = function (fn) {
  var result, next
  result = this.next()
  if (result === UNDEFINED) return null
  while (true) {
    next = this.next()
    if (next === UNDEFINED) break
    result = fn(result, next)
  }
  return result
}

// @value
lz.prototype.elem = function (n) {
  var item
  while (true) {
    item = this.next()
    if (item === UNDEFINED) break
    if (item === n) return true
  }
  return false
}

// @value
lz.prototype.head = function () {
  var item
  return (item = this.next()) === UNDEFINED ? null : item
}

// @value
lz.prototype.last = function () {
  var item
  this.i = this.length
  return (item = this.prev()) === UNDEFINED ? null : item
}

// @value
lz.prototype.or = function () {
  var item

  while (true) {
    item = this.next()
    if (item === true) return true
    if (item === UNDEFINED) break
  }

  return false
}

lz.cycle = function (list) {
  var z = new lz(list)
  var length = list.length
  z.length = Infinity
  z._next = z.next
  z.next = function () {
    if (this.i === length) {
      this.i = 0
    }
    return this._next()
  }
  return z
}

lz.range = function (start, end) {
  var i = new lz([])
  i.length = end
  i._next = i.next
  i.next = function () {
    this.list.push(this.i + start)
    return i._next()
  }
  return i
}

lz.zipWith = function (fn, list1, list2) {
  var z = new lz([])
  z.length = list1.length < list2.length ? list1.length : list2.length

  if (!(list1 instanceof lz) && !(list2 instanceof lz)) {
    z.next = function () {
      if (this.i >= this.length) return UNDEFINED
      return fn(list1[this.i], list2[this.i++])
    }
    return z
  } else {
    if (!(list1 instanceof lz)) list1 = lz(list1)
    if (!(list2 instanceof lz)) list2 = lz(list2)
    z._next = z.next
    z.next = function () {
      this.list.push(fn(list1.next(), list2.next()))
      return this._next()
    }
    return z
  }
}

module.exports = lz
<commit_msg>Adds an all method | Moves nil<commit_after>/*jshint asi: true */
var UNDEFINED = {}
var FALSE = {}

function lz(list) {
  this.fn = []
  this.i = 0
  this.length = list.length

  this.list = list

  if (!(this instanceof lz)) {
    return new lz(list)
  }
}

Object.defineProperty(Array.prototype, 'lz', {
  value: function () {
    return new lz(this)
  },
  enumerable: false
})

lz.prototype.$ = lz.prototype.toArray = function () {
  if (this._value) {
    return this._value
  }

  var results = []
  var item
  var n = this.length

  while (n > 0) {
    item = this.next()
    if (item === UNDEFINED) break
    results.push(item)
    n -= 1
  }

  this._value = results

  return results
}

lz.prototype.cycle = function () {
  return lz.cycle(this.list)
}

lz.prototype.drop = function (n) {
  this._value = null
  var item

  while (n > 0) {
    item = this.next()
    if (item === UNDEFINED) {
      this._value = []
      return this
    }
    n -= 1
  }

  this.list = this.list.slice(this.i)

  // partial reset
  this.i = 0
  this.length = this.list.length

  return this
}

lz.prototype.dropWhile = function (fn) {
  this._value = null
  var item

  while (true) {
    item = this.next()
    if (item === UNDEFINED) {
      this._value = []
      return this
    }
    if (fn(item) === false) break
  }

  this.list = this.list.slice(this.i - 1)

  // partial reset
  this.i = 0
  this.length = this.list.length

  return this
}

lz.prototype.filter = function (f) {
  this._value = null
  this.fn.push(function (x) {
    if (f(x) === true) return x
    else return FALSE
  })
  return this
}

lz.prototype.init = function () {
  var results = []
  var item
  var n = this.length

  while (n > 0) {
    item = this.next()
    if (item === UNDEFINED) break
    results.push(item)
    n -= 1
  }

  results.pop()

  this.list = this._value = results

  // reset
  this.fn = []
  this.i = 0
  this.length = this.list.length

  return this
}

lz.prototype.map = function (f) {
  this._value = null
  this.fn.push(function (x) { return f(x) })
  return this
}

lz.prototype.next = function () {
  var item = this.list[this.i++]
  if (this.i > this.length) return UNDEFINED
  for (var j = 0; j < this.fn.length; j += 1) {
    item = this.fn[j](item)
    if (item === FALSE) return this.next()
  }
  return item
}

lz.prototype.prev = function () {
  var item = this.list[--this.i]
  if (this.i === -1) return UNDEFINED
  for (var j = 0; j < this.fn.length; j += 1) {
    item = this.fn[j](item)
    if (item === FALSE) return this.prev()
  }
  return item
}

lz.prototype.tail = function () {
  var results = []
  var item
  var n = this.length

  while (n > 0) {
    item = this.next()
    if (item === UNDEFINED) break
    results.push(item)
    n -= 1
  }

  results.shift()

  this.list = this._value = results

  // reset
  this.fn = []
  this.i = 0
  this.length = this.list.length

  return this
}

lz.prototype.take = function (n) {
  var results = []
  var item

  while (n > 0) {
    item = this.next()
    if (item === UNDEFINED) break
    results.push(item)
    n -= 1
  }

  this.list = this._value = results

  // reset
  this.fn = []
  this.i = 0
  this.length = this.list.length

  return this
}

lz.prototype.takeWhile = function (fn) {
  var results = []
  var result
  var item

  while (true) {
    item = this.next()
    if (item === UNDEFINED) break
    result = fn(item)
    if (result === true) results.push(item)
    else break
  }

  this.list = this._value = results

  // reset
  this.fn = []
  this.i = 0
  this.length = this.list.length

  return this
}

lz.prototype.zipWith = function (fn, list) {
  return lz.zipWith(fn, list, this.list)
}

// @value
lz.prototype.and = function () {
  var item

  while (true) {
    item = this.next()
    if (item === false) return false
    if (item === UNDEFINED) break
  }

  return true
}

// @value
lz.prototype.all = function (fn) {
  var item

  while (true) {
    item = this.next()
    if (fn(item) === false) return false
    if (item === UNDEFINED) break
  }

  return true
}

// @value
lz.prototype.any = function (fn) {
  var item

  while (true) {
    item = this.next()
    if (fn(item) === true) return true
    if (item === UNDEFINED) break
  }

  return false
}

// @value
lz.prototype.foldl = function (fn) {
  var result, next
  result = this.next()
  if (result === UNDEFINED) return null
  while (true) {
    next = this.next()
    if (next === UNDEFINED) break
    result = fn(result, next)
  }
  return result
}

// @value
lz.prototype.elem = function (n) {
  var item
  while (true) {
    item = this.next()
    if (item === UNDEFINED) break
    if (item === n) return true
  }
  return false
}

// @value
lz.prototype.head = function () {
  var item
  return (item = this.next()) === UNDEFINED ? null : item
}

// @value
lz.prototype.last = function () {
  var item
  this.i = this.length
  return (item = this.prev()) === UNDEFINED ? null : item
}

// @value
lz.prototype.nil = function () {
  if (this.length === 0) return true

  while (true) {
    item = this.next()
    if (item != null) return false
    if (item === UNDEFINED) break
  }

  return true
}

// @value
lz.prototype.or = function () {
  var item

  while (true) {
    item = this.next()
    if (item === true) return true
    if (item === UNDEFINED) break
  }

  return false
}

lz.cycle = function (list) {
  var z = new lz(list)
  var length = list.length
  z.length = Infinity
  z._next = z.next
  z.next = function () {
    if (this.i === length) {
      this.i = 0
    }
    return this._next()
  }
  return z
}

lz.range = function (start, end) {
  var i = new lz([])
  i.length = end
  i._next = i.next
  i.next = function () {
    this.list.push(this.i + start)
    return i._next()
  }
  return i
}

lz.zipWith = function (fn, list1, list2) {
  var z = new lz([])
  z.length = list1.length < list2.length ? list1.length : list2.length

  if (!(list1 instanceof lz) && !(list2 instanceof lz)) {
    z.next = function () {
      if (this.i >= this.length) return UNDEFINED
      return fn(list1[this.i], list2[this.i++])
    }
    return z
  } else {
    if (!(list1 instanceof lz)) list1 = lz(list1)
    if (!(list2 instanceof lz)) list2 = lz(list2)
    z._next = z.next
    z.next = function () {
      this.list.push(fn(list1.next(), list2.next()))
      return this._next()
    }
    return z
  }
}

module.exports = lz
<|endoftext|>


<commit_before>
featureToggleFrontend.controller('TogglesController', ['$scope', '$timeout', 'toggleService', 'applicationService', 'focus', 'ENV', '$rootScope', function($scope, $timeout, toggleService, applicationService, focus, ENV, $rootScope) {

    $scope.adding = false;
    $scope.newToggleName = '';
    $scope.setAddingToggleState = function(state){
        $scope.adding = state;
        if (state){
            $scope.newToggleName = $scope.toggleSuggestions[0];
            focus('newToggleName');
        }
    };

    $scope.updateThisToggle = function(toggle){
        $timeout(function(){
            toggleService.updateFeatureToggle($scope.applicationName, $scope.featureName,
                $scope.isMultiToggle, toggle.name, toggle.value,
                function(){
                    $rootScope.$broadcast('toggleUpdated', toggle, $scope.isMultiToggle);
                },
                function(data){
                    $scope.$emit('error', "Failed to update toggle", new Error(data));
                });
        });
    };

    var validateNewToggle = function(toggleName){
        if (!toggleName){
            return "Must enter an toggle name";
        }
        if (!_.contains($scope.toggleSuggestions, toggleName)){
            return "Not a valid toggle name. Please use the autocomplete box to get valid values.";
        }
        if (_.any($scope.toggles, function(toggle){ return toggle.name === toggleName;})){
            return "Toggle name must be unique in this application";
        }
    };

    var addFakeToggle = function(toggleName){
        $scope.toggles.push({
            name: toggleName,
            value: false
        });
        $scope.toggleSuggestions = _.without($scope.toggleSuggestions, toggleName);
    };

    $scope.addToggle = function() {
        var applicationName = $scope.applicationName;
        var featureName = $scope.featureName;
        var toggleName = $scope.newToggleName.trim();

        var validationError = validateNewToggle(toggleName);
        if (validationError){
            $scope.$emit('error', validationError);
            return;
        }

        toggleService.addFeatureToggle(applicationName, featureName, toggleName,
            function(){
                addFakeToggle(toggleName);
                $scope.setAddingToggleState(false);
                $scope.$emit('success', toggleName + " was successfully added");
            },
            function(data){
                $scope.$emit('error', "Failed to add feature", new Error(data));
            });
    };

    var addGithubSearchDataToToggles = function(feature, metaData){
        var githubRepoUrl = metaData.githubRepoUrl;
        if (githubRepoUrl){
            _.each($scope.toggles, function(toggle){
                var searchPhrase = feature.isMultiToggle ? $scope.featureName + '+AND+' + toggle.name : $scope.featureName;
                toggle.githubSearchUrl = githubRepoUrl + '/search?utf8=✓&type=Code&q=' + searchPhrase + '+AND+getOrDefault';
            });
        }
    };

    (function loadFeatureToggles() {
        $scope.toggles = [];
        $scope.loadingToggles = true;
        $scope.isMultiToggle = false;

        toggleService.getFeature($scope.applicationName, $scope.featureName,
            function(feature){
                $scope.toggles = feature.toggles;
                $scope.isMultiToggle = feature.isMultiToggle;
                $scope.toggleSuggestions = feature.toggleSuggestions;
                $scope.loadingToggles = false;

                applicationService.getApplicationMetaData($scope.applicationName, function(err, metaData){
                    if (err){
                        return $scope.$emit('error', "Failed to get Github search data for these toggles", new Error(err));
                    }
                    addGithubSearchDataToToggles(feature, metaData);
                });
            },
            function(data){
                $scope.$emit('error', "Failed to load this feature toggle", new Error(data));
                $scope.loadingToggles = false;
            });
    })();

}]);
<commit_msg>Now only using feature toggle name for seach<commit_after>
featureToggleFrontend.controller('TogglesController', ['$scope', '$timeout', 'toggleService', 'applicationService', 'focus', 'ENV', '$rootScope', function($scope, $timeout, toggleService, applicationService, focus, ENV, $rootScope) {

    $scope.adding = false;
    $scope.newToggleName = '';
    $scope.setAddingToggleState = function(state){
        $scope.adding = state;
        if (state){
            $scope.newToggleName = $scope.toggleSuggestions[0];
            focus('newToggleName');
        }
    };

    $scope.updateThisToggle = function(toggle){
        $timeout(function(){
            toggleService.updateFeatureToggle($scope.applicationName, $scope.featureName,
                $scope.isMultiToggle, toggle.name, toggle.value,
                function(){
                    $rootScope.$broadcast('toggleUpdated', toggle, $scope.isMultiToggle);
                },
                function(data){
                    $scope.$emit('error', "Failed to update toggle", new Error(data));
                });
        });
    };

    var validateNewToggle = function(toggleName){
        if (!toggleName){
            return "Must enter an toggle name";
        }
        if (!_.contains($scope.toggleSuggestions, toggleName)){
            return "Not a valid toggle name. Please use the autocomplete box to get valid values.";
        }
        if (_.any($scope.toggles, function(toggle){ return toggle.name === toggleName;})){
            return "Toggle name must be unique in this application";
        }
    };

    var addFakeToggle = function(toggleName){
        $scope.toggles.push({
            name: toggleName,
            value: false
        });
        $scope.toggleSuggestions = _.without($scope.toggleSuggestions, toggleName);
    };

    $scope.addToggle = function() {
        var applicationName = $scope.applicationName;
        var featureName = $scope.featureName;
        var toggleName = $scope.newToggleName.trim();

        var validationError = validateNewToggle(toggleName);
        if (validationError){
            $scope.$emit('error', validationError);
            return;
        }

        toggleService.addFeatureToggle(applicationName, featureName, toggleName,
            function(){
                addFakeToggle(toggleName);
                $scope.setAddingToggleState(false);
                $scope.$emit('success', toggleName + " was successfully added");
            },
            function(data){
                $scope.$emit('error', "Failed to add feature", new Error(data));
            });
    };

    var addGithubSearchDataToToggles = function(feature, metaData){
        var githubRepoUrl = metaData.githubRepoUrl;
        if (githubRepoUrl){
            _.each($scope.toggles, function(toggle){
                var searchPhrase = feature.isMultiToggle ? $scope.featureName + '+AND+' + toggle.name : $scope.featureName;
                toggle.githubSearchUrl = githubRepoUrl + '/search?utf8=✓&type=Code&q=' + searchPhrase;
            });
        }
    };

    (function loadFeatureToggles() {
        $scope.toggles = [];
        $scope.loadingToggles = true;
        $scope.isMultiToggle = false;

        toggleService.getFeature($scope.applicationName, $scope.featureName,
            function(feature){
                $scope.toggles = feature.toggles;
                $scope.isMultiToggle = feature.isMultiToggle;
                $scope.toggleSuggestions = feature.toggleSuggestions;
                $scope.loadingToggles = false;

                applicationService.getApplicationMetaData($scope.applicationName, function(err, metaData){
                    if (err){
                        return $scope.$emit('error', "Failed to get Github search data for these toggles", new Error(err));
                    }
                    addGithubSearchDataToToggles(feature, metaData);
                });
            },
            function(data){
                $scope.$emit('error', "Failed to load this feature toggle", new Error(data));
                $scope.loadingToggles = false;
            });
    })();

}]);
<|endoftext|>