<commit_before>/*
 * This content script takes input from its webpage and executes commands locally on behalf of the background
 * page. It must be run prior to domReady so that we perform some operations very early, like setting
 * the page's zoom level. We tell the background page that we're in domReady and ready to accept normal
 * commands by connectiong to a port named "domReady".
 */
var settings = {};
var settingsToLoad = ["scrollStepSize"];

var getCurrentUrlHandlers = []; // function(url)

var keyCodes = { ESC: 27, backspace: 8, deleteKey: 46, enter: 13, space: 32 };
var insertMode = false;
var findMode = false;
var findModeQuery = "";
var findModeQueryHasResults = false;
var keyPort;
var settingPort;
var saveZoomLevelPort;
// Users can disable Vimium on URL patterns via the settings page.
var isEnabledForUrl = true;
// The user's operating system.
var platform;
var currentCompletionKeys;

// TODO(philc): This should be pulled from the extension's storage when the page loads.
var currentZoomLevel = 100;

// This is a mapping of the incorrect keyIdentifiers generated by Webkit on Windows during keydown events to
// the correct identifiers, which are correctly generated on Mac. We require this mapping to properly handle
// these keys on Windows. See https://bugs.webkit.org/show_bug.cgi?id=19906 for more details.
// TODO(philc): Currently we cannot distinguish between e.g. ",<"; we'll need to look at the keyboard event's
// shift key to do so on Windows.
var keyIdentifierCorrectionMap = {
  "U+00C0": "U+0060", // `~
  "U+00BD": "U+002D", // -_
  "U+00BB": "U+003D", // =+
  "U+00DB": "U+005B", // [{
  "U+00DD": "U+005D", // ]}
  "U+00DC": "U+005C", // \|
  "U+00BA": "U+003B", // ;:
  "U+00DE": "U+0027", // '"
  "U+00BC": "U+002C", // ,<
  "U+00BE": "U+002E", // .>
  "U+00BF": "U+002F"  // /?
};

function getSetting(key) {
  if (!settingPort)
    settingPort = chrome.extension.connect({ name: "getSetting" });
  settingPort.postMessage({ key: key });
}

function setSetting(args) { settings[args.key] = args.value; }

/*
 * Complete initialization work that sould be done prior to DOMReady, like setting the page's zoom level.
 */
function initializePreDomReady() {
  for (var i in settingsToLoad) { getSetting(settingsToLoad[i]); }

  var isEnabledForUrlPort = chrome.extension.connect({ name: "isEnabledForUrl" });
  isEnabledForUrlPort.postMessage({ url: window.location.toString() });

  var getZoomLevelPort = chrome.extension.connect({ name: "getZoomLevel" });
  getZoomLevelPort.postMessage({ domain: window.location.host });

  refreshCompletionKeys();

  // Send the key to the key handler in the background page.
  keyPort = chrome.extension.connect({ name: "keyDown" });

  if (navigator.userAgent.indexOf("Mac") != -1)
    platform = "Mac";
  else if (navigator.userAgent.indexOf("Linux") != -1)
    platform = "Linux";
  else
    platform = "Windows";

  chrome.extension.onConnect.addListener(function(port, name) {
    if (port.name == "executePageCommand") {
      port.onMessage.addListener(function(args) {
        if (this[args.command]) {
          for (var i = 0; i < args.count; i++) { this[args.command].call(); }
        }

        refreshCompletionKeys(args.completionKeys);
      });
    }
    else if (port.name == "getScrollPosition") {
      port.onMessage.addListener(function(args) {
        var scrollPort = chrome.extension.connect({ name: "returnScrollPosition" });
        scrollPort.postMessage({
          scrollX: window.scrollX,
          scrollY: window.scrollY,
          currentTab: args.currentTab
        });
      });
    } else if (port.name == "setScrollPosition") {
      port.onMessage.addListener(function(args) {
        if (args.scrollX > 0 || args.scrollY > 0) { window.scrollBy(args.scrollX, args.scrollY); }
      });
    } else if (port.name == "returnCurrentTabUrl") {
      port.onMessage.addListener(function(args) {
        if (getCurrentUrlHandlers.length > 0) { getCurrentUrlHandlers.pop()(args.url); }
      });
    } else if (port.name == "returnZoomLevel") {
      port.onMessage.addListener(function(args) {
        currentZoomLevel = args.zoomLevel;
        if (isEnabledForUrl)
          setPageZoomLevel(currentZoomLevel);
      });
    } else if (port.name == "returnIsEnabledForUrl") {
      port.onMessage.addListener(function(args) {
        isEnabledForUrl = args.isEnabledForUrl;
        if (isEnabledForUrl)
          initializeWhenEnabled();
        else if (HUD.isReady())
          // Quickly hide any HUD we might already be showing, e.g. if we entered insertMode on page load.
          HUD.hide();
      });
    } else if (port.name == "returnSetting") {
      port.onMessage.addListener(setSetting);
    } else if (port.name == "refreshCompletionKeys") {
      port.onMessage.addListener(function (args) {
        refreshCompletionKeys(args.completionKeys);
      });
    }
  });
}

/*
 * This is called once the background page has told us that Vimium should be enabled for the current URL.
 */
function initializeWhenEnabled() {
  document.addEventListener("keydown", onKeydown, true);
  document.addEventListener("focus", onFocusCapturePhase, true);
  document.addEventListener("blur", onBlurCapturePhase, true);
  enterInsertModeIfElementIsFocused();
}

/*
 * Initialization tasks that must wait for the document to be ready.
 */
function initializeOnDomReady() {
  if (isEnabledForUrl)
    enterInsertModeIfElementIsFocused();
  // Tell the background page we're in the dom ready state.
  chrome.extension.connect({ name: "domReady" });
};

/*
 * Checks the currently focused element of the document and will enter insert mode if that element is focusable.
 */
function enterInsertModeIfElementIsFocused() {
  // Enter insert mode automatically if there's already a text box focused.
  // TODO(philc): Consider using document.activeElement here instead.
  var focusNode = window.getSelection().focusNode;
  var focusOffset = window.getSelection().focusOffset;
  if (focusNode && focusOffset && focusNode.children.length > focusOffset &&<commit_msg>Check for "not null" instead of false (which incorrectly includes 0) when focusing an element. Fixes #63.<commit_after>/*
 * This content script takes input from its webpage and executes commands locally on behalf of the background
 * page. It must be run prior to domReady so that we perform some operations very early, like setting
 * the page's zoom level. We tell the background page that we're in domReady and ready to accept normal
 * commands by connectiong to a port named "domReady".
 */
var settings = {};
var settingsToLoad = ["scrollStepSize"];

var getCurrentUrlHandlers = []; // function(url)

var keyCodes = { ESC: 27, backspace: 8, deleteKey: 46, enter: 13, space: 32 };
var insertMode = false;
var findMode = false;
var findModeQuery = "";
var findModeQueryHasResults = false;
var keyPort;
var settingPort;
var saveZoomLevelPort;
// Users can disable Vimium on URL patterns via the settings page.
var isEnabledForUrl = true;
// The user's operating system.
var platform;
var currentCompletionKeys;

// TODO(philc): This should be pulled from the extension's storage when the page loads.
var currentZoomLevel = 100;

// This is a mapping of the incorrect keyIdentifiers generated by Webkit on Windows during keydown events to
// the correct identifiers, which are correctly generated on Mac. We require this mapping to properly handle
// these keys on Windows. See https://bugs.webkit.org/show_bug.cgi?id=19906 for more details.
// TODO(philc): Currently we cannot distinguish between e.g. ",<"; we'll need to look at the keyboard event's
// shift key to do so on Windows.
var keyIdentifierCorrectionMap = {
  "U+00C0": "U+0060", // `~
  "U+00BD": "U+002D", // -_
  "U+00BB": "U+003D", // =+
  "U+00DB": "U+005B", // [{
  "U+00DD": "U+005D", // ]}
  "U+00DC": "U+005C", // \|
  "U+00BA": "U+003B", // ;:
  "U+00DE": "U+0027", // '"
  "U+00BC": "U+002C", // ,<
  "U+00BE": "U+002E", // .>
  "U+00BF": "U+002F"  // /?
};

function getSetting(key) {
  if (!settingPort)
    settingPort = chrome.extension.connect({ name: "getSetting" });
  settingPort.postMessage({ key: key });
}

function setSetting(args) { settings[args.key] = args.value; }

/*
 * Complete initialization work that sould be done prior to DOMReady, like setting the page's zoom level.
 */
function initializePreDomReady() {
  for (var i in settingsToLoad) { getSetting(settingsToLoad[i]); }

  var isEnabledForUrlPort = chrome.extension.connect({ name: "isEnabledForUrl" });
  isEnabledForUrlPort.postMessage({ url: window.location.toString() });

  var getZoomLevelPort = chrome.extension.connect({ name: "getZoomLevel" });
  getZoomLevelPort.postMessage({ domain: window.location.host });

  refreshCompletionKeys();

  // Send the key to the key handler in the background page.
  keyPort = chrome.extension.connect({ name: "keyDown" });

  if (navigator.userAgent.indexOf("Mac") != -1)
    platform = "Mac";
  else if (navigator.userAgent.indexOf("Linux") != -1)
    platform = "Linux";
  else
    platform = "Windows";

  chrome.extension.onConnect.addListener(function(port, name) {
    if (port.name == "executePageCommand") {
      port.onMessage.addListener(function(args) {
        if (this[args.command]) {
          for (var i = 0; i < args.count; i++) { this[args.command].call(); }
        }

        refreshCompletionKeys(args.completionKeys);
      });
    }
    else if (port.name == "getScrollPosition") {
      port.onMessage.addListener(function(args) {
        var scrollPort = chrome.extension.connect({ name: "returnScrollPosition" });
        scrollPort.postMessage({
          scrollX: window.scrollX,
          scrollY: window.scrollY,
          currentTab: args.currentTab
        });
      });
    } else if (port.name == "setScrollPosition") {
      port.onMessage.addListener(function(args) {
        if (args.scrollX > 0 || args.scrollY > 0) { window.scrollBy(args.scrollX, args.scrollY); }
      });
    } else if (port.name == "returnCurrentTabUrl") {
      port.onMessage.addListener(function(args) {
        if (getCurrentUrlHandlers.length > 0) { getCurrentUrlHandlers.pop()(args.url); }
      });
    } else if (port.name == "returnZoomLevel") {
      port.onMessage.addListener(function(args) {
        currentZoomLevel = args.zoomLevel;
        if (isEnabledForUrl)
          setPageZoomLevel(currentZoomLevel);
      });
    } else if (port.name == "returnIsEnabledForUrl") {
      port.onMessage.addListener(function(args) {
        isEnabledForUrl = args.isEnabledForUrl;
        if (isEnabledForUrl)
          initializeWhenEnabled();
        else if (HUD.isReady())
          // Quickly hide any HUD we might already be showing, e.g. if we entered insertMode on page load.
          HUD.hide();
      });
    } else if (port.name == "returnSetting") {
      port.onMessage.addListener(setSetting);
    } else if (port.name == "refreshCompletionKeys") {
      port.onMessage.addListener(function (args) {
        refreshCompletionKeys(args.completionKeys);
      });
    }
  });
}

/*
 * This is called once the background page has told us that Vimium should be enabled for the current URL.
 */
function initializeWhenEnabled() {
  document.addEventListener("keydown", onKeydown, true);
  document.addEventListener("focus", onFocusCapturePhase, true);
  document.addEventListener("blur", onBlurCapturePhase, true);
  enterInsertModeIfElementIsFocused();
}

/*
 * Initialization tasks that must wait for the document to be ready.
 */
function initializeOnDomReady() {
  if (isEnabledForUrl)
    enterInsertModeIfElementIsFocused();
  // Tell the background page we're in the dom ready state.
  chrome.extension.connect({ name: "domReady" });
};

/*
 * Checks the currently focused element of the document and will enter insert mode if that element is focusable.
 */
function enterInsertModeIfElementIsFocused() {
  // Enter insert mode automatically if there's already a text box focused.
  // TODO(philc): Consider using document.activeElement here instead.
  var focusNode = window.getSelection().focusNode;
  var focusOffset = window.getSelection().focusOffset;
  if (focusNode && focusOffset != null && focusNode.children.length > focusOffset &&
{'fraction_non_alphanumeric': 0.1282867875224563, 'fraction_numerical': 0.013473787359137677, 'mean_word_length': 3.5989485542621105, 'pattern_counts': {'":': 22, '<': 9, '<?xml version=': 0, '>': 13, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2178278', 'n_tokens_mistral': 3763, 'n_tokens_neox': 3585, 'n_words': 1071}