<commit_before>// ==UserScript==
// @name           Gmail Macros (New)
// @namespace      http://persistent.info
// @include        http://mail.google.com/*
// @include        https://mail.google.com/*
// ==/UserScript==

window.addEventListener('load', function() {
  if (unsafeWindow.gmonkey) {
    unsafeWindow.gmonkey.load('1.0', init)
  }
}, true);

var UNREAD_COUNT_RE = /\s+\(\d+\)?$/;

var MORE_ACTIONS_MENU_HEADER_CLASS = "QOD9Ec";
var MORE_ACTIONS_MENU_BODY_CLASS = "Sn99bd";
var MORE_ACTIONS_MENU_ITEM_CLASS = "SenFne";

var LABEL_ITEM_CLASS_NAME = "yyT6sf";

var MARK_AS_READ_ACTION = "1";
var ARCHIVE_ACTION = "7";
var ADD_LABEL_ACTION = "12";
var REMOVE_LABEL_ACTION = "13";

// Map from nav pane names to location names
var SPECIAL_LABELS = {
  "Inbox": "inbox",
  "Starred": "starred",
  "Chats": "chats",
  "Sent Mail": "sent",
  "Drafts": "drafts",
  "All Mail": "all",
  "Spam": "spam",
  "Trash": "trash"
}

const LABEL_ACTIONS = {
  // g: go to label
  71: {
    label: "Go to label",
    func: function(labelName) {
      if (labelName in SPECIAL_LABELS) {
        top.location.hash = "#" + SPECIAL_LABELS[labelName];
      } else {
        top.location.hash = "#label/" + encodeURIComponent(labelName);
      }
    }
  },
  // l: apply label
  76: {
    label: "Apply label",
    func: function (labelName) {
      clickMoreActionsMenuItem(labelName, ADD_LABEL_ACTION);
    },
  },
  // b: remove label
  66: {
    label: "Remove label",
    func: function (labelName) {
      clickMoreActionsMenuItem(labelName, REMOVE_LABEL_ACTION);
    }
  }
};

const ACTIONS = {
  // d: archive and mark as read, i.e. discard
  68: function() {
    clickMoreActionsMenuItem("Mark as read", MARK_AS_READ_ACTION);

    // Wait for the mark as read action to complete
    window.setTimeout(function() {
      // Just re-use the always archive action
      ACTIONS[69]();
    }, 500);
  },
  // f: focus (only show unread and inbox messages)
  70: function() {
    // Can only focus when in threadlist views
    if (gmail.getActiveViewType() != 'tl') return;

    var loc = top.location.hash;
    if (loc.length <= 1) return;
    loc = loc.substring(1);

    var search = getSearchForLocation(loc);

    if (search === null) {
      return;
    }

    search += " {in:inbox is:starred is:unread} -is:muted";

    top.location.hash = "#search/" + search;
  }
};

var LOC_TO_SEARCH = {
  "inbox": "in:inbox",
  "starred": "is:starred",
  "chats": "is:chat",
  "sent": "from:me",
  "drafts": "is:draft",
  "all": "",
  "spam": "in:spam",
  "trash": "in:trash"
};

var LABEL_PREFIX = "label/";

function getSearchForLocation(loc) {
  if (loc in LOC_TO_SEARCH) {
    return LOC_TO_SEARCH[loc];
  }

  if (loc.indexOf(LABEL_PREFIX) == 0) {
    var labelName = loc.substring(LABEL_PREFIX.length);

    // Normalize spaces to dashes, since that's what Gmail wants for searches
    labelName = labelName.replace(/\+/g, "-");

    return "label:" + labelName;
  }

  return null;
}

// TODO(mihaip): too many global variables, use objects
var banner = null;
var gmail = null;

var labelInput = null;
var activeLabelAction = null;
var lastPrefix = null;
var selLabelIndex = null;

function getDoc() {
  return gmail.getNavPaneElement().ownerDocument;
}

function newNode(tagName) {
  return getDoc().createElement(tagName);
}

function getNode(id) {
  return getDoc().getElementById(id);
}

function getFirstVisibleNode(nodes) {
  for (var i = 0, node; node = nodes[i]; i++) {
    if (node.offsetHeight) return node;
  }

  return null;
}

function simulateClick(node, eventType) {
  var event = node.ownerDocument.createEvent("MouseEvents");
  event.initMouseEvent(eventType,
                       true, // can bubble
                       true, // cancellable
                       node.ownerDocument.defaultView,
                       1, // clicks
                       50, 50, // screen coordinates
                       50, 50, // client coordinates
                       false, false, false, false, // control/alt/shift/meta
                       0, // button,
                       node);

  node.dispatchEvent(event);
}

function clickMoreActionsMenuItem(menuItemText, menuItemAction) {
  var moreActionsMenu = getFirstVisibleNode(getNodesByTagNameAndClass(
      getDoc().body, "div", MORE_ACTIONS_MENU_HEADER_CLASS));

  if (!moreActionsMenu) {
    alert("Couldn't find the menu header node");
    return;
  }

  simulateClick(moreActionsMenu, "mousedown");

  var menuBodyNodes = getNodesByTagNameAndClass(
      getDoc().body, "div", MORE_ACTIONS_MENU_BODY_CLASS);
  var menuBodyNode = getFirstVisibleNode(menuBodyNodes);

  if (!menuBodyNode) {
    alert("Couldn't find the menu body node");
    return;
  }

  var menuItemNodes = getNodesByTagNameAndClass(
      menuBodyNode, "div", MORE_ACTIONS_MENU_ITEM_CLASS);

  for (var i = 0; menuItemNode = menuItemNodes[i]; i++) {
    if (menuItemNode.textContent == menuItemText &&
        menuItemNode.getAttribute("act") == menuItemAction) {
      simulateClick(menuItemNode, "mouseup");
      return;
    }
  }

  alert("Couldn't find the menu item node '" + menuItemText + "'");
}

function init(g) {
  gmail = g;
  banner = new Banner();

  getDoc().defaultView.addEventListener('keydown', keyHandler, false);
}

function keyHandler(event) {
  // Apparently we still see Firefox shortcuts like control-T for a new tab -
  // checking for modifiers lets us ignore those
  if (event.altKey || event.ctrlKey || event.metaKey) return;

  // We also don't want to interfere with regular user typing
  if (event.target && event.target.nodeName) {
    var targetNodeName = event.target.nodeName.toLowerCase();
    if (targetNodeName == "textarea" ||
        (targetNodeName == "input" && event.target.type &&
         (event.target.type.toLowerCase() == "text" ||
          event.target.type.toLowerCase() == "file"))) {
      return;
    }
  }

  var k = event.keyCode;

  if (k in LABEL_ACTIONS) {
    if (activeLabelAction) {
      endLabelAction();
      return
    } else {
      activeLabelAction = LABEL_ACTIONS[k];
      beginLabelAction();
      return;
    }
  }

  if (k in ACTIONS) {
    ACTIONS[k]();
    return;
  }

  return;
}

function beginLabelAction() {
  // TODO(mihaip): make sure the labels nav pane is open

  banner.show();
  banner.setFooter(activeLabelAction.label);

  lastPrefix = null;
  selLabelIndex = 0;
  dispatchedActionTimeout = null;

  labelInput = makeLabelInput();
  labelInput.addEventListener("keyup", updateLabelAction, false);
  // we want escape, clicks, etc. to cancel, which seems to be equivalent to the
  // field losing focus
  labelInput.addEventListener("blur", endLabelAction, false);
}

function makeLabelInput() {
  labelInput = newNode("input");
  labelInput.type = "text";
  labelInput.setAttribute("autocomplete", "off");
  with (labelInput.style) {
    position = "fixed"; // We need to use fixed positioning since we have to ensure
                        // that the input is not scrolled out of view (since
                        // Gecko will scroll for us if it is).
    top = "0";
    left = "-300px";
    width = "200px";
    height = "20px";
    zIndex = "1000";
  }

  getDoc().body.appendChild(labelInput);
  labelInput.focus();
  labelInput.value = "";

  return labelInput;
}

function endLabelAction() {
  if (dispatchedActionTimeout) return;

  // TODO(mihaip): re-close label box if necessary

  banner.hide();

  if (labelInput) {
    labelInput.parentNode.removeChild(labelInput);
    labelInput = null;
  }

  activeLabelAction = null;
}

function updateLabelAction(event) {
  // We've already dispatched the action, the user is just typing away
  if (dispatchedActionTimeout) return;

  var labels = getLabels();
  var selectedLabels = [];

  // We need to skip the label shortcut that got us here
  var labelPrefix = labelInput.value.substring(1).toLowerCase();

  // We always want to reset the cursor position to the end of the text
  // field, since some of the keys that we support (arrows) would
  // otherwise change it
  labelInput.selectionStart = labelInput.selectionEnd = labelPrefix.length + 1;

  if (labelPrefix.length == 0) {
    banner.update("");
    return;
  }

  for (var i = 0; i < labels.length; i++) {
    label = labels[i];

    if (label.toLowerCase().indexOf(labelPrefix) == 0) {
      selectedLabels.push(label);
    }
  }

  if (labelPrefix != lastPrefix) {
    lastPrefix = labelPrefix;
    selLabelIndex = 0;
  }

  if (selectedLabels.length == 0) {
    banner.update(labelPrefix);
    return;
  }

  if (event.keyCode == 13 || selectedLabels.length == 1) {
    var selectedLabelName = selectedLabels[selLabelIndex];

    // Tell the user what we picked
    banner.update(selectedLabelName);

    // Invoke the action straight away, but keep the banner up so the user can
    // see what was picked, and so that extra typing is caught.
    activeLabelAction.func(selectedLabelName);
    dispatchedActionTimeout = window.setTimeout(function() {
      dispatchedActionTimeout = null;
      endLabelAction()
    }, 500);
    return;
  } else if (event.keyCode == 40) { // down
    selLabelIndex = (selLabelIndex + 1) % selectedLabels.length;
  } else if (event.keyCode == 38) { // up
    selLabelIndex = (selLabelIndex + selectedLabels.length - 1) %
        selectedLabels.length;
  }

  var selectedLabelName = selectedLabels[selLabelIndex];

  var highlightedSelectedLabelName = selectedLabelName.replace(
      new RegExp("(" + labelPrefix + ")", "i"), "$1");
  var labelPosition = " (" +
      (selLabelIndex + 1) + "/" + selectedLabels.length + ")";

  banner.update(highlightedSelectedLabelName + labelPosition);
}

function getLabels() {
  var navPaneNode = gmail.getNavPaneElement();

  var labelNodes = getNodesByTagNameAndClass(
      navPaneNode, "div", LABEL_ITEM_CLASS_NAME);

  var labels = [];

  for (var i = 0, labelNode; labelNode = labelNodes[i]; i++) {
    var labelName = labelNode.textContent.replace(UNREAD_COUNT_RE, "");

    labels.push(labelName);
  }

  return labels;
}

function evalXPath(expression, rootNode) {
  try {
    var xpathIterator = rootNode.ownerDocument.evaluate(
      expression,
      rootNode,
      null, // no namespace resolver
      XPathResult.ORDERED_NODE_ITERATOR_TYPE,
      null); // no existing results
  } catch (err) {
    GM_log("Error when evaluating XPath expression '" + expression + "'" +
           ": " + err);
    return null;
  }
  var results = [];

  // Convert result to JS array
  for (var xpathNode = xpathIterator.iterateNext();
       xpathNode;
       xpathNode = xpathIterator.iterateNext()) {
    results.push(xpathNode);
  }

  return results;
}

function getNodesByTagNameAndClass(rootNode, tagName, className) {
  var expression =
      ".//" + tagName +
      "[contains(concat(' ', @class, ' '), ' " + className + " ')]";

  return evalXPath(expression, rootNode);
}

function Banner() {
  function getNodeSet() {
    var boxNode = newNode("div");
    boxNode.className = "banner";
    with (boxNode.style) {
      display = "none";
      position = "fixed";
      left = "10%";
      margin = "0 10% 0 10%";
      width = "60%";
      textAlign = "center";
      MozBorderRadius = "10px";
      padding = "10px";
      color = "#fff";
    }

    var messageNode = newNode("div");
    with (messageNode.style) {
      fontSize = "24px";
      fontWeight = "bold";
      fontFamily = "Lucida Grande, Trebuchet MS, sans-serif";
      margin = "0 0 10px 0";
    }
    boxNode.appendChild(messageNode);

    var taglineNode = newNode("div");
    with (taglineNode.style) {
      fontSize = "13px";
      margin = "0";
      position = "absolute";
      right = "0.2em";
      bottom = "0";
      MozOpacity = "0.5";
    }
    taglineNode.innerHTML = 'LabelSelector9001';
    boxNode.appendChild(taglineNode);

    var footerNode = newNode("div");
    with (footerNode.style) {
      fontSize = "13px";
    }
    boxNode.appendChild(footerNode);

    return boxNode;
  }

  this.backgroundNode = getNodeSet();
  this.backgroundNode.style.background = "#000";
  this.backgroundNode.style.MozOpacity = "0.70";
  this.backgroundNode.style.zIndex = 100;
  for (var child = this.backgroundNode.firstChild;
       child;
       child = child.nextSibling) {
    child.style.visibility = "hidden";
  }

  this.foregroundNode = getNodeSet();
  this.foregroundNode.style.zIndex = 101;
}

Banner.prototype.hide = function() {
  this.backgroundNode.style.display =
    this.foregroundNode.style.display = "none";
}

Banner.prototype.show = function(opt_isBottomAnchored) {
  this.update("");
  getDoc().body.appendChild(this.backgroundNode);
  getDoc().body.appendChild(this.foregroundNode);

  this.backgroundNode.style.bottom = this.foregroundNode.style.bottom =
    opt_isBottomAnchored ? "10%" : "";
  this.backgroundNode.style.top = this.foregroundNode.style.top =
    opt_isBottomAnchored ? "" : "50%";

  this.backgroundNode.style.display =
    this.foregroundNode.style.display = "block";
}

Banner.prototype.update = function(message) {
  if (message.length) {
    this.backgroundNode.firstChild.style.display =
      this.foregroundNode.firstChild.style.display = "inline";
  } else {
    this.backgroundNode.firstChild.style.display =
      this.foregroundNode.firstChild.style.display = "none";
  }
  this.backgroundNode.firstChild.innerHTML =
    this.foregroundNode.firstChild.innerHTML = message;
}

Banner.prototype.setFooter = function(text) {
  this.backgroundNode.lastChild.innerHTML =
    this.foregroundNode.lastChild.innerHTML = text;
}
<commit_msg>Oops, the "d" command depended on the "e" command that was removed necessary anymore. Add back the archiving code.<commit_after>// ==UserScript==
// @name           Gmail Macros (New)
// @namespace      http://persistent.info
// @include        http://mail.google.com/*
// @include        https://mail.google.com/*
// ==/UserScript==

window.addEventListener('load', function() {
  if (unsafeWindow.gmonkey) {
    unsafeWindow.gmonkey.load('1.0', init)
  }
}, true);

var UNREAD_COUNT_RE = /\s+\(\d+\)?$/;

var MORE_ACTIONS_MENU_HEADER_CLASS = "QOD9Ec";
var MORE_ACTIONS_MENU_BODY_CLASS = "Sn99bd";
var MORE_ACTIONS_MENU_ITEM_CLASS = "SenFne";

var LABEL_ITEM_CLASS_NAME = "yyT6sf";

var MARK_AS_READ_ACTION = "1";
var ARCHIVE_ACTION = "7";
var ADD_LABEL_ACTION = "12";
var REMOVE_LABEL_ACTION = "13";

// Map from nav pane names to location names
var SPECIAL_LABELS = {
  "Inbox": "inbox",
  "Starred": "starred",
  "Chats": "chats",
  "Sent Mail": "sent",
  "Drafts": "drafts",
  "All Mail": "all",
  "Spam": "spam",
  "Trash": "trash"
}

const LABEL_ACTIONS = {
  // g: go to label
  71: {
    label: "Go to label",
    func: function(labelName) {
      if (labelName in SPECIAL_LABELS) {
        top.location.hash = "#" + SPECIAL_LABELS[labelName];
      } else {
        top.location.hash = "#label/" + encodeURIComponent(labelName);
      }
    }
  },
  // l: apply label
  76: {
    label: "Apply label",
    func: function (labelName) {
      clickMoreActionsMenuItem(labelName, ADD_LABEL_ACTION);
    },
  },
  // b: remove label
  66: {
    label: "Remove label",
    func: function (labelName) {
      clickMoreActionsMenuItem(labelName, REMOVE_LABEL_ACTION);
    }
  }
};

const ACTIONS = {
  // d: archive and mark as read, i.e. discard
  68: function() {
    clickMoreActionsMenuItem("Mark as read", MARK_AS_READ_ACTION);

    // Wait for the mark as read action to complete
    window.setTimeout(function() {
      var archiveButton = getFirstVisibleNode(
          evalXPath(".//button[@act='" + ARCHIVE_ACTION + "']", getDoc().body));

      if (archiveButton) {
        simulateClick(archiveButton, "click");
      } else {
        clickMoreActionsMenuItem("Archive", ARCHIVE_ACTION);
      }
    }, 500);
  },
  // f: focus (only show unread and inbox messages)
  70: function() {
    // Can only focus when in threadlist views
    if (gmail.getActiveViewType() != 'tl') return;

    var loc = top.location.hash;
    if (loc.length <= 1) return;
    loc = loc.substring(1);

    var search = getSearchForLocation(loc);

    if (search === null) {
      return;
    }

    search += " {in:inbox is:starred is:unread} -is:muted";

    top.location.hash = "#search/" + search;
  }
};

var LOC_TO_SEARCH = {
  "inbox": "in:inbox",
  "starred": "is:starred",
  "chats": "is:chat",
  "sent": "from:me",
  "drafts": "is:draft",
  "all": "",
  "spam": "in:spam",
  "trash": "in:trash"
};

var LABEL_PREFIX = "label/";

function getSearchForLocation(loc) {
  if (loc in LOC_TO_SEARCH) {
    return LOC_TO_SEARCH[loc];
  }

  if (loc.indexOf(LABEL_PREFIX) == 0) {
    var labelName = loc.substring(LABEL_PREFIX.length);

    // Normalize spaces to dashes, since that's what Gmail wants for searches
    labelName = labelName.replace(/\+/g, "-");

    return "label:" + labelName;
  }

  return null;
}

// TODO(mihaip): too many global variables, use objects
var banner = null;
var gmail = null;

var labelInput = null;
var activeLabelAction = null;
var lastPrefix = null;
var selLabelIndex = null;

function getDoc() {
  return gmail.getNavPaneElement().ownerDocument;
}

function newNode(tagName) {
  return getDoc().createElement(tagName);
}

function getNode(id) {
  return getDoc().getElementById(id);
}

function getFirstVisibleNode(nodes) {
  for (var i = 0, node; node = nodes[i]; i++) {
    if (node.offsetHeight) return node;
  }

  return null;
}

function simulateClick(node, eventType) {
  var event = node.ownerDocument.createEvent("MouseEvents");
  event.initMouseEvent(eventType,
                       true, // can bubble
                       true, // cancellable
                       node.ownerDocument.defaultView,
                       1, // clicks
                       50, 50, // screen coordinates
                       50, 50, // client coordinates
                       false, false, false, false, // control/alt/shift/meta
                       0, // button,
                       node);

  node.dispatchEvent(event);
}

function clickMoreActionsMenuItem(menuItemText, menuItemAction) {
  var moreActionsMenu = getFirstVisibleNode(getNodesByTagNameAndClass(
      getDoc().body, "div", MORE_ACTIONS_MENU_HEADER_CLASS));

  if (!moreActionsMenu) {
    alert("Couldn't find the menu header node");
    return;
  }

  simulateClick(moreActionsMenu, "mousedown");

  var menuBodyNodes = getNodesByTagNameAndClass(
      getDoc().body, "div", MORE_ACTIONS_MENU_BODY_CLASS);
  var menuBodyNode = getFirstVisibleNode(menuBodyNodes);

  if (!menuBodyNode) {
    alert("Couldn't find the menu body node");
    return;
  }

  var menuItemNodes = getNodesByTagNameAndClass(
      menuBodyNode, "div", MORE_ACTIONS_MENU_ITEM_CLASS);

  for (var i = 0; menuItemNode = menuItemNodes[i]; i++) {
    if (menuItemNode.textContent == menuItemText &&
        menuItemNode.getAttribute("act") == menuItemAction) {
      simulateClick(menuItemNode, "mouseup");
      return;
    }
  }

  alert("Couldn't find the menu item node '" + menuItemText + "'");
}

function init(g) {
  gmail = g;
  banner = new Banner();

  getDoc().defaultView.addEventListener('keydown', keyHandler, false);
}

function keyHandler(event) {
  // Apparently we still see Firefox shortcuts like control-T for a new tab -
  // checking for modifiers lets us ignore those
  if (event.altKey || event.ctrlKey || event.metaKey) return;

  // We also don't want to interfere with regular user typing
  if (event.target && event.target.nodeName) {
    var targetNodeName = event.target.nodeName.toLowerCase();
    if (targetNodeName == "textarea" ||
        (targetNodeName == "input" && event.target.type &&
         (event.target.type.toLowerCase() == "text" ||
          event.target.type.toLowerCase() == "file"))) {
      return;
    }
  }

  var k = event.keyCode;

  if (k in LABEL_ACTIONS) {
    if (activeLabelAction) {
      endLabelAction();
      return
    } else {
      activeLabelAction = LABEL_ACTIONS[k];
      beginLabelAction();
      return;
    }
  }

  if (k in ACTIONS) {
    ACTIONS[k]();
    return;
  }

  return;
}

function beginLabelAction() {
  // TODO(mihaip): make sure the labels nav pane is open

  banner.show();
  banner.setFooter(activeLabelAction.label);

  lastPrefix = null;
  selLabelIndex = 0;
  dispatchedActionTimeout = null;

  labelInput = makeLabelInput();
  labelInput.addEventListener("keyup", updateLabelAction, false);
  // we want escape, clicks, etc. to cancel, which seems to be equivalent to the
  // field losing focus
  labelInput.addEventListener("blur", endLabelAction, false);
}

function makeLabelInput() {
  labelInput = newNode("input");
  labelInput.type = "text";
  labelInput.setAttribute("autocomplete", "off");
  with (labelInput.style) {
    position = "fixed"; // We need to use fixed positioning since we have to ensure
                        // that the input is not scrolled out of view (since
                        // Gecko will scroll for us if it is).
    top = "0";
    left = "-300px";
    width = "200px";
    height = "20px";
    zIndex = "1000";
  }

  getDoc().body.appendChild(labelInput);
  labelInput.focus();
  labelInput.value = "";

  return labelInput;
}

function endLabelAction() {
  if (dispatchedActionTimeout) return;

  // TODO(mihaip): re-close label box if necessary

  banner.hide();

  if (labelInput) {
    labelInput.parentNode.removeChild(labelInput);
    labelInput = null;
  }

  activeLabelAction = null;
}

function updateLabelAction(event) {
  // We've already dispatched the action, the user is just typing away
  if (dispatchedActionTimeout) return;

  var labels = getLabels();
  var selectedLabels = [];

  // We need to skip the label shortcut that got us here
  var labelPrefix = labelInput.value.substring(1).toLowerCase();

  // We always want to reset the cursor position to the end of the text
  // field, since some of the keys that we support (arrows) would
  // otherwise change it
  labelInput.selectionStart = labelInput.selectionEnd = labelPrefix.length + 1;

  if (labelPrefix.length == 0) {
    banner.update("");
    return;
  }

  for (var i = 0; i < labels.length; i++) {
    label = labels[i];

    if (label.toLowerCase().indexOf(labelPrefix) == 0) {
      selectedLabels.push(label);
    }
  }

  if (labelPrefix != lastPrefix) {
    lastPrefix = labelPrefix;
    selLabelIndex = 0;
  }

  if (selectedLabels.length == 0) {
    banner.update(labelPrefix);
    return;
  }

  if (event.keyCode == 13 || selectedLabels.length == 1) {
    var selectedLabelName = selectedLabels[selLabelIndex];

    // Tell the user what we picked
    banner.update(selectedLabelName);

    // Invoke the action straight away, but keep the banner up so the user can
    // see what was picked, and so that extra typing is caught.
    activeLabelAction.func(selectedLabelName);
    dispatchedActionTimeout = window.setTimeout(function() {
      dispatchedActionTimeout = null;
      endLabelAction()
    }, 500);
    return;
  } else if (event.keyCode == 40) { // down
    selLabelIndex = (selLabelIndex + 1) % selectedLabels.length;
  } else if (event.keyCode == 38) { // up
    selLabelIndex = (selLabelIndex + selectedLabels.length - 1) %
        selectedLabels.length;
  }

  var selectedLabelName = selectedLabels[selLabelIndex];

  var highlightedSelectedLabelName = selectedLabelName.replace(
      new RegExp("(" + labelPrefix + ")", "i"), "$1");
  var labelPosition = " (" +
      (selLabelIndex + 1) + "/" + selectedLabels.length + ")";

  banner.update(highlightedSelectedLabelName + labelPosition);
}

function getLabels() {
  var navPaneNode = gmail.getNavPaneElement();

  var labelNodes = getNodesByTagNameAndClass(
      navPaneNode, "div", LABEL_ITEM_CLASS_NAME);

  var labels = [];

  for (var i = 0, labelNode; labelNode = labelNodes[i]; i++) {
    var labelName = labelNode.textContent.replace(UNREAD_COUNT_RE, "");

    labels.push(labelName);
  }

  return labels;
}

function evalXPath(expression, rootNode) {
  try {
    var xpathIterator = rootNode.ownerDocument.evaluate(
      expression,
      rootNode,
      null, // no namespace resolver
      XPathResult.ORDERED_NODE_ITERATOR_TYPE,
      null); // no existing results
  } catch (err) {
    GM_log("Error when evaluating XPath expression '" + expression + "'" +
           ": " + err);
    return null;
  }
  var results = [];

  // Convert result to JS array
  for (var xpathNode = xpathIterator.iterateNext();
       xpathNode;
       xpathNode = xpathIterator.iterateNext()) {
    results.push(xpathNode);
  }

  return results;
}

function getNodesByTagNameAndClass(rootNode, tagName, className) {
  var expression =
      ".//" + tagName +
      "[contains(concat(' ', @class, ' '), ' " + className + " ')]";

  return evalXPath(expression, rootNode);
}

function Banner() {
  function getNodeSet() {
    var boxNode = newNode("div");
    boxNode.className = "banner";
    with (boxNode.style) {
      display = "none";
      position = "fixed";
      left = "10%";
      margin = "0 10% 0 10%";
      width = "60%";
      textAlign = "center";
      MozBorderRadius = "10px";
      padding = "10px";
      color = "#fff";
    }

    var messageNode = newNode("div");
    with (messageNode.style) {
      fontSize = "24px";
      fontWeight = "bold";
      fontFamily = "Lucida Grande, Trebuchet MS, sans-serif";
      margin = "0 0 10px 0";
    }
    boxNode.appendChild(messageNode);

    var taglineNode = newNode("div");
    with (taglineNode.style) {
      fontSize = "13px";
      margin = "0";
      position = "absolute";
      right = "0.2em";
      bottom = "0";
      MozOpacity = "0.5";
    }
    taglineNode.innerHTML = 'LabelSelector9001';
    boxNode.appendChild(taglineNode);

    var footerNode = newNode("div");
    with (footerNode.style) {
      fontSize = "13px";
    }
    boxNode.appendChild(footerNode);

    return boxNode;
  }

  this.backgroundNode = getNodeSet();
  this.backgroundNode.style.background = "#000";
  this.backgroundNode.style.MozOpacity = "0.70";
  this.backgroundNode.style.zIndex = 100;
  for (var child = this.backgroundNode.firstChild;
       child;
       child = child.nextSibling) {
    child.style.visibility = "hidden";
  }

  this.foregroundNode = getNodeSet();
  this.foregroundNode.style.zIndex = 101;
}

Banner.prototype.hide = function() {
  this.backgroundNode.style.display =
    this.foregroundNode.style.display = "none";
}

Banner.prototype.show = function(opt_isBottomAnchored) {
  this.update("");
  getDoc().body.appendChild(this.backgroundNode);
  getDoc().body.appendChild(this.foregroundNode);

  this.backgroundNode.style.bottom = this.foregroundNode.style.bottom =
    opt_isBottomAnchored ? "10%" : "";
  this.backgroundNode.style.top = this.foregroundNode.style.top =
    opt_isBottomAnchored ? "" : "50%";

  this.backgroundNode.style.display =
    this.foregroundNode.style.display = "block";
}

Banner.prototype.update = function(message) {
  if (message.length) {
    this.backgroundNode.firstChild.style.display =
      this.foregroundNode.firstChild.style.display = "inline";
  } else {
    this.backgroundNode.firstChild.style.display =
      this.foregroundNode.firstChild.style.display = "none";
  }
  this.backgroundNode.firstChild.innerHTML =
    this.foregroundNode.firstChild.innerHTML = message;
}

Banner.prototype.setFooter = function(text) {
  this.backgroundNode.lastChild.innerHTML =
    this.foregroundNode.lastChild.innerHTML = text;
}
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

goog.provide('shaka.ui.Overlay');

goog.require('goog.asserts');
goog.require('shaka.polyfill.installAll');
goog.require('shaka.ui.Controls');
goog.require('shaka.ui.TextDisplayer');
goog.require('shaka.util.Platform');

/**
 * @param {!shaka.Player} player
 * @param {!HTMLElement} videoContainer
 * @param {!HTMLMediaElement} video
 * @implements {shaka.util.IDestroyable}
 * @constructor
 * @export
 */
shaka.ui.Overlay = function(player, videoContainer, video) {
  /** @private {shaka.Player} */
  this.player_ = player;

  /** @private {!HTMLElement} */
  this.videoContainer_ = videoContainer;

  /** @private {!HTMLMediaElement} */
  this.video_ = video;

  /** @private {!shaka.extern.UIConfiguration} */
  this.config_ = this.defaultConfig_();

  // Make sure this container is discoverable and that the UI can be reached
  // through it.
  videoContainer['dataset']['shakaPlayerContainer'] = '';
  videoContainer['ui'] = this;

  // Tag the container for mobile platforms, to allow different styles.
  if (this.isMobile()) {
    videoContainer.classList.add('shaka-mobile');
  }
};

/**
 * @override
 * @export
 */
shaka.ui.Overlay.prototype.destroy = async function() {
  await this.controls_.destroy();
  this.controls_ = null;

  await this.player_.destroy();
  this.player_ = null;
};

/**
 * Detects if this is a mobile platform, in case you want to choose a different
 * UI configuration on mobile devices.
 *
 * @return {boolean}
 * @export
 */
shaka.ui.Overlay.prototype.isMobile = function() {
  return shaka.util.Platform.isMobile();
};

/**
 * @return {!shaka.extern.UIConfiguration}
 * @export
 */
shaka.ui.Overlay.prototype.getConfiguration = function() {
  const ret = this.defaultConfig_();
  shaka.util.ConfigUtils.mergeConfigObjects(
      ret, this.config_, this.defaultConfig_(),
      /* overrides (only used for player config)*/ {}, /* path */ '');
  return ret;
};

/**
 * @param {string|!Object} config This should either be a field name or an
 *   object following the form of {@link shaka.extern.UIConfiguration}, where
 *   you may omit any field you do not wish to change.
 * @param {*=} value This should be provided if the previous parameter
 *   was a string field name.
 * @export
 */
shaka.ui.Overlay.prototype.configure = function(config, value) {
  goog.asserts.assert(typeof(config) == 'object' || arguments.length == 2,
                      'String configs should have values!');

  // ('fieldName', value) format
  if (arguments.length == 2 && typeof(config) == 'string') {
    config = shaka.util.ConfigUtils.convertToConfigObject(config, value);
  }

  goog.asserts.assert(typeof(config) == 'object', 'Should be an object!');

  const DomUtils = shaka.util.Dom;
  // Deconstruct the old layout.

  // Save the text container, so subtitles can be displayed with
  // the new layout.
  const textContainer =
    this.videoContainer_.querySelector('.shaka-text-container');

  // Remember whether the controls were shown
  let shown = false;
  let controlsContainer =
      this.videoContainer_.querySelector('.shaka-controls-container');
  if (controlsContainer != null) {
    shown = controlsContainer.getAttribute('shown');
  }

  // Destroy the old layout.
  shaka.util.Dom.removeAllChildren(this.videoContainer_);

  // Add the video back in
  this.videoContainer_.appendChild(this.video_);

  shaka.util.ConfigUtils.mergeConfigObjects(
        this.config_, config, this.defaultConfig_(),
        /* overrides (only used for player config)*/ {}, /* path */ '');

  // If a cast receiver app id has been given, add a cast button to the UI
  if (this.config_.castReceiverAppId &&
      !this.config_.overflowMenuButtons.includes('cast')) {
    this.config_.overflowMenuButtons.push('cast');
  }

  goog.asserts.assert(this.player_ != null, 'Should have a player!');

  /** @private {shaka.ui.Controls} */
  this.controls_ = new shaka.ui.Controls(
      this.player_, this.videoContainer_, this.video_, this.config_);

  controlsContainer = DomUtils.getElementByClassName(
      'shaka-controls-container', this.videoContainer_);
  controlsContainer.setAttribute('shown', shown);

  // Add the text container back.
  if (textContainer) {
    this.videoContainer_.appendChild(textContainer);
  }

  this.controls_.dispatchEvent(new shaka.util.FakeEvent('uiupdated'));
};

/**
 * @return {shaka.Player}
 * @export
 */
shaka.ui.Overlay.prototype.getPlayer = function() {
  return this.player_;
};

/**
 * @return {shaka.ui.Controls}
 * @export
 */
shaka.ui.Overlay.prototype.getControls = function() {
  return this.controls_;
};

/**
 * Enable or disable the custom controls.
 *
 * @param {boolean} enabled
 * @export
 */
shaka.ui.Overlay.prototype.setEnabled = function(enabled) {
  this.controls_.setEnabledShakaControls(enabled);
};

/**
 * @return {!shaka.extern.UIConfiguration}
 * @private
 */
shaka.ui.Overlay.prototype.defaultConfig_ = function() {
  return {
    controlPanelElements: [
      'time_and_duration',
      'spacer',
      'mute',
      'volume',
      'fullscreen',
      'overflow_menu',
    ],
    overflowMenuButtons: [
      'captions',
      'quality',
      'language',
      'picture_in_picture',
      'cast',
    ],
    addSeekBar: true,
    castReceiverAppId: '',
  };
};

/**
 * @private
 */
shaka.ui.Overlay.scanPageForShakaElements_ = function() {
  // Install built-in polyfills to patch browser incompatibilities.
  shaka.polyfill.installAll();
  // Check to see if the browser supports the basic APIs Shaka needs.
  if (!shaka.Player.isBrowserSupported()) {
    shaka.log.error('Shaka Player does not support this browser. ' +
        'Please see https://tinyurl.com/y7s4j9tr for the list of ' +
        'supported browsers.');

    // After scanning the page for elements, fire a special "loaded" event for
    // when the load fails. This will allow the page to react to the failure.
    shaka.ui.Overlay.dispatchLoadedEvent_('shaka-ui-load-failed');
    return;
  }

  // Look for elements marked 'data-shaka-player-container'
  // on the page. These will be used to create our default
  // UI.
  const containers = document.querySelectorAll(
      '[data-shaka-player-container]');

  // Look for elements marked 'data-shaka-player'. They will
  // either be used in our default UI or with native browser
  // controls.
  const videos = document.querySelectorAll(
      '[data-shaka-player]');

  if (!videos.length && !containers.length) {
    // No elements have been tagged with shaka attributes.
  } else if (videos.length && !containers.length) {
    // Just the video elements were provided.
    for (let i = 0; i < videos.length; i++) {
      const video = videos[i];
      goog.asserts.assert(video.tagName.toLowerCase() == 'video',
        'Should be a video element!');

      const container = document.createElement('div');
      const videoParent = video.parentElement;
      videoParent.replaceChild(container, video);
      container.appendChild(video);

      let castAppId = '';

      // If cast receiver application id was provided, pass it to the
      // UI constructor.
      if (video['dataset'] && video['dataset']['shakaPlayerCastReceiverId']) {
        castAppId = video['dataset']['shakaPlayerCastReceiverId'];
      }

      const ui = shaka.ui.Overlay.createUI_(
          shaka.util.Dom.asHTMLElement(container),
          shaka.util.Dom.asHTMLMediaElement(video));

      ui.configure({castReceiverAppId: castAppId});

      if (shaka.util.Dom.asHTMLMediaElement(video).controls) {
        ui.getControls().setEnabledNativeControls(true);
      }
    }
  } else {
    for (let i = 0; i < containers.length; i++) {
      const container = containers[i];
      goog.asserts.assert(container.tagName.toLowerCase() == 'div',
        'Container should be a div!');

      let castAppId = '';

      // Cast receiver id can be specified on either container or video.
      // It should not be provided on both. If it was, we will use the last
      // one we saw.
      if (container['dataset'] &&
          container['dataset']['shakaPlayerCastReceiverId']) {
        castAppId = container['dataset']['shakaPlayerCastReceiverId'];
      }

      let video = null;
      for (let j = 0; j < videos.length; j++) {
        goog.asserts.assert(videos[j].tagName.toLowerCase() == 'video',
          'Should be a video element!');
        if (videos[j].parentElement == container) {
          video = videos[j];
          break;
        }
      }

      if (!video) {
        video = document.createElement('video');
        video.setAttribute('playsinline', '');
        container.appendChild(video);
      }

      if (video['dataset'] && video['dataset']['shakaPlayerCastReceiverId']) {
        castAppId = video['dataset']['shakaPlayerCastReceiverId'];
      }
      const ui = shaka.ui.Overlay.createUI_(
          shaka.util.Dom.asHTMLElement(container),
          shaka.util.Dom.asHTMLMediaElement(video));

      ui.configure({castReceiverAppId: castAppId});
    }
  }

  // After scanning the page for elements, fire the "loaded" event.  This will
  // let apps know they can use the UI library programmatically now, even if
  // they didn't have any Shaka-related elements declared in their HTML.
  shaka.ui.Overlay.dispatchLoadedEvent_('shaka-ui-loaded');
};

/**
 * @param {string} eventName
 * @private
 */
shaka.ui.Overlay.dispatchLoadedEvent_ = function(eventName) {
  // "Event" is not constructable on IE, so we use this CustomEvent pattern.
  const uiLoadedEvent = /** @type {!CustomEvent} */(
      document.createEvent('CustomEvent'));
  uiLoadedEvent.initCustomEvent(eventName, false, false, null);

  document.dispatchEvent(uiLoadedEvent);
};

/**
 * @param {!HTMLElement} container
 * @param {!HTMLMediaElement} video
 * @return {!shaka.ui.Overlay}
 * @private
 */
shaka.ui.Overlay.createUI_ = function(container, video) {
  const player = new shaka.Player(video);
  const ui = new shaka.ui.Overlay(player, container, video);

  // If the browser's native controls are disabled, use UI TextDisplayer. Right
  // now because the factory must be a constructor and () => {} can't be a
  // constructor.
  if (!video.controls) {
    player.configure(
        'textDisplayFactory',
        () => { return new shaka.ui.TextDisplayer(video, container); });
  }

  container['ui'] = ui;
  video['ui'] = ui;
  return ui;
};

if (document.readyState == 'complete') {
  // Don't fire this event synchronously.  In a compiled bundle, the "shaka"
  // namespace might not be exported to the window until after this point.
  Promise.resolve().then(shaka.ui.Overlay.scanPageForShakaElements_);
} else {
  window.addEventListener('load', shaka.ui.Overlay.scanPageForShakaElements_);
}
<commit_msg>Fix API-based UI setup with default config<commit_after>/**
 * @license
 * Copyright 2016 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

goog.provide('shaka.ui.Overlay');

goog.require('goog.asserts');
goog.require('shaka.polyfill.installAll');
goog.require('shaka.ui.Controls');
goog.require('shaka.ui.TextDisplayer');
goog.require('shaka.util.Platform');

/**
 * @param {!shaka.Player} player
 * @param {!HTMLElement} videoContainer
 * @param {!HTMLMediaElement} video
 * @implements {shaka.util.IDestroyable}
 * @constructor
 * @export
 */
shaka.ui.Overlay = function(player, videoContainer, video) {
  /** @private {shaka.Player} */
  this.player_ = player;

  /** @private {!HTMLElement} */
  this.videoContainer_ = videoContainer;

  /** @private {!HTMLMediaElement} */
  this.video_ = video;

  /** @private {!shaka.extern.UIConfiguration} */
  this.config_ = this.defaultConfig_();

  // Make sure this container is discoverable and that the UI can be reached
  // through it.
  videoContainer['dataset']['shakaPlayerContainer'] = '';
  videoContainer['ui'] = this;

  // Tag the container for mobile platforms, to allow different styles.
  if (this.isMobile()) {
    videoContainer.classList.add('shaka-mobile');
  }

  // Run the initial setup so that no configure() call is required for default
  // settings.
  this.configure({});
};

/**
 * @override
 * @export
 */
shaka.ui.Overlay.prototype.destroy = async function() {
  await this.controls_.destroy();
  this.controls_ = null;

  await this.player_.destroy();
  this.player_ = null;
};

/**
 * Detects if this is a mobile platform, in case you want to choose a different
 * UI configuration on mobile devices.
 *
 * @return {boolean}
 * @export
 */
shaka.ui.Overlay.prototype.isMobile = function() {
  return shaka.util.Platform.isMobile();
};

/**
 * @return {!shaka.extern.UIConfiguration}
 * @export
 */
shaka.ui.Overlay.prototype.getConfiguration = function() {
  const ret = this.defaultConfig_();
  shaka.util.ConfigUtils.mergeConfigObjects(
      ret, this.config_, this.defaultConfig_(),
      /* overrides (only used for player config)*/ {}, /* path */ '');
  return ret;
};

/**
 * @param {string|!Object} config This should either be a field name or an
 *   object following the form of {@link shaka.extern.UIConfiguration}, where
 *   you may omit any field you do not wish to change.
 * @param {*=} value This should be provided if the previous parameter
 *   was a string field name.
 * @export
 */
shaka.ui.Overlay.prototype.configure = function(config, value) {
  goog.asserts.assert(typeof(config) == 'object' || arguments.length == 2,
                      'String configs should have values!');

  // ('fieldName', value) format
  if (arguments.length == 2 && typeof(config) == 'string') {
    config = shaka.util.ConfigUtils.convertToConfigObject(config, value);
  }

  goog.asserts.assert(typeof(config) == 'object', 'Should be an object!');

  const DomUtils = shaka.util.Dom;
  // Deconstruct the old layout.

  // Save the text container, so subtitles can be displayed with
  // the new layout.
  const textContainer =
    this.videoContainer_.querySelector('.shaka-text-container');

  // Remember whether the controls were shown
  let shown = false;
  let controlsContainer =
      this.videoContainer_.querySelector('.shaka-controls-container');
  if (controlsContainer != null) {
    shown = controlsContainer.getAttribute('shown');
  }

  // Destroy the old layout.
  shaka.util.Dom.removeAllChildren(this.videoContainer_);

  // Add the video back in
  this.videoContainer_.appendChild(this.video_);

  shaka.util.ConfigUtils.mergeConfigObjects(
        this.config_, config, this.defaultConfig_(),
        /* overrides (only used for player config)*/ {}, /* path */ '');

  // If a cast receiver app id has been given, add a cast button to the UI
  if (this.config_.castReceiverAppId &&
      !this.config_.overflowMenuButtons.includes('cast')) {
    this.config_.overflowMenuButtons.push('cast');
  }

  goog.asserts.assert(this.player_ != null, 'Should have a player!');

  /** @private {shaka.ui.Controls} */
  this.controls_ = new shaka.ui.Controls(
      this.player_, this.videoContainer_, this.video_, this.config_);

  controlsContainer = DomUtils.getElementByClassName(
      'shaka-controls-container', this.videoContainer_);
  controlsContainer.setAttribute('shown', shown);

  // Add the text container back.
  if (textContainer) {
    this.videoContainer_.appendChild(textContainer);
  }

  this.controls_.dispatchEvent(new shaka.util.FakeEvent('uiupdated'));
};

/**
 * @return {shaka.Player}
 * @export
 */
shaka.ui.Overlay.prototype.getPlayer = function() {
  return this.player_;
};

/**
 * @return {shaka.ui.Controls}
 * @export
 */
shaka.ui.Overlay.prototype.getControls = function() {
  return this.controls_;
};

/**
 * Enable or disable the custom controls.
 *
 * @param {boolean} enabled
 * @export
 */
shaka.ui.Overlay.prototype.setEnabled = function(enabled) {
  this.controls_.setEnabledShakaControls(enabled);
};

/**
 * @return {!shaka.extern.UIConfiguration}
 * @private
 */
shaka.ui.Overlay.prototype.defaultConfig_ = function() {
  return {
    controlPanelElements: [
      'time_and_duration',
      'spacer',
      'mute',
      'volume',
      'fullscreen',
      'overflow_menu',
    ],
    overflowMenuButtons: [
      'captions',
      'quality',
      'language',
      'picture_in_picture',
      'cast',
    ],
    addSeekBar: true,
    castReceiverAppId: '',
  };
};

/**
 * @private
 */
shaka.ui.Overlay.scanPageForShakaElements_ = function() {
  // Install built-in polyfills to patch browser incompatibilities.
  shaka.polyfill.installAll();
  // Check to see if the browser supports the basic APIs Shaka needs.
  if (!shaka.Player.isBrowserSupported()) {
    shaka.log.error('Shaka Player does not support this browser. ' +
        'Please see https://tinyurl.com/y7s4j9tr for the list of ' +
        'supported browsers.');

    // After scanning the page for elements, fire a special "loaded" event for
    // when the load fails. This will allow the page to react to the failure.
    shaka.ui.Overlay.dispatchLoadedEvent_('shaka-ui-load-failed');
    return;
  }

  // Look for elements marked 'data-shaka-player-container'
  // on the page. These will be used to create our default
  // UI.
  const containers = document.querySelectorAll(
      '[data-shaka-player-container]');

  // Look for elements marked 'data-shaka-player'. They will
  // either be used in our default UI or with native browser
  // controls.
  const videos = document.querySelectorAll(
      '[data-shaka-player]');

  if (!videos.length && !containers.length) {
    // No elements have been tagged with shaka attributes.
  } else if (videos.length && !containers.length) {
    // Just the video elements were provided.
    for (let i = 0; i < videos.length; i++) {
      const video = videos[i];
      goog.asserts.assert(video.tagName.toLowerCase() == 'video',
        'Should be a video element!');

      const container = document.createElement('div');
      const videoParent = video.parentElement;
      videoParent.replaceChild(container, video);
      container.appendChild(video);

      let castAppId = '';

      // If cast receiver application id was provided, pass it to the
      // UI constructor.
      if (video['dataset'] && video['dataset']['shakaPlayerCastReceiverId']) {
        castAppId = video['dataset']['shakaPlayerCastReceiverId'];
      }

      const ui = shaka.ui.Overlay.createUI_(
          shaka.util.Dom.asHTMLElement(container),
          shaka.util.Dom.asHTMLMediaElement(video));

      ui.configure({castReceiverAppId: castAppId});

      if (shaka.util.Dom.asHTMLMediaElement(video).controls) {
        ui.getControls().setEnabledNativeControls(true);
      }
    }
  } else {
    for (let i = 0; i < containers.length; i++) {
      const container = containers[i];
      goog.asserts.assert(container.tagName.toLowerCase() == 'div',
        'Container should be a div!');

      let castAppId = '';

      // Cast receiver id can be specified on either container or video.
      // It should not be provided on both. If it was, we will use the last
      // one we saw.
      if (container['dataset'] &&
          container['dataset']['shakaPlayerCastReceiverId']) {
        castAppId = container['dataset']['shakaPlayerCastReceiverId'];
      }

      let video = null;
      for (let j = 0; j < videos.length; j++) {
        goog.asserts.assert(videos[j].tagName.toLowerCase() == 'video',
          'Should be a video element!');
        if (videos[j].parentElement == container) {
          video = videos[j];
          break;
        }
      }

      if (!video) {
        video = document.createElement('video');
        video.setAttribute('playsinline', '');
        container.appendChild(video);
      }

      if (video['dataset'] && video['dataset']['shakaPlayerCastReceiverId']) {
        castAppId = video['dataset']['shakaPlayerCastReceiverId'];
      }
      const ui = shaka.ui.Overlay.createUI_(
          shaka.util.Dom.asHTMLElement(container),
          shaka.util.Dom.asHTMLMediaElement(video));

      ui.configure({castReceiverAppId: castAppId});
    }
  }

  // After scanning the page for elements, fire the "loaded" event.  This will
  // let apps know they can use the UI library programmatically now, even if
  // they didn't have any Shaka-related elements declared in their HTML.
  shaka.ui.Overlay.dispatchLoadedEvent_('shaka-ui-loaded');
};

/**
 * @param {string} eventName
 * @private
 */
shaka.ui.Overlay.dispatchLoadedEvent_ = function(eventName) {
  // "Event" is not constructable on IE, so we use this CustomEvent pattern.
  const uiLoadedEvent = /** @type {!CustomEvent} */(
      document.createEvent('CustomEvent'));
  uiLoadedEvent.initCustomEvent(eventName, false, false, null);

  document.dispatchEvent(uiLoadedEvent);
};

/**
 * @param {!HTMLElement} container
 * @param {!HTMLMediaElement} video
 * @return {!shaka.ui.Overlay}
 * @private
 */
shaka.ui.Overlay.createUI_ = function(container, video) {
  const player = new shaka.Player(video);
  const ui = new shaka.ui.Overlay(player, container, video);

  // If the browser's native controls are disabled, use UI TextDisplayer. Right
  // now because the factory must be a constructor and () => {} can't be a
  // constructor.
  if (!video.controls) {
    player.configure(
        'textDisplayFactory',
        () => { return new shaka.ui.TextDisplayer(video, container); });
  }

  container['ui'] = ui;
  video['ui'] = ui;
  return ui;
};

if (document.readyState == 'complete') {
  // Don't fire this event synchronously.  In a compiled bundle, the "shaka"
  // namespace might not be exported to the window until after this point.
  Promise.resolve().then(shaka.ui.Overlay.scanPageForShakaElements_);
} else {
  window.addEventListener('load', shaka.ui.Overlay.scanPageForShakaElements_);
}
<|endoftext|>


<commit_before>'use strict';

angular.module('mean.mean-date-filter').directive('meanDateFilter', ['MeanDateFilter',

  function(MeanDateFilter) {
    return {
      restrict: 'A',
      transclude: 'true',
      scope: {
        dates: '=',
        mode: '@',
        clearText: '@',
        currentText: '@',
        closeText: '@',
        weekText: '@',
        monthText: '@',
        yearText: '@',
        startDateText: '@',
        endDateText: '@',
        format: '@',
        momentjsFormat: '@'
      },
      templateUrl: 'mean-date-filter/directives/templates/dateFilter.html',
      link: function($scope, element, attrs) {
        $scope.opened = {
          start: false,
          end: false,
        };
        $scope.toggle = function(type, event) {
          event.preventDefault();
          event.stopPropagation();
          $scope.opened[type] = !$scope.opened[type];
        };

        $scope.week = function() {
          changeMode('week', $scope.save);
        };
        $scope.month = function() {
          changeMode('month', $scope.save);
        };
        $scope.year = function() {
          changeMode('year', $scope.save);
        };

        var changeMode = function(mode, callback) {
          if (mode) {
            $scope.mode = mode;
            if (mode === 'year') {
              $scope.dates.startDate = moment(new Date()).subtract(1, 'year').format($scope.momentjsFormat);
              $scope.dates.endDate = moment(new Date()).subtract(1, 'days').format($scope.momentjsFormat);
            } else if (mode === 'month') {
              $scope.dates.startDate = moment(new Date()).subtract(1, 'month').format($scope.momentjsFormat);
              $scope.dates.endDate = moment(new Date()).subtract(1, 'days').format($scope.momentjsFormat);
            } else if (mode === 'week') {
              $scope.dates.startDate = moment(new Date()).subtract(7, 'days').format($scope.momentjsFormat);
              $scope.dates.endDate = moment(new Date()).subtract(1, 'days').format($scope.momentjsFormat);
            }
            if (typeof callback === 'function') {
              callback();
            }
          }
        };

        $scope.resetMode = function() {
          $scope.mode = null;
        };

        $scope.save = function() {
          MeanDateFilter.setDateFilter($scope.dates.startDate, $scope.dates.endDate, $scope.mode, function(data) {});
        };

        var load = function() {
          MeanDateFilter.getDateFilter(function(data) {
            if (typeof data.startDate !== 'undefined') {
              $scope.dates.startDate = moment(data.startDate).format($scope.momentjsFormat);
            }
            if (typeof data.endDate !== 'undefined') {
              $scope.dates.endDate = moment(data.endDate).format($scope.momentjsFormat);
            }
            if (typeof data.mode !== 'undefined') {
              $scope.mode = data.mode;
            }
          });
        };
        load();

        if (!$scope.startDateText) {
          $scope.startDateText = 'Start Date';
        }
        if (!$scope.endDateText) {
          $scope.endDateText = 'End Date';
        }
        if (!$scope.weekText) {
          $scope.weekText = 'Week';
        }
        if (!$scope.monthText) {
          $scope.monthText = 'Month';
        }
        if (!$scope.yearText) {
          $scope.yearText = 'Year';
        }
      }
    };
  }
]);
<commit_msg>Fix dates to be without hours, minutes, seconds and milliseconds<commit_after>'use strict';

angular.module('mean.mean-date-filter').directive('meanDateFilter', ['MeanDateFilter',

  function(MeanDateFilter) {
    return {
      restrict: 'A',
      transclude: 'true',
      scope: {
        dates: '=',
        mode: '@',
        clearText: '@',
        currentText: '@',
        closeText: '@',
        weekText: '@',
        monthText: '@',
        yearText: '@',
        startDateText: '@',
        endDateText: '@',
        format: '@',
        momentjsFormat: '@'
      },
      templateUrl: 'mean-date-filter/directives/templates/dateFilter.html',
      link: function($scope, element, attrs) {
        $scope.opened = {
          start: false,
          end: false,
        };
        $scope.toggle = function(type, event) {
          event.preventDefault();
          event.stopPropagation();
          $scope.opened[type] = !$scope.opened[type];
        };

        $scope.week = function() {
          changeMode('week', $scope.save);
        };
        $scope.month = function() {
          changeMode('month', $scope.save);
        };
        $scope.year = function() {
          changeMode('year', $scope.save);
        };

        var changeMode = function(mode, callback) {
          if (mode) {
            $scope.mode = mode;
            if (mode === 'year') {
              $scope.dates.startDate = moment().hours(0).minutes(0).seconds(0).milliseconds(0).subtract(1, 'year').format($scope.momentjsFormat);
              $scope.dates.endDate = moment().hours(0).minutes(0).seconds(0).milliseconds(0).subtract(1, 'days').format($scope.momentjsFormat);
            } else if (mode === 'month') {
              $scope.dates.startDate = moment().hours(0).minutes(0).seconds(0).milliseconds(0).subtract(1, 'month').format($scope.momentjsFormat);
              $scope.dates.endDate = moment().hours(0).minutes(0).seconds(0).milliseconds(0).subtract(1, 'days').format($scope.momentjsFormat);
            } else if (mode === 'week') {
              $scope.dates.startDate = moment().hours(0).minutes(0).seconds(0).milliseconds(0).subtract(7, 'days').format($scope.momentjsFormat);
              $scope.dates.endDate = moment().hours(0).minutes(0).seconds(0).milliseconds(0).subtract(1, 'days').format($scope.momentjsFormat);
            }
            if (typeof callback === 'function') {
              callback();
            }
          }
        };

        $scope.resetMode = function() {
          $scope.mode = null;
        };

        $scope.save = function() {
          MeanDateFilter.setDateFilter($scope.dates.startDate, $scope.dates.endDate, $scope.mode, function(data) {});
        };

        var load = function() {
          MeanDateFilter.getDateFilter(function(data) {
            if (typeof data.startDate !== 'undefined') {
              $scope.dates.startDate = moment(data.startDate).hours(0).minutes(0).seconds(0).milliseconds(0).format($scope.momentjsFormat);
            }
            if (typeof data.endDate !== 'undefined') {
              $scope.dates.endDate = moment(data.endDate).hours(0).minutes(0).seconds(0).milliseconds(0).format($scope.momentjsFormat);
            }
            if (typeof data.mode !== 'undefined') {
              $scope.mode = data.mode;
            }
          });
        };
        load();

        if (!$scope.startDateText) {
          $scope.startDateText = 'Start Date';
        }
        if (!$scope.endDateText) {
          $scope.endDateText = 'End Date';
        }
        if (!$scope.weekText) {
          $scope.weekText = 'Week';
        }
        if (!$scope.monthText) {
          $scope.monthText = 'Month';
        }
        if (!$scope.yearText) {
          $scope.yearText = 'Year';
        }
      }
    };
  }
]);
<|endoftext|>


<commit_before>const Statement = require('../entities/Statement.js');
const error = require('../error.js');

class ReturnStatement extends Statement {
  constructor(returnValue) {
    super();
    this.returnValue = returnValue;
  }
  analyze(context) {
    if (context.inFunction) {
      error('Return statement not in function');
    }
    // this.body.analyze();
  }
  toString() {
<<<<<<< HEAD
    return (`(ReturnStatement return ${this.body})`);
=======
    return (`return ${this.returnValue}`);
>>>>>>> master
  }
}

module.exports = ReturnStatement;
<commit_msg>Remove broken merge commit header<commit_after>const Statement = require('../entities/Statement.js');
const error = require('../error.js');

class ReturnStatement extends Statement {
  constructor(returnValue) {
    super();
    this.returnValue = returnValue;
  }
  analyze(context) {
    if (context.inFunction) {
      error('Return statement not in function');
    }
    // this.body.analyze();
  }
  toString() {
    return (`(ReturnStatement return ${this.body})`);
  }
}

module.exports = ReturnStatement;
<|endoftext|>


<commit_before>(function($, window, document, undefined){

      var no_of_rows = 0,
      no_of_rows_all = 0;
      var rowsShown = 50;

      //getting no. of paths to be displayed from config file
      var no_of_paths=10,
      paths_selected=[];

      $("div.logcontainer").append($("
<button id='All' href='All'> Top Ten Most Visited Paths </button>
"));

      $(document).ready(function(){
        $('#All').addClass('clickedbutton');
          $.get("json/logListing/All/1",function(data){
            console.log("on load");

              alldata();
          });

        });

      $('div.logcontainer').on('click','button',function(){

          var clicked = $(this),
          id = clicked.attr('id');

          if(id=="All") {
            alldata();
          }//if

      })//click

      function alldata(){
            console.log("inside all script");
              href="/All";
              $.get("json/logListing"+href+"/1",function(data){
                  count = data[1].count;
                  console.log("count "+data[1].count);

                    drawHeader(data[0],"All");
                    drawTable(data[0],"All");

                    //pagenation call
                    $('#nav').html('');
                    $('#personDataTable').after('

');
                    var rowsTotal =  count;
                    drawRowDynamic(data,rowsTotal,href,'/All');

              });//ajax req

      }//alldata fn

    //initialising no_of_paths  from config file

      no_of_paths = config.paths;

      //storing the paths a/c to config file
      $.get("json/logListing/",function(data) {
        data = JSON.parse(data);

                for(var i=0; i<no_of_paths; i++)
                {
                  //storing paths into an array

                    paths_selected.push({"path": data.arr[i]["path"],
                    "count": data.arr[i]["count"]
                    });
                }
               var paths= $(document).trigger('pathArray', paths_selected);

    });

    //Displaying the paths in the document
    $(document).on('pathArray', function(e, arry){// arry is just the first item why???

        for(var j =0 ; j<paths_selected.length; j++)
        {
          $("div.logcontainer").append($('
<button id = '+ paths_selected[j]["path"] + ' href = '+ paths_selected[j]["path"] + ' > ' + paths_selected[j]["path"] + ' ' + '('+ paths_selected[j]["count"] + ')'+'</button>	'));
          $("div.logcontainer tr button").addClass("logButtonStyle");
        }
    });

      $('div.logcontainer').on('mouseover','button',function() {

            $(this).removeClass('mouseout').addClass('mouseover');
      }); //hover event for button

      $('div.logcontainer').on('mouseout','button',function() {

          $(this).addClass('mouseout');
      });//mouseout event for button

      $('div.logcontainer').on('click','button',function(){

          $(this).parent().parent().siblings().children().children().removeClass('clickedbutton');

          $(this).addClass('clickedbutton');

           no_of_rows_all = 0;
           $('tbody').remove();

           var clicked = $(this),
           id = clicked.attr('id');
           if(id!="All"){

                        href = clicked.attr('href');

                   //got the path so fetch corresponding json file
                       var pos_found = i+1;
                       //ajax request to the clicked path json
                       if(pos_found > 7)
                       document.location.href='#';
                      temp =  href.substring(1);
                      newhref = "/"+temp.split('/').join('^');

                       $.get("json/logListing"+newhref+"/1", function(data){
                         console.log(data);
                          var count=data[1].count;
                         console.log("count "+count);

                           drawHeader(data[0],id);
                           drawTable(data[0],id);
                           //pagenation call
                           $('#nav').html('');
                           $('#personDataTable').after('

');

                           var rowsTotal =  count;
                           drawRowDynamic(data,rowsTotal,newhref,id);

                       });

            }//close if

         });//click end

      function drawHeader(data,id){

            $("#personDataTable").html('');
            no_of_rows = 0;
            var row = $("
");

            $("#personDataTable").append(row);
            if(id!="All"){
            delete data[0].path;
            delete data[0]._id;
            }
            else {
              delete data[0]._id;
            }

            for(key in data[0]){
                row.append($("" + key+ "	"));
            }

      }//end draw header

       function drawTable(data,id) {

            no_of_rows = 0;
            for (var i = 0; i < data.length; i++) {
                 drawRow(data[i],id);
             }
       }//end draw table

       function drawRow(rowData,id) {

             var row = $("
")
             $("#personDataTable").append(row); //this will append tr element to table...
             var objdate = new Date(parseInt(rowData.time));

             var path = rowData.path;
             delete rowData.time;
            if(id!="All"){
                delete rowData.path;
                delete rowData._id; }
            else {
                delete rowData._id;
            }

            for(key in rowData){

                if(key === "agent") {
                  //checking for browser names
                  var temp = rowData[key],
                      title;
                  if(temp.indexOf("Chrome") != -1)
                      {title="Chrome";}
                  else if (temp.indexOf("Safari")!= -1)
                      {title="Safari";}
                  else if (temp.indexOf("Trident")!= -1)
                      {title="IE";}
                  else if (temp.indexOf("Vagrant")!= -1)
                      {title="Others";}
                  else if (temp.indexOf("Opr")!= -1)
                       {title="Opera";}
                  else if (temp.indexOf("-")!= -1)
                      {title="Others";}
                  else
                        {title="Mozilla";}

                  row.append($("" + title + "	")
                      .attr("title",rowData[key]));
                }

                else if(key=="size") {
                    //changing size to mb or kb
                      rowData.size=parseInt(rowData.size)/8;
                      if(rowData.size>1000 && rowData.size<1000000)
                          {rowData.size = parseFloat(rowData.size)/1000;
                           rowData.size = (rowData.size).toFixed(2)+ " KB" ;}

                      else if (rowData.size<1000 ) {
                           rowData.size = rowData.size + " B" ;}

                      else if (rowData.size>1000000 ) {
                         rowData.size = parseFloat(rowData.size)/1000000;
                         rowData.size = (rowData.size).toFixed(2)+ " MB" ;
                       }

                       row.append($("" + rowData[key] + "	"));
               }//else for size key

                else {
                    row.append($("" + rowData[key] + "	"));
                }

          }//close  for key in rowData
            row.append($("" + String(objdate).substring(0, 25) + "	"));
            no_of_rows ++;
            no_of_rows_all++;
     }//end draw row

     function drawRowDynamic(data, rowsTotal,path,id){
              rowsShown= 100;
              console.log("rowsTotal "+rowsTotal);
          var numPages = Math.ceil(rowsTotal/rowsShown);

          console.log("numpages= "+numPages);
          for(i = 0;i < numPages;i++) {
                  var pageNum = i + 1;
                  $('#nav').append(''+pageNum+' ');
          }

          // $('#personDataTable tbody tr').hide();
          // $('#personDataTable tbody tr').slice(0, rowsShown).show();
          $('#nav a:first').addClass('active');
          //$('#rowsshowing').remove();
          $('#nav a').bind('click', function(){

              $('#nav a').removeClass('active');
              $(this).addClass('active');
              var currPage = parseInt($(this).attr('rel')) +1;
              console.log("current page "+currPage);
              $.get("json/logListing"+path+"/"+currPage, function(data){

                    drawHeader(data[0],id);
                    drawTable(data[0],id);

              });

              // var startItem = currPage * rowsShown;
              // var endItem = startItem + rowsShown;
              //  dispPages =($('#personDataTable tbody tr').slice(startItem, endItem)).length;

              //  $('#rowsshowing').remove();
            //  $('#nav').append('('+  dispPages +'/'+ rowsTotal+') ')

              // $('#personDataTable tbody tr').css('opacity','0.0').hide().slice(startItem, endItem).
              //         css('display','table-row').animate({opacity:1}, 300);

          });//end pagenumber link fn
    }//end drawRowDynamic

})(jQuery, window, document);
<commit_msg>date 1970 bug solved loglisting<commit_after>(function($, window, document, undefined){

      var no_of_rows = 0,
      no_of_rows_all = 0;
      var rowsShown = 50;

      //getting no. of paths to be displayed from config file
      var no_of_paths=10,
      paths_selected=[];

      $("div.logcontainer").append($("
<button id='All' href='All'> Top Ten Most Visited Paths </button>
"));

      $(document).ready(function(){
        $('#All').addClass('clickedbutton');
        alldata();
      });

      $('div.logcontainer').on('click','button',function(){

          var clicked = $(this),
          id = clicked.attr('id');

          if(id=="All") {
            alldata();
          }//if

      })//click

      function alldata(){
              href="/All";
              $.get("json/logListing"+href+"/1",function(data){
                  count = data[1].count;

                    drawHeader(data[0],"All");
                    drawTable(data[0],"All");

                    //pagenation call
                    $('#nav').html('');
                    $('#personDataTable').after('

');
                    var rowsTotal =  count;
                    drawRowDynamic(data,rowsTotal,href,'/All');

              });//ajax req

      }//alldata fn

    //initialising no_of_paths  from config file

      no_of_paths = config.paths;

      //storing the paths a/c to config file
      $.get("json/logListing/",function(data) {
        data = JSON.parse(data);

                for(var i=0; i<no_of_paths; i++)
                {
                  //storing paths into an array

                    paths_selected.push({"path": data.arr[i]["path"],
                    "count": data.arr[i]["count"]
                    });
                }
               var paths= $(document).trigger('pathArray', paths_selected);

    });

    //Displaying the paths in the document
    $(document).on('pathArray', function(e, arry){// arry is just the first item why???

        for(var j =0 ; j<paths_selected.length; j++)
        {
          $("div.logcontainer").append($('
<button id = '+ paths_selected[j]["path"] + ' href = '+ paths_selected[j]["path"] + ' > ' + paths_selected[j]["path"] + ' ' + '('+ paths_selected[j]["count"] + ')'+'</button>	'));
          $("div.logcontainer tr button").addClass("logButtonStyle");
        }
    });

      $('div.logcontainer').on('mouseover','button',function() {

            $(this).removeClass('mouseout').addClass('mouseover');
      }); //hover event for button

      $('div.logcontainer').on('mouseout','button',function() {

          $(this).addClass('mouseout');
      });//mouseout event for button

      $('div.logcontainer').on('click','button',function(){

          $(this).parent().parent().siblings().children().children().removeClass('clickedbutton');

          $(this).addClass('clickedbutton');

           no_of_rows_all = 0;
           $('tbody').remove();

           var clicked = $(this),
           id = clicked.attr('id');
           if(id!="All"){

                        href = clicked.attr('href');

                   //got the path so fetch corresponding json file
                       var pos_found = i+1;
                       //ajax request to the clicked path json
                       if(pos_found > 7)
                       document.location.href='#';
                      temp =  href.substring(1);
                      newhref = "/"+temp.split('/').join('^');

                       $.get("json/logListing"+newhref+"/1", function(data){
                          var count=data[1].count;

                           drawHeader(data[0],id);
                           drawTable(data[0],id);
                           //pagenation call
                           $('#nav').html('');
                           $('#personDataTable').after('

');

                           var rowsTotal =  count;
                           drawRowDynamic(data,rowsTotal,newhref,id);

                       });

            }//close if

         });//click end

      function drawHeader(data,id){

            $("#personDataTable").html('');
            no_of_rows = 0;
            var row = $("
");

            $("#personDataTable").append(row);
            if(id!="All"){
            delete data[0].path;
            delete data[0]._id;
            }
            else {
              delete data[0]._id;
            }

            for(key in data[0]){
                row.append($("" + key+ "	"));
            }

      }//end draw header

       function drawTable(data,id) {

            no_of_rows = 0;
            for (var i = 0; i < data.length; i++) {
                 drawRow(data[i],id);
             }
       }//end draw table

       function drawRow(rowData,id) {

             var row = $("
")
             $("#personDataTable").append(row); //this will append tr element to table...
             var objdate = new Date(rowData.time);

             var path = rowData.path;
             delete rowData.time;
            if(id!="All"){
                delete rowData.path;
                delete rowData._id; }
            else {
                delete rowData._id;
            }

            for(key in rowData){

                if(key === "agent") {
                  //checking for browser names
                  var temp = rowData[key],
                      title;
                  if(temp.indexOf("Chrome") != -1)
                      {title="Chrome";}
                  else if (temp.indexOf("Safari")!= -1)
                      {title="Safari";}
                  else if (temp.indexOf("Trident")!= -1)
                      {title="IE";}
                  else if (temp.indexOf("Vagrant")!= -1)
                      {title="Others";}
                  else if (temp.indexOf("Opr")!= -1)
                       {title="Opera";}
                  else if (temp.indexOf("-")!= -1)
                      {title="Others";}
                  else
                        {title="Mozilla";}

                  row.append($("" + title + "	")
                      .attr("title",rowData[key]));
                }

                else if(key=="size") {
                    //changing size to mb or kb
                      rowData.size=parseInt(rowData.size)/8;
                      if(rowData.size>1000 && rowData.size<1000000)
                          {rowData.size = parseFloat(rowData.size)/1000;
                           rowData.size = (rowData.size).toFixed(2)+ " KB" ;}

                      else if (rowData.size<1000 ) {
                           rowData.size = rowData.size + " B" ;}

                      else if (rowData.size>1000000 ) {
                         rowData.size = parseFloat(rowData.size)/1000000;
                         rowData.size = (rowData.size).toFixed(2)+ " MB" ;
                       }

                       row.append($("" + rowData[key] + "	"));
               }//else for size key

                else {
                    row.append($("" + rowData[key] + "	"));
                }

          }//close  for key in rowData
            row.append($("" + String(objdate).substring(0, 25) + "	"));
            no_of_rows ++;
            no_of_rows_all++;
     }//end draw row

     function drawRowDynamic(data, rowsTotal,path,id){
              rowsShown= 100;
          var numPages = Math.ceil(rowsTotal/rowsShown);

          for(i = 0;i < numPages;i++) {
                  var pageNum = i + 1;
                  $('#nav').append(''+pageNum+' ');
          }

          // $('#personDataTable tbody tr').hide();
          // $('#personDataTable tbody tr').slice(0, rowsShown).show();
          $('#nav a:first').addClass('active');
          //$('#rowsshowing').remove();
          $('#nav a').bind('click', function(){

              $('#nav a').removeClass('active');
              $(this).addClass('active');
              var currPage = parseInt($(this).attr('rel')) +1;

              $.get("json/logListing"+path+"/"+currPage, function(data){

                    drawHeader(data[0],id);
                    drawTable(data[0],id);

              });

              // var startItem = currPage * rowsShown;
              // var endItem = startItem + rowsShown;
              //  dispPages =($('#personDataTable tbody tr').slice(startItem, endItem)).length;

              //  $('#rowsshowing').remove();
            //  $('#nav').append('('+  dispPages +'/'+ rowsTotal+') ')

              // $('#personDataTable tbody tr').css('opacity','0.0').hide().slice(startItem, endItem).
              //         css('display','table-row').animate({opacity:1}, 300);

          });//end pagenumber link fn
    }//end drawRowDynamic

})(jQuery, window, document);
<|endoftext|>


<commit_before>/* l-b
 * This file is part of ES Search.
 *
 * Copyright (c) 2009 Jacob Essex
 *
 * Foobar is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ES Search is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with ES Search. If not, see <http://www.gnu.org/licenses/>.
 * l-b */

$(function() {

    if ( $('#formSwapLink').length !== 1 ){
        return;
    }

    //set the html for the button
    $("#formSwapLink").show()
    .data('other', $('#activeForm').attr('name'))
    .html($('#inactiveForm').attr('name'));

    var af = $('#activeForm');
    var bf = $('#inactiveForm');
    af.after('

');

    var tf = $('#tempForm').hide();

    //center the advanced form table
    //TODO FIX IN CSS
    $('#activeForm table').attr('style', 'margin:auto');
    $('#inactiveForm table').attr('style', 'margin:auto');

    $('#formSwapLink').click(function(){
        tf.html(bf.attr('value'));

        $('#tempForm table').attr('style', 'margin:auto');

        af.toggle('blind', {}, 500);
        tf.toggle('blind', {}, 500, function(){
            bf.attr('value', af.html());
            af.html(tf.html());
            af.show();
            tf.hide();
        });

        $.cookie('CurrentSearchType', $(this).html());

        //swap the data for the link names over
        var t = $(this).data('other');
        $(this).data('other', $(this).html());
        $(this).html(t);
    });

});<commit_msg>Stores the state of the 'game' drop down box<commit_after>/* l-b
 * This file is part of ES Search.
 *
 * Copyright (c) 2009 Jacob Essex
 *
 * Foobar is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ES Search is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with ES Search. If not, see <http://www.gnu.org/licenses/>.
 * l-b */

$(function() {

    if ( $('#formSwapLink').length !== 1 ){
        return;
    }

    //set the html for the button
    $("#formSwapLink").show()
    .data('other', $('#activeForm').attr('name'))
    .html($('#inactiveForm').attr('name'));

    var af = $('#activeForm');
    var bf = $('#inactiveForm');
    af.after('

');

    var tf = $('#tempForm').hide();

    //center the advanced form table
    //TODO FIX IN CSS
    $('#activeForm table').attr('style', 'margin:auto');
    $('#inactiveForm table').attr('style', 'margin:auto');

    $('#formSwapLink').click(function(){
        tf.html(bf.attr('value'));

        $('#tempForm table').attr('style', 'margin:auto');

        af.toggle('blind', {}, 500);
        tf.toggle('blind', {}, 500, function(){
            bf.attr('value', af.html());
            af.html(tf.html());
            af.show();
            tf.hide();

            if ( $.cookie('SelectedGame') ){
                $('#game').val($.cookie('SelectedGame'));
            }
        });

        $.cookie('CurrentSearchType', $(this).html());

        //swap the data for the link names over
        var t = $(this).data('other');
        $(this).data('other', $(this).html());
        $(this).html(t);
    });
});

$(function(){
    $('#game').live('change', function(){
        $.cookie('SelectedGame', $(this).val());
    });
    if ( $.cookie('SelectedGame') ){
        $('#game').val($.cookie('SelectedGame'));
    }
});<|endoftext|>


<commit_before>var photoArray = [];

define(['facebook'], function(){
  // initializes fb call
  FB.init({
    appId : '711138455590961', // this app id might need to be hidden at some point
  });
  FB.login(function(response){
    if(response.authResponse){
      FB.api('/me/photos?limit=100', function(res){
        photoArray.push(res.data);
        $.ajax({
          url: res.paging.next, complete: function(res) {
            photoArray.push(JSON.parse(res.responseText).data);
            console.log(res);
          }
        });
      });
    } else {
       console.log('User cancelled login or did not fully authorize.');
    }
  }, {scope: ['user_photos']});
});<commit_msg>Pulls all photos and sets pagination scaffolding<commit_after>var photoArray = [];
var photosByYou = 0;
var photosByOthers = 0;
var username;

define(['facebook'], function(){
  // initializes fb call
  FB.init({
    appId : '711138455590961', // this app id might need to be hidden at some point
  });
  FB.login(function(response){
    if(response.authResponse){
      FB.api('/me/photos?limit=400', function(res){
        photoArray.push(res.data);
        // with more time, this is where to begin logic to grab data from pagination
        // note that total photos is only 400 so it's hardcoded for the purpose of the hackathon
        // you can call getNextPage and break when the last item in the array has lengh < the limit in '/me/photos?limit=x'
        console.log('Completed photo fetch');
      });
    } else {
       console.log('User cancelled login or did not fully authorize.');
    }
  }, {scope: ['user_photos']});
});

// this is an incomplete method to grab data from the next page
// return a bool on whether it is the last page and the next page's url if not null
// it should accept as argument the array to push to
// note this is not necessary for this purpose
var getNextPage = function(nextURL) {
  $.ajax({
    url: res.paging.next, complete: function(res) {
      photoArray.push(JSON.parse(res.responseText).data);
      console.log('page get call returned and pushed');
      return res.paging.next;
    }
  });
};<|endoftext|>


<commit_before>jQuery(function($) {
    // Used for code highlighting
    hljs.initHighlightingOnLoad();
});<commit_msg>Forgot gallery js<commit_after>jQuery(function ($) {
    // Used for code highlighting
    hljs.initHighlightingOnLoad();

    var colorbox_params = {
        reposition: true,
        scalePhotos: true,
        scrolling: false,
        previous: '',
        next: '',
        close: '×',
        current: '{current} of {total}',
        maxWidth: '100%',
        maxHeight: '100%',
        onOpen: function () {
            document.body.style.overflow = 'hidden';
        },
        onClosed: function () {
            document.body.style.overflow = 'auto';
        },
        onComplete: function () {
            $.colorbox.resize();
        }
    };

    $('.ace-thumbnails [data-rel="colorbox"]').colorbox(colorbox_params);

    $("#cboxLoadingGraphic").append(""); //let's add a custom loading icon
});<|endoftext|>


<commit_before>/*
 * Copyright 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Definitions for all the extensions over W3C's DOM
 *  specification by webkit. This file depends on w3c_dom2.js.
 *  All the provided definitions has been type annotated
 *
 * @externs
 */

/**
 * @constructor
 * @see http://trac.webkit.org/browser/trunk/WebCore/page/Console.idl
 * @see http://trac.webkit.org/browser/trunk/WebCore/page/Console.cpp
 */
function Console() {};

/**
 * @param {*} condition
 * @param {...*} var_args
 */
Console.prototype.assert = function(condition, var_args) {};

/**
 * @param {...*} var_args
 */
Console.prototype.error = function(var_args) {};

/**
 * @param {...*} var_args
 */
Console.prototype.info = function(var_args) {};

/**
 * @param {...*} var_args
 */
Console.prototype.log = function(var_args) {};

/**
 * @param {...*} var_args
 */
Console.prototype.warn = function(var_args) {};

/**
 * @param {...*} var_args
 */
Console.prototype.debug = function(var_args) {};

/**
 * @param {*} value
 */
Console.prototype.dir = function(value) {};

/**
 * @param {...*} var_args
 */
Console.prototype.dirxml = function(var_args) {};

/**
 * @param {*} value
 */
Console.prototype.trace = function(value) {};

/**
 * @param {*} value
 */
Console.prototype.count = function(value) {};

/**
 * @param {string=} opt_title
 */
Console.prototype.profile = function(opt_title) {};

Console.prototype.profileEnd = function() {};

/**
 * @param {string} name
 */
Console.prototype.time = function(name) {};

/**
 * @param {string} name
 */
Console.prototype.timeEnd = function(name) {};

Console.prototype.group = function() {};
Console.prototype.groupEnd = function() {};

/** @type {Console} */
Window.prototype.console;

/**
 * @type {number}
 * @see http://developer.android.com/reference/android/webkit/WebView.html
 */
Window.prototype.devicePixelRatio;

/** @type {Node} */
Selection.prototype.baseNode;

/** @type {number} */
Selection.prototype.baseOffset;

/** @type {Node} */
Selection.prototype.extentNode;

/** @type {number} */
Selection.prototype.extentOffset;

/** @type {string} */
Selection.prototype.type;

/**
 * @return {undefined}
 */
Selection.prototype.empty = function() {};

/**
 * @param {Node} baseNode
 * @param {number} baseOffset
 * @param {Node} extentNode
 * @param {number} extentOffset
 * @return {undefined}
 */
Selection.prototype.setBaseAndExtent =
 function(baseNode, baseOffset, extentNode, extentOffset) {};

/**
 * @param {string} alter
 * @param {string} direction
 * @param {string} granularity
 * @return {undefined}
 */
Selection.prototype.modify = function(alter, direction, granularity) {};

/**
 * @param {Element} element
 * @param {string} pseudoElement
 * @param {boolean=} opt_authorOnly
 * @return {CSSRuleList}
 * @nosideeffects
 */
ViewCSS.prototype.getMatchedCSSRules =
    function(element, pseudoElement, opt_authorOnly) {};

/**
 * @param {string} contextId
 * @param {string} name
 * @param {number} width
 * @param {number} height
 * @nosideeffects
 */
Document.prototype.getCSSCanvasContext =
    function(contextId, name, width, height) {};

<commit_msg><commit_after>/*
 * Copyright 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Definitions for all the extensions over W3C's DOM
 *  specification by webkit. This file depends on w3c_dom2.js.
 *  All the provided definitions has been type annotated
 *
 * @externs
 */

/**
 * @constructor
 * @see http://trac.webkit.org/browser/trunk/WebCore/page/Console.idl
 * @see http://trac.webkit.org/browser/trunk/WebCore/page/Console.cpp
 */
function Console() {};

/**
 * @param {*} condition
 * @param {...*} var_args
 */
Console.prototype.assert = function(condition, var_args) {};

/**
 * @param {...*} var_args
 */
Console.prototype.error = function(var_args) {};

/**
 * @param {...*} var_args
 */
Console.prototype.info = function(var_args) {};

/**
 * @param {...*} var_args
 */
Console.prototype.log = function(var_args) {};

/**
 * @param {...*} var_args
 */
Console.prototype.warn = function(var_args) {};

/**
 * @param {...*} var_args
 */
Console.prototype.debug = function(var_args) {};

/**
 * @param {*} value
 */
Console.prototype.dir = function(value) {};

/**
 * @param {...*} var_args
 */
Console.prototype.dirxml = function(var_args) {};

/**
 * @param {*} value
 */
Console.prototype.trace = function(value) {};

/**
 * @param {*} value
 */
Console.prototype.count = function(value) {};

/**
 * @param {string=} opt_title
 */
Console.prototype.profile = function(opt_title) {};

Console.prototype.profileEnd = function() {};

/**
 * @param {string} name
 */
Console.prototype.time = function(name) {};

/**
 * @param {string} name
 */
Console.prototype.timeEnd = function(name) {};

Console.prototype.group = function() {};
Console.prototype.groupEnd = function() {};

/** @type {Console} */
Window.prototype.console;

/**
 * @type {number}
 * @see http://developer.android.com/reference/android/webkit/WebView.html
 */
Window.prototype.devicePixelRatio;

/** @type {Node} */
Selection.prototype.baseNode;

/** @type {number} */
Selection.prototype.baseOffset;

/** @type {Node} */
Selection.prototype.extentNode;

/** @type {number} */
Selection.prototype.extentOffset;

/** @type {string} */
Selection.prototype.type;

/**
 * @return {undefined}
 */
Selection.prototype.empty = function() {};

/**
 * @param {Node} baseNode
 * @param {number} baseOffset
 * @param {Node} extentNode
 * @param {number} extentOffset
 * @return {undefined}
 */
Selection.prototype.setBaseAndExtent =
 function(baseNode, baseOffset, extentNode, extentOffset) {};

/**
 * @param {string} alter
 * @param {string} direction
 * @param {string} granularity
 * @return {undefined}
 */
Selection.prototype.modify = function(alter, direction, granularity) {};

/**
 * @param {Element} element
 * @param {string} pseudoElement
 * @param {boolean=} opt_authorOnly
 * @return {CSSRuleList}
 * @nosideeffects
 */
ViewCSS.prototype.getMatchedCSSRules =
    function(element, pseudoElement, opt_authorOnly) {};

/**
 * @param {string} contextId
 * @param {string} name
 * @param {number} width
 * @param {number} height
 * @nosideeffects
 */
Document.prototype.getCSSCanvasContext =
    function(contextId, name, width, height) {};

/**
 * @type {string}
 * @see http://code.google.com/chrome/whitepapers/pagevisibility.html
 */
Document.prototype.webkitVisibilityState;
<|endoftext|>


<commit_before>hqDefine("icds/js/location_reassignment", [
    'jquery',
    'knockout',
    'hqwebapp/js/assert_properties',
    'locations/js/search',
], function (
    $,
    ko,
    assertProperties
) {
    $(function () {
        var LocationReassignmentModel = function (options) {
            assertProperties.assertRequired(options, ['baseUrl']);

            var self = {};
            self.baseUrl = options.baseUrl;

            // Download
            self.location_id = ko.observable('');
            self.url = ko.computed(function () {
                return self.baseUrl + "?location_id=" + (self.location_id() || '');
            });

            // Upload
            self.file = ko.observable();

            return self;
        };

        var $content = $("#hq-content");
        $content.koApplyBindings(LocationReassignmentModel({
            baseUrl: $content.find("#download_link").attr("href"),
        }));
    });
});
<commit_msg>avoid indefinite spinner<commit_after>hqDefine("icds/js/location_reassignment", [
    'jquery',
    'knockout',
    'hqwebapp/js/assert_properties',
    'locations/js/search',
], function (
    $,
    ko,
    assertProperties
) {
    $(function () {
        var LocationReassignmentModel = function (options) {
            assertProperties.assertRequired(options, ['baseUrl']);

            var self = {};
            self.baseUrl = options.baseUrl;

            // Download
            self.location_id = ko.observable('');
            self.url = ko.computed(function () {
                return self.baseUrl + "?location_id=" + (self.location_id() || '');
            });

            // Upload
            self.file = ko.observable();

            return self;
        };

        var $content = $("#hq-content");
        $content.koApplyBindings(LocationReassignmentModel({
            baseUrl: $content.find("#download_link").attr("href"),
        }));

        // https://stackoverflow.com/a/35489517
        // bind the form submit to the document ajax to get notified on success
        $("#bulk_upload_form").on("submit", function(e) {
            $.ajax({context: this})
        });

        $("#bulk_upload_form").ajaxSuccess(function(event) {
            if (event.target.id === "bulk_upload_form") {
                $(event.target).trigger('reset');
            }
        });
    });
});
<|endoftext|>