browser/metro/modules/ContentUtil.jsm
author David Rajchenbach-Teller <dteller@mozilla.com>
Fri, 17 Oct 2014 10:17:37 -0400
changeset 213384 09fbfd40895ad06d6168f1288dbb397969800f0d
parent 189502 ca251a28d3ddae784436d28829fb019025f4b127
permissions -rw-r--r--
Bug 1083989 - Browser Chrome mochitests should not export Promise.jsm to the scope. r=ted

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";

this.EXPORTED_SYMBOLS = ["ContentUtil"];

const XHTML_NS = "http://www.w3.org/1999/xhtml";
const nsIDOMKeyEvent = Components.interfaces.nsIDOMKeyEvent;

this.ContentUtil = {
  populateFragmentFromString: function populateFragmentFromString(fragment, str) {
    let re = /^([^#]*)#(\d+)\b([^#]*)/,
        document = fragment.ownerDocument,
        // the remaining arguments are our {text, className} values
        replacements = Array.slice(arguments, 2),
        match;

    // walk over the string, building textNode/spans as nec. with replacement content
    // note that #1,#2 etc. may not appear in numerical order in the string
    while ((match = re.exec(str))) {
      let [mstring,pre,num,post] = match,
          replaceText = "",
          replaceClass,
          idx = num-1; // markers are 1-based, replacement indices 0 based

      str = str.substring(re.lastIndex+mstring.length);

      if (pre)
          fragment.appendChild(document.createTextNode(pre));

      if (replacements[idx]) {
        replaceText = replacements[idx].text;
        let spanNode = document.createElementNS(XHTML_NS, "span");
        spanNode.appendChild(document.createTextNode(replaceText));
        // add class to the span when provided
        if(replacements[idx].className)
          spanNode.classList.add(replacements[idx].className);

        fragment.appendChild(spanNode);
      } else {
        // put it back if no replacement was provided
        fragment.appendChild(document.createTextNode("#"+num));
      }

      if(post)
        fragment.appendChild(document.createTextNode(post));
    }
    if(str)
      fragment.appendChild(document.createTextNode(str));

    return fragment;
  },

  // Pass several objects in and it will combine them all into the first object and return it.
  // NOTE: Deep copy is not supported
  extend: function extend() {
    // copy reference to target object
    let target = arguments[0] || {};
    let length = arguments.length;

    if (length === 1) {
      return target;
    }

    // Handle case when target is a string or something
    if (typeof target != "object" && typeof target != "function") {
      target = {};
    }

    for (let i = 1; i < length; i++) {
      // Only deal with non-null/undefined values
      let options = arguments[i];
      if (options != null) {
        // Extend the base object
        for (let name in options) {
          let copy = options[name];

          // Prevent never-ending loop
          if (target === copy)
            continue;

          if (copy !== undefined)
            target[name] = copy;
        }
      }
    }

    // Return the modified object
    return target;
  },

  // Checks if a keycode is used for list navigation.
  isNavigationKey: function (keyCode) {
    let navigationKeys = [
      nsIDOMKeyEvent.DOM_VK_DOWN,
      nsIDOMKeyEvent.DOM_VK_UP,
      nsIDOMKeyEvent.DOM_VK_LEFT,
      nsIDOMKeyEvent.DOM_VK_RIGHT,
      nsIDOMKeyEvent.DOM_VK_PAGE_UP,
      nsIDOMKeyEvent.DOM_VK_PAGE_DOWN,
      nsIDOMKeyEvent.DOM_VK_ESCAPE];

    return navigationKeys.indexOf(keyCode) != -1;
  }
};