<commit_before>/**
 * Module Dependencies
 */

var Zeditor = require('zeditor');
var plugin = require('zeditor-plugin');

var htmlpipe = require('html-pipe');
var toArray = require('to-array');
var classes = require('component-classes');
var tmp = require('tmp-el');
var domPaste = require('dom-paste');
var currentRange = require('current-range');
var currentSelection = require('current-selection');
var insertNode = require('range-insert-node');
var query = require('component-query');
var move = require('dom-move');

var HTMLBlock = require('../../lib/block-html');
var is = require('../../lib/is');
var insertPastedContent = require('./insert');

/**
 * Expose pasted
 */

module.exports = plugin(ZeditorPaste);

/**
 * Pasted editor plugin
 */

function ZeditorPaste(node) {
  Zeditor(node).el.addEventListener('paste', onPaste, false);
  Zeditor(node).normalizer.use(normalizePaste, Zeditor(node).normalizer.BEFORE_BUILTINS);
}

function onPaste(e) {
  // parse and sanitize the text
  domPaste(e, function(content) {
    if (!content) return;

    // hook for plugins to inspect/alter "paste" content before insertion
    editor.emit('paste', content);
    editor.normalizer.normalize('paste', content);

    var fragment = move(content);
    var selection = currentSelection(editor.el);
    var range = currentRange(selection);
    var end = fragment.lastChild;

    var joinHint = document.createElement('span');
    joinHint.className = 'tmp';
    joinHint.innerHTML = '';
    end.appendChild(joinHint);

    // inject the content into the editor
    editor.transactions.run(function() {
      // remove selected content (if any)
      range.deleteContents();

      insertPastedContent(editor.el, fragment, range);
    });

    // implicitly called here by the mutation observer:
    // editor.normalizer.normalize();

    editor.transactions.runAndSquash(function() {
      // place collapsed cursor after content
      range.selectNode(query('.tmp', editor.el));
      range.deleteContents();
      range.collapse(false);

      // add range to selection
      selection.removeAllRanges();
      selection.addRange(range);
    });
  });
}

function normalizePaste(root, subtree, context) {
  if (context != 'paste') return;

  checkForSingleA(root);

  console.log(root.innerHTML);

  htmlpipe(root)
    .pipe(replaceElements('CITE'))
    .pipe(removeMSOEmptyParagraphs())
    .pipe(detectMSOQuotes())
    .pipe(detectMSOLists())
    .pipe(convertMSOMarginToPadding())
    .pipe(unwrapElements('SPAN', 'FONT'))
    .pipe(allowedStyles('text-align', 'padding-left'))
    .pipe(normalizeInlineElements())
    .run();

  htmlpipe(root)
    .pipe(normalizeWhitespace())
    .pipe(removeComments())
    .run();

  htmlpipe(root)
    .pipe(joinMSOLists())
    .pipe(allowedElements(editor, 'A', 'STRONG', 'B', 'BLOCKQUOTE', 'BR', 'CODE', 'DEL', 'DIV', 'U', 'EM', 'I', 'SUP', 'SUB',
          'H1', 'H2', 'H3', 'H4', 'H5', 'H6',
          'STRIKE', 'P', 'FONT', 'OL', 'UL', 'LI'))
    .pipe(allowedAttrs('style', 'type', 'href'))
    .run();
}

function checkForSingleA(root) {
  // Safari will paste URLs from other sources as a single "A" element.
  // We check for this pattern and transform it into the text content to
  // allow easy embedding.
  if (root.firstChild &&
      root.firstChild == root.lastChild &&
      root.firstChild.nodeName == 'A' &&
      root.firstChild.firstChild &&
      root.firstChild.firstChild == root.firstChild.lastChild &&
      root.firstChild.firstChild.nodeType == Node.TEXT_NODE &&
      root.firstChild.href == root.firstChild.firstChild.nodeValue) {
    root.replaceChild(root.firstChild.firstChild, root.firstChild);
  }
}

function normalizeInlineElements() {
  return function(el) {
    var tmpEl;
    if (el.nodeName == 'STRIKE' || el.nodeName == 'S') {
      tmpEl = document.createElement('del');
      while (el.firstChild) {
        tmpEl.appendChild(el.firstChild);
      }
      el.appendChild(tmpEl);
      return false;
    } else if (el.nodeName == 'B') {
      tmpEl = document.createElement('strong');
      while (el.firstChild) {
        tmpEl.appendChild(el.firstChild);
      }
      el.appendChild(tmpEl);
      return false;
    } else if (el.nodeName == 'I') {
      tmpEl = document.createElement('em');
      while (el.firstChild) {
        tmpEl.appendChild(el.firstChild);
      }
      el.appendChild(tmpEl);
      return false;
    }
  }
}

function removeMSOEmptyParagraphs() {
  return function(el) {
    if (el.nodeName == 'P' && el.className.match(/^MsoNormal/)) {
      if (el.childNodes.length == 1) {
        if (el.firstChild.nodeName == 'O:P' &&
            el.firstChild.childNodes.length == 1 &&
            el.firstChild.firstChild.nodeType == Node.TEXT_NODE &&
            el.firstChild.firstChild.nodeValue == '\u00A0' /*   */) {
          return null;
        }
        if (el.firstChild.nodeType == Node.TEXT_NODE &&
            el.firstChild.nodeValue == '\u00A0' /*   */) {
          return null;
        }
      }
    }
  }
}

function detectMSOQuotes() {
  return function(el) {
    if (el.nodeName == 'P' && el.className.match(/^Mso(Intense)?Quote/)) {
      var blockquote = document.createElement('blockquote');
      var p = document.createElement('p');
      while (el.firstChild) {
        p.appendChild(el.firstChild);
      }
      blockquote.appendChild(p);
      el.appendChild(blockquote);
      return false;
    }
  }
}

function detectMSOLists() {
  return function(el) {
    var placeholder = '';
    var listEl;
    var listType;
    if (el.nodeName == 'P' && el.className.match(/^MsoList/)) {
      var style = el.getAttribute('style') || '';
      var msoListInfo = style.match(/mso\-list\:\s*l([A-Za-z0-9]+)\s+level([A-Za-z0-9]+)\s+lfo([A-Za-z0-9]+)\;?/);
      if (el.firstChild && el.firstChild.nodeType == Node.COMMENT_NODE && el.firstChild.nodeValue == '[if !supportLists]') {
        while (el.childNodes[1] && el.childNodes[1].nodeType != Node.COMMENT_NODE) {
          placeholder += el.childNodes[1].textContent;
          if (el.childNodes[1].nodeType == Node.ELEMENT_NODE) {
            if (el.childNodes[1].style['font-family'].match(/(\"|\')?Symbol|Wingdings|Courier New(\"|\')?/)) {
              listEl = 'ul';
            }
          }
          el.removeChild(el.childNodes[1]);
        }
      } else if (el.firstChild && el.firstChild.nodeType == Node.ELEMENT_NODE) {
        placeholder = el.firstChild.textContent;
        if (el.firstChild.style['font-family'].match(/(\"|\')?Symbol|Wingdings|Courier New(\"|\')?/)) {
          listEl = 'ul';
        }
        el.removeChild(el.firstChild);
      } else {
        el.setAttribute('data-mso-list', 'separator');
        return;
      }
      if (!listEl) {
        placeholder = placeholder.replace(/\s+/g, '');
        if (placeholder.match(/^[0-9]/)) {
          listEl = 'ol';
          listType = '1';
        } else if (placeholder.match(/^[ivx]/)) {
          listEl = 'ol';
          listType = 'i';
        } else if (placeholder.match(/^[IVX]/)) {
          listEl = 'ol';
          listType = 'I';
        } else if (placeholder.match(/^[a-z]/)) {
          listEl = 'ol';
          listType = 'a';
        } else if (placeholder.match(/^[A-Z]/)) {
          listEl = 'ol';
          listType = 'A';
        } else {
          listEl = 'ul';
        }
      }
      var li = move(el, document.createElement('li'));
      var ul = document.createElement(listEl);
      ul.setAttribute('data-mso-list', 'item');
      ul.appendChild(li);
      if (listType) {
        ul.type = listType;
      }
      if (msoListInfo) {
        for (var level = 1; level < (+msoListInfo[2] || 1); level++) {
          var tmp = document.createElement(listEl);
          tmp.appendChild(ul);
          ul = tmp;
          ul.setAttribute('data-mso-list', 'nest');
        }
      }
      el.appendChild(ul);
      return false;
    }
  }
}

function joinMSOLists() {
  return function(el) {
    if (el.nodeType != Node.ELEMENT_NODE) {
      return;
    }
    if (el.getAttribute('data-mso-list') == 'item') {
      for (;;) {
        if (!el.nextElementSibling) break;

        var msoList = el.nextElementSibling.getAttribute('data-mso-list');

        if (msoList == 'item') {
          if (el.nodeName == el.nextElementSibling.nodeName) {
            if (el.type == el.nextElementSibling.type ||
              ((el.type == 'A' || el.type == 'a') && (el.nextElementSibling.type == 'I' || el.nextElementSibling.type == 'i')) ||
              ((el.type == 'I' || el.type == 'i') && (el.nextElementSibling.type == 'A' || el.nextElementSibling.type == 'a'))) {
              move(el.nextElementSibling, el);
              el.parentNode.removeChild(el.nextElementSibling);
            } else {
              break;
            }
          } else {
            break;
          }
        } else if (msoList == 'nest') {
          move(el.nextElementSibling, el);
          el.parentNode.removeChild(el.nextElementSibling);
        } else {
          break;
        }
      }
    } else if (el.getAttribute('data-mso-list') == 'separator') {
      return null;
    }
  }
}

function convertMSOMarginToPadding() {
  return function(el) {
    if (el.nodeName != 'P') {
      return;
    }
    if (!el.className.match(/^Mso.+/)) {
      return;
    }
    if (el.style.paddingLeft) {
      return;
    }
    var marginLeft = parseInt(el.style.marginLeft, 10);
    // TODO: read the increment value from the PaddingCommand. We assume 30 here
    var paddingLeft = Math.round(marginLeft / 36.0) * 30;
    el.style.paddingLeft = paddingLeft + 'px';
  }
}

function replaceElements() {
  var args = toArray(arguments);

  return function(el) {
    var replace = ~args.indexOf(el.nodeName);
    if (!replace) return;
    var tmpEl = document.createElement('p');
    while (el.firstChild) {
      tmpEl.appendChild(el.firstChild);
    }
    el.appendChild(tmpEl);
    return false;
  }
}

/**
 * Unwrap elements
 *
 * @return {Function} fn
 */

function unwrapElements() {
  var args = toArray(arguments);

  return function(el) {
    var unwrap = ~args.indexOf(el.nodeName);
    if (!unwrap) return;
    var tmpEl;
    var computedStyle = window.getComputedStyle(el, null);
    var weight = computedStyle.fontWeight;
    var style = computedStyle.fontStyle;
    var family = computedStyle.fontFamily;
    var decoration = computedStyle.textDecoration;
    if (weight == 'bold' ||
        weight == 'bolder' ||
        parseInt(weight) > 500) {
      tmpEl = document.createElement('strong');
      while (el.firstChild) {
        tmpEl.appendChild(el.firstChild);
      }
      el.appendChild(tmpEl);
    }
    if (style == 'italic' || style == 'oblique') {
      tmpEl = document.createElement('em');
      while (el.firstChild) {
        tmpEl.appendChild(el.firstChild);
      }
      el.appendChild(tmpEl);
    }
    if (decoration == 'underline') {
      tmpEl = document.createElement('u');
      while (el.firstChild) {
        tmpEl.appendChild(el.firstChild);
      }
      el.appendChild(tmpEl);
    }
    if (decoration == 'line-through') {
      tmpEl = document.createElement('del');
      while (el.firstChild) {
        tmpEl.appendChild(el.firstChild);
      }
      el.appendChild(tmpEl);
    }
    return false;
  };
}

function allowedStyles() {
  var names = toArray(arguments);
  return function (el) {
    if (el.nodeType != Node.ELEMENT_NODE) {
      return;
    }
    var tmp = {};
    for (var i = 0; i < names.length; i++) {
      name = names[i];
      tmp[name] = el.style[name];
    }
    el.removeAttribute('style');
    for (var i = 0; i < names.length; i++) {
      name = names[i];
      el.style[name] = tmp[name];
    }
  }
}
/**
 *
 */

function removeComments() {
  return function(node) {
    if (node.nodeType == Node.COMMENT_NODE) {
      return null;
    }
  }
}

/**
 * Normalize whitespace of non pre-wrap text nodes
 *
 * @return {Function} fn
 */

function normalizeWhitespace() {
  return function(node) {

    if (node.nodeType != Node.TEXT_NODE) {
      return;
    }

    var computedStyle = window.getComputedStyle(node.parentNode, null);
    if (computedStyle.whiteSpace.match(/^pre.*/)) {
      return;
    }

    node.nodeValue = node.nodeValue.replace(/\r|\n|\r\n/g, ' ').replace(/[ \t]+/g, ' ');

    var inlineAfter = node.nextSibling &&
                      node.nextSibling.nodeType == Node.ELEMENT_NODE &&
                      window.getComputedStyle(node.nextSibling).display == 'inline' &&
                      node.nextSibling.nodeName != 'BR';

    var inlineBefore = node.previousSibling &&
                       node.previousSibling.nodeType == Node.ELEMENT_NODE &&
                       window.getComputedStyle(node.previousSibling).display == 'inline' &&
                       node.previousSibling.nodeName != 'BR';

    if (computedStyle.display != 'inline') {
      if (inlineAfter) {
        if (inlineBefore) {
          // don't replace
        } else {
          node.nodeValue = node.nodeValue.replace(/^[ \t]+/g, '');
        }
      } else {
        if (inlineBefore) {
          node.nodeValue = node.nodeValue.replace(/[ \t]+$/g, '');
        } else {
          node.nodeValue = node.nodeValue.replace(/^[ \t]+|[ \t]+$/g, '');
        }
      }
    }
  }
}

/**
 * Whitelisted elements
 *
 * @return {Function} fn
 */

function allowedElements() {
  var args = toArray(arguments);
  var editor = args.shift();

  return function(el) {
    if (is.overlayReference(el)) {
      return;
    }
    if (el.nodeType == Node.TEXT_NODE) {
      return;
    }
    if (args.indexOf(el.nodeName) == -1) {
      if (el.nodeName == 'TABLE') {
        var block = new HTMLBlock(el);
        block.bind(editor);
        return block.el;
      }
      if (el.nodeName == 'STYLE') {
        return null;
      }
      return false;
    }
  };
}

/**
 * Whitelisted attrs on element nodes
 *
 * @return {Function} fn
 */

function allowedAttrs() {
  var allowed = {};

  for (var i = 0; i < arguments.length; i++) {
    allowed[arguments[i]] = true;
  }

  return function(el) {
    if (el.nodeType != Node.ELEMENT_NODE) {
      return;
    }

    if (is.overlayReference(el)) {
      return;
    }

    var attrs = toArray(el.attributes);

    for (var i = 0; i < attrs.length; i++) {
      var name = attrs[i].name;
      if (!allowed[name]) {
        el.removeAttribute(name);
      }
    }
  };
}
<commit_msg>Fix paste on paste plugin.<commit_after>/**
 * Module Dependencies
 */

var Zeditor = require('zeditor');
var plugin = require('zeditor-plugin');

var htmlpipe = require('html-pipe');
var toArray = require('to-array');
var classes = require('component-classes');
var tmp = require('tmp-el');
var domPaste = require('dom-paste');
var currentRange = require('current-range');
var currentSelection = require('current-selection');
var insertNode = require('range-insert-node');
var query = require('component-query');
var move = require('dom-move');

var HTMLBlock = require('../../lib/block-html');
var is = require('../../lib/is');
var insertPastedContent = require('./insert');

/**
 * Expose pasted
 */

module.exports = plugin(ZeditorPaste);

/**
 * Pasted editor plugin
 */

function ZeditorPaste(node) {
  Zeditor(node).el.addEventListener('paste', onPaste, false);
  Zeditor(node).normalizer.use(normalizePaste, Zeditor(node).normalizer.BEFORE_BUILTINS);

  function onPaste(e) {
    // parse and sanitize the text
    domPaste(e, function(content) {
      if (!content) return;

      // hook for plugins to inspect/alter "paste" content before insertion
      Zeditor(node).emit('paste', content);
      Zeditor(node).normalizer.normalize('paste', content);

      var fragment = move(content);
      var selection = currentSelection(Zeditor(node).el);
      var range = currentRange(selection);
      var end = fragment.lastChild;

      var joinHint = document.createElement('span');
      joinHint.className = 'tmp';
      joinHint.innerHTML = '';
      end.appendChild(joinHint);

      // inject the content into the editor
      Zeditor(node).transactions.run(function() {
        // remove selected content (if any)
        range.deleteContents();

        insertPastedContent(Zeditor(node).el, fragment, range);
      });

      // implicitly called here by the mutation observer:
      // Zeditor(node).normalizer.normalize();

      Zeditor(node).transactions.runAndSquash(function() {
        // place collapsed cursor after content
        range.selectNode(query('.tmp', Zeditor(node).el));
        range.deleteContents();
        range.collapse(false);

        // add range to selection
        selection.removeAllRanges();
        selection.addRange(range);
      });
    });
  }

  function normalizePaste(root, subtree, context) {
    if (context != 'paste') return;

    checkForSingleA(root);

    console.log(root.innerHTML);

    htmlpipe(root)
      .pipe(replaceElements('CITE'))
      .pipe(removeMSOEmptyParagraphs())
      .pipe(detectMSOQuotes())
      .pipe(detectMSOLists())
      .pipe(convertMSOMarginToPadding())
      .pipe(unwrapElements('SPAN', 'FONT'))
      .pipe(allowedStyles('text-align', 'padding-left'))
      .pipe(normalizeInlineElements())
      .run();

    htmlpipe(root)
      .pipe(normalizeWhitespace())
      .pipe(removeComments())
      .run();

    htmlpipe(root)
      .pipe(joinMSOLists())
      .pipe(allowedElements(Zeditor(node), 'A', 'STRONG', 'B', 'BLOCKQUOTE', 'BR', 'CODE', 'DEL', 'DIV', 'U', 'EM', 'I', 'SUP', 'SUB',
            'H1', 'H2', 'H3', 'H4', 'H5', 'H6',
            'STRIKE', 'P', 'FONT', 'OL', 'UL', 'LI'))
      .pipe(allowedAttrs('style', 'type', 'href'))
      .run();
  }
}

function checkForSingleA(root) {
  // Safari will paste URLs from other sources as a single "A" element.
  // We check for this pattern and transform it into the text content to
  // allow easy embedding.
  if (root.firstChild &&
      root.firstChild == root.lastChild &&
      root.firstChild.nodeName == 'A' &&
      root.firstChild.firstChild &&
      root.firstChild.firstChild == root.firstChild.lastChild &&
      root.firstChild.firstChild.nodeType == Node.TEXT_NODE &&
      root.firstChild.href == root.firstChild.firstChild.nodeValue) {
    root.replaceChild(root.firstChild.firstChild, root.firstChild);
  }
}

function normalizeInlineElements() {
  return function(el) {
    var tmpEl;
    if (el.nodeName == 'STRIKE' || el.nodeName == 'S') {
      tmpEl = document.createElement('del');
      while (el.firstChild) {
        tmpEl.appendChild(el.firstChild);
      }
      el.appendChild(tmpEl);
      return false;
    } else if (el.nodeName == 'B') {
      tmpEl = document.createElement('strong');
      while (el.firstChild) {
        tmpEl.appendChild(el.firstChild);
      }
      el.appendChild(tmpEl);
      return false;
    } else if (el.nodeName == 'I') {
      tmpEl = document.createElement('em');
      while (el.firstChild) {
        tmpEl.appendChild(el.firstChild);
      }
      el.appendChild(tmpEl);
      return false;
    }
  }
}

function removeMSOEmptyParagraphs() {
  return function(el) {
    if (el.nodeName == 'P' && el.className.match(/^MsoNormal/)) {
      if (el.childNodes.length == 1) {
        if (el.firstChild.nodeName == 'O:P' &&
            el.firstChild.childNodes.length == 1 &&
            el.firstChild.firstChild.nodeType == Node.TEXT_NODE &&
            el.firstChild.firstChild.nodeValue == '\u00A0' /*   */) {
          return null;
        }
        if (el.firstChild.nodeType == Node.TEXT_NODE &&
            el.firstChild.nodeValue == '\u00A0' /*   */) {
          return null;
        }
      }
    }
  }
}

function detectMSOQuotes() {
  return function(el) {
    if (el.nodeName == 'P' && el.className.match(/^Mso(Intense)?Quote/)) {
      var blockquote = document.createElement('blockquote');
      var p = document.createElement('p');
      while (el.firstChild) {
        p.appendChild(el.firstChild);
      }
      blockquote.appendChild(p);
      el.appendChild(blockquote);
      return false;
    }
  }
}

function detectMSOLists() {
  return function(el) {
    var placeholder = '';
    var listEl;
    var listType;
    if (el.nodeName == 'P' && el.className.match(/^MsoList/)) {
      var style = el.getAttribute('style') || '';
      var msoListInfo = style.match(/mso\-list\:\s*l([A-Za-z0-9]+)\s+level([A-Za-z0-9]+)\s+lfo([A-Za-z0-9]+)\;?/);
      if (el.firstChild && el.firstChild.nodeType == Node.COMMENT_NODE && el.firstChild.nodeValue == '[if !supportLists]') {
        while (el.childNodes[1] && el.childNodes[1].nodeType != Node.COMMENT_NODE) {
          placeholder += el.childNodes[1].textContent;
          if (el.childNodes[1].nodeType == Node.ELEMENT_NODE) {
            if (el.childNodes[1].style['font-family'].match(/(\"|\')?Symbol|Wingdings|Courier New(\"|\')?/)) {
              listEl = 'ul';
            }
          }
          el.removeChild(el.childNodes[1]);
        }
      } else if (el.firstChild && el.firstChild.nodeType == Node.ELEMENT_NODE) {
        placeholder = el.firstChild.textContent;
        if (el.firstChild.style['font-family'].match(/(\"|\')?Symbol|Wingdings|Courier New(\"|\')?/)) {
          listEl = 'ul';
        }
        el.removeChild(el.firstChild);
      } else {
        el.setAttribute('data-mso-list', 'separator');
        return;
      }
      if (!listEl) {
        placeholder = placeholder.replace(/\s+/g, '');
        if (placeholder.match(/^[0-9]/)) {
          listEl = 'ol';
          listType = '1';
        } else if (placeholder.match(/^[ivx]/)) {
          listEl = 'ol';
          listType = 'i';
        } else if (placeholder.match(/^[IVX]/)) {
          listEl = 'ol';
          listType = 'I';
        } else if (placeholder.match(/^[a-z]/)) {
          listEl = 'ol';
          listType = 'a';
        } else if (placeholder.match(/^[A-Z]/)) {
          listEl = 'ol';
          listType = 'A';
        } else {
          listEl = 'ul';
        }
      }
      var li = move(el, document.createElement('li'));
      var ul = document.createElement(listEl);
      ul.setAttribute('data-mso-list', 'item');
      ul.appendChild(li);
      if (listType) {
        ul.type = listType;
      }
      if (msoListInfo) {
        for (var level = 1; level < (+msoListInfo[2] || 1); level++) {
          var tmp = document.createElement(listEl);
          tmp.appendChild(ul);
          ul = tmp;
          ul.setAttribute('data-mso-list', 'nest');
        }
      }
      el.appendChild(ul);
      return false;
    }
  }
}

function joinMSOLists() {
  return function(el) {
    if (el.nodeType != Node.ELEMENT_NODE) {
      return;
    }
    if (el.getAttribute('data-mso-list') == 'item') {
      for (;;) {
        if (!el.nextElementSibling) break;

        var msoList = el.nextElementSibling.getAttribute('data-mso-list');

        if (msoList == 'item') {
          if (el.nodeName == el.nextElementSibling.nodeName) {
            if (el.type == el.nextElementSibling.type ||
              ((el.type == 'A' || el.type == 'a') && (el.nextElementSibling.type == 'I' || el.nextElementSibling.type == 'i')) ||
              ((el.type == 'I' || el.type == 'i') && (el.nextElementSibling.type == 'A' || el.nextElementSibling.type == 'a'))) {
              move(el.nextElementSibling, el);
              el.parentNode.removeChild(el.nextElementSibling);
            } else {
              break;
            }
          } else {
            break;
          }
        } else if (msoList == 'nest') {
          move(el.nextElementSibling, el);
          el.parentNode.removeChild(el.nextElementSibling);
        } else {
          break;
        }
      }
    } else if (el.getAttribute('data-mso-list') == 'separator') {
      return null;
    }
  }
}

function convertMSOMarginToPadding() {
  return function(el) {
    if (el.nodeName != 'P') {
      return;
    }
    if (!el.className.match(/^Mso.+/)) {
      return;
    }
    if (el.style.paddingLeft) {
      return;
    }
    var marginLeft = parseInt(el.style.marginLeft, 10);
    // TODO: read the increment value from the PaddingCommand. We assume 30 here
    var paddingLeft = Math.round(marginLeft / 36.0) * 30;
    el.style.paddingLeft = paddingLeft + 'px';
  }
}

function replaceElements() {
  var args = toArray(arguments);

  return function(el) {
    var replace = ~args.indexOf(el.nodeName);
    if (!replace) return;
    var tmpEl = document.createElement('p');
    while (el.firstChild) {
      tmpEl.appendChild(el.firstChild);
    }
    el.appendChild(tmpEl);
    return false;
  }
}

/**
 * Unwrap elements
 *
 * @return {Function} fn
 */

function unwrapElements() {
  var args = toArray(arguments);

  return function(el) {
    var unwrap = ~args.indexOf(el.nodeName);
    if (!unwrap) return;
    var tmpEl;
    var computedStyle = window.getComputedStyle(el, null);
    var weight = computedStyle.fontWeight;
    var style = computedStyle.fontStyle;
    var family = computedStyle.fontFamily;
    var decoration = computedStyle.textDecoration;
    if (weight == 'bold' ||
        weight == 'bolder' ||
        parseInt(weight) > 500) {
      tmpEl = document.createElement('strong');
      while (el.firstChild) {
        tmpEl.appendChild(el.firstChild);
      }
      el.appendChild(tmpEl);
    }
    if (style == 'italic' || style == 'oblique') {
      tmpEl = document.createElement('em');
      while (el.firstChild) {
        tmpEl.appendChild(el.firstChild);
      }
      el.appendChild(tmpEl);
    }
    if (decoration == 'underline') {
      tmpEl = document.createElement('u');
      while (el.firstChild) {
        tmpEl.appendChild(el.firstChild);
      }
      el.appendChild(tmpEl);
    }
    if (decoration == 'line-through') {
      tmpEl = document.createElement('del');
      while (el.firstChild) {
        tmpEl.appendChild(el.firstChild);
      }
      el.appendChild(tmpEl);
    }
    return false;
  };
}

function allowedStyles() {
  var names = toArray(arguments);
  return function (el) {
    if (el.nodeType != Node.ELEMENT_NODE) {
      return;
    }
    var tmp = {};
    for (var i = 0; i < names.length; i++) {
      name = names[i];
      tmp[name] = el.style[name];
    }
    el.removeAttribute('style');
    for (var i = 0; i < names.length; i++) {
      name = names[i];
      el.style[name] = tmp[name];
    }
  }
}
/**
 *
 */

function removeComments() {
  return function(node) {
    if (node.nodeType == Node.COMMENT_NODE) {
      return null;
    }
  }
}

/**
 * Normalize whitespace of non pre-wrap text nodes
 *
 * @return {Function} fn
 */

function normalizeWhitespace() {
  return function(node) {

    if (node.nodeType != Node.TEXT_NODE) {
      return;
    }

    var computedStyle = window.getComputedStyle(node.parentNode, null);
    if (computedStyle.whiteSpace.match(/^pre.*/)) {
      return;
    }

    node.nodeValue = node.nodeValue.replace(/\r|\n|\r\n/g, ' ').replace(/[ \t]+/g, ' ');

    var inlineAfter = node.nextSibling &&
                      node.nextSibling.nodeType == Node.ELEMENT_NODE &&
                      window.getComputedStyle(node.nextSibling).display == 'inline' &&
                      node.nextSibling.nodeName != 'BR';

    var inlineBefore = node.previousSibling &&
                       node.previousSibling.nodeType == Node.ELEMENT_NODE &&
                       window.getComputedStyle(node.previousSibling).display == 'inline' &&
                       node.previousSibling.nodeName != 'BR';

    if (computedStyle.display != 'inline') {
      if (inlineAfter) {
        if (inlineBefore) {
          // don't replace
        } else {
          node.nodeValue = node.nodeValue.replace(/^[ \t]+/g, '');
        }
      } else {
        if (inlineBefore) {
          node.nodeValue = node.nodeValue.replace(/[ \t]+$/g, '');
        } else {
          node.nodeValue = node.nodeValue.replace(/^[ \t]+|[ \t]+$/g, '');
        }
      }
    }
  }
}

/**
 * Whitelisted elements
 *
 * @return {Function} fn
 */

function allowedElements() {
  var args = toArray(arguments);
  var editor = args.shift();

  return function(el) {
    if (is.overlayReference(el)) {
      return;
    }
    if (el.nodeType == Node.TEXT_NODE) {
      return;
    }
    if (args.indexOf(el.nodeName) == -1) {
      if (el.nodeName == 'TABLE') {
        var block = new HTMLBlock(el);
        block.bind(editor);
        return block.el;
      }
      if (el.nodeName == 'STYLE') {
        return null;
      }
      return false;
    }
  };
}

/**
 * Whitelisted attrs on element nodes
 *
 * @return {Function} fn
 */

function allowedAttrs() {
  var allowed = {};

  for (var i = 0; i < arguments.length; i++) {
    allowed[arguments[i]] = true;
  }

  return function(el) {
    if (el.nodeType != Node.ELEMENT_NODE) {
      return;
    }

    if (is.overlayReference(el)) {
      return;
    }

    var attrs = toArray(el.attributes);

    for (var i = 0; i < attrs.length; i++) {
      var name = attrs[i].name;
      if (!allowed[name]) {
        el.removeAttribute(name);
      }
    }
  };
}
<|endoftext|>


<commit_before>/**
 * @namespace ajax
 * @summary module to make ajax requests
 */
var ajax = (function() {
    "use strict";
    /**
     * @summary loader HTML element injected into loaderTarget when ajax is running
     * @private
     * @type {Element}
     */
    var loader = document.createElement("div");
    loader.className = "ajax-loader";

    /**
     * @memberof ajax
     * @summary injects the loader element into loaderTarget
     * @private
     * @param target {Element}
     */
    function startLoader(target) {
        target.appendChild(loader);
    }

    /**
     * @memberof ajax
     * @summary removes the loader from loaderTarget
     * @private
     * @param target {Element}
     */
    function stopLoader(target) {
        target.removeChild(loader);
    }

    /**
     * @memberof ajax
     * @summary executes the XMLHttpRequest
     * @private
     * @param c {object} request configuration hash
     */
    function sendRequest(c) {
        var req = new XMLHttpRequest();

        if (c.loaderTarget) {
            startLoader(c.loaderTarget);
        }

        // start XMLHttpRequest
        req.open(c.method, c.url, c.async);
        setRequestHeaders(req, c.setHeaders);

        // request now going through
        req.onreadystatechange = function() {
            // Headers & status are received
            if (req.readyState === 2) {
                if (c.onHeaders) {
                    c.onHeaders(req.getAllResponseHeaders());
                }
            }

            // request is complete and successful
            if (req.readyState === 4) {
                // loader needs to be removed BEFORE callbacks
                if (c.loaderTarget) {
                    stopLoader(c.loaderTarget);
                }

                // process success or failure callbacks
                if (req.status.toString().charAt(0) === "2" && c.onSuccess) {
                    c.onSuccess({
                        response: getResponse(req, c),
                        status: req.status,
                        getHeader: function(name) {
                            return req.getResponseHeader.call(req, name);
                        }
                    });
                } else if (c.onFailure) {
                    c.onFailure({
                        response: getResponse(req, c),
                        status: req.status,
                        getHeader: function(name) {
                            return req.getResponseHeader.call(req, name);
                        }
                    });
                }
            }
        };
        req.send(c.data);
    }

    /**
     * @memberof ajax
     * @summary sets basic headers for the request and sets the additional ones provided by the configuration
     * @private
     * @param req {object} XMLHttpRequest object
     * @param headers {object} additional headers to be injected
     */
    function setRequestHeaders(req, headers) {
        // set default values
        if (!headers["Content-Type"]) {
            headers["Content-Type"] = "application/json;charset=utf-8";
        }

        if (!headers.Accept) {
            headers.Accept = "application/json";
        }

        if (!headers["X-Requested-With"]) {
            headers["X-Requested-With"] = "XMLHttpRequest";
        }

        // get all object (t) keys from own properties
        // inject them as request headers
        Object.keys(headers).forEach(function(header) {
            req.setRequestHeader(header, headers[header]);
        });

        // xhr2 spec
        if (req.responseType) {
            req.responseType = c.responseType; // "arraybuffer", "blob", "document", "json", "text"
        }
    }

    /**
     * @memberof ajax
     * @summary parses the response data based on provided responseType
     * @private
     * @param req {object} XMLHttpRequest object
     * @param c {object} configuration hash
     * @returns the parsed data
     */
    function getResponse(req, c) {
        var r = req.response;

        if (c.responseType && c.responseType === "json" && r !== "") {
            r = JSON.parse(r);
        }

        return r;
    }

    /**
     * @memberof ajax
     * @private
     * @summary verifies content provided by configuration object
     * @param c {object} configuration hash
     * @returns {boolean} result of validation (true|false)
     */
    function validateConfig(c) {
        if (Object.prototype.toString.call(c.url) !== "[object String]") {
            throw new TypeError("ajax: requires a URL string");
        }

        if (c.loaderTarget && c.loaderTarget.nodeType !== 1) {
            throw new TypeError("ajax: 'loaderTarget' is not an HTML element");
        }

        if (Object.prototype.toString.call(c.method) === "[object String]") {
            c.method = c.method.toUpperCase();
            if (!["GET","POST","PUT","DELETE"].some(function(method) {
                return method === c.method;
            })) {
                throw new TypeError("ajax: 'method' must have one of the following values:\nGET\nPOST\nPUT\nDelete");
            }
        } else {
            throw Error("ajax: query 'method' is required");
        }

        if (c.setHeaders && Object.prototype.toString.call(c.setHeaders) !== "[object Object]") {
            throw new TypeError("ajax: 'setHeaders' is not an object");
        }

        if (c.onFailure && Object.prototype.toString.call(c.onFailure) !== "[object Function]") {
            throw new TypeError("ajax: onFailure must be a function");
        }
        if (c.onSuccess && Object.prototype.toString.call(c.onSuccess) !== "[object Function]") {
            throw new TypeError("ajax: onFailure must be a function");
        }
        if (c.onHeaders && Object.prototype.toString.call(c.onHEaders) !== "[object Function]") {
            throw new TypeError("ajax: onFailure must be a function");
        }

        if (c.responseType) {
            if (!["json","text","arraybuffer","document","blob"].some(function(value) {
                    return value === c.responseType;
                })) {
                throw new Error("ajax: responseType must have one of the following value:\njson\ntext\ndocument\nblob\narraybuffer");
            }
        }

        return true;
    }

    /**
     * @memberof ajax
     * @private
     * @summary builds the final request configuration object
     * @param c {object} configuration hash
     * @returns {
     *  {
     *   async: boolean,
     *   data: (object|null),
     *   setHeaders: (object|{}),
     *   method: string,
     *   onFailure: (function|null),
     *   onHeaders: (function|null),
     *   onSuccess: (function|null),
     *   responseType: (string),
     *   url: string,
     *   loaderTarget: (Element|null)
     *   }
     *  }
     */
    function finalizeConfig(c) {
        return {
            async: c.async !== false,
            data: c.data || null,
            setHeaders: c.setHeaders || {},
            method: c.method,
            onFailure: c.onFailure || null,
            onHeaders: c.onHeaders || null,
            onSuccess: c.onSuccess || null,
            responseType: c.responseType || "text",
            url: encodeURI(c.url).replace(/%5B/g, "[").replace(/%5D/g, "]"),
            loaderTarget: c.loadTarget || null
        };
    }

    function query(c) {
        if (validateConfig(c)) {
            sendRequest(finalizeConfig(c));
        }
    }

    return query;
}());
<commit_msg>fixed loaderTarget typo<commit_after>/**
 * @namespace ajax
 * @summary module to make ajax requests
 */
var ajax = (function() {
    "use strict";
    /**
     * @summary loader HTML element injected into loaderTarget when ajax is running
     * @private
     * @type {Element}
     */
    var loader = document.createElement("div");
    loader.className = "ajax-loader";

    /**
     * @memberof ajax
     * @summary injects the loader element into loaderTarget
     * @private
     * @param target {Element}
     */
    function startLoader(target) {
        target.appendChild(loader);
    }

    /**
     * @memberof ajax
     * @summary removes the loader from loaderTarget
     * @private
     * @param target {Element}
     */
    function stopLoader(target) {
        target.removeChild(loader);
    }

    /**
     * @memberof ajax
     * @summary executes the XMLHttpRequest
     * @private
     * @param c {object} request configuration hash
     */
    function sendRequest(c) {
        var req = new XMLHttpRequest();

        if (c.loaderTarget) {
            startLoader(c.loaderTarget);
        }

        // start XMLHttpRequest
        req.open(c.method, c.url, c.async);
        setRequestHeaders(req, c.setHeaders);

        // request now going through
        req.onreadystatechange = function() {
            // Headers & status are received
            if (req.readyState === 2) {
                if (c.onHeaders) {
                    c.onHeaders(req.getAllResponseHeaders());
                }
            }

            // request is complete and successful
            if (req.readyState === 4) {
                // loader needs to be removed BEFORE callbacks
                if (c.loaderTarget) {
                    stopLoader(c.loaderTarget);
                }

                // process success or failure callbacks
                if (req.status.toString().charAt(0) === "2" && c.onSuccess) {
                    c.onSuccess({
                        response: getResponse(req, c),
                        status: req.status,
                        getHeader: function(name) {
                            return req.getResponseHeader.call(req, name);
                        }
                    });
                } else if (c.onFailure) {
                    c.onFailure({
                        response: getResponse(req, c),
                        status: req.status,
                        getHeader: function(name) {
                            return req.getResponseHeader.call(req, name);
                        }
                    });
                }
            }
        };
        req.send(c.data);
    }

    /**
     * @memberof ajax
     * @summary sets basic headers for the request and sets the additional ones provided by the configuration
     * @private
     * @param req {object} XMLHttpRequest object
     * @param headers {object} additional headers to be injected
     */
    function setRequestHeaders(req, headers) {
        // set default values
        if (!headers["Content-Type"]) {
            headers["Content-Type"] = "application/json;charset=utf-8";
        }

        if (!headers.Accept) {
            headers.Accept = "application/json";
        }

        if (!headers["X-Requested-With"]) {
            headers["X-Requested-With"] = "XMLHttpRequest";
        }

        // get all object (t) keys from own properties
        // inject them as request headers
        Object.keys(headers).forEach(function(header) {
            req.setRequestHeader(header, headers[header]);
        });

        // xhr2 spec
        if (req.responseType) {
            req.responseType = c.responseType; // "arraybuffer", "blob", "document", "json", "text"
        }
    }

    /**
     * @memberof ajax
     * @summary parses the response data based on provided responseType
     * @private
     * @param req {object} XMLHttpRequest object
     * @param c {object} configuration hash
     * @returns the parsed data
     */
    function getResponse(req, c) {
        var r = req.response;

        if (c.responseType && c.responseType === "json" && r !== "") {
            r = JSON.parse(r);
        }

        return r;
    }

    /**
     * @memberof ajax
     * @private
     * @summary verifies content provided by configuration object
     * @param c {object} configuration hash
     * @returns {boolean} result of validation (true|false)
     */
    function validateConfig(c) {
        if (Object.prototype.toString.call(c.url) !== "[object String]") {
            throw new TypeError("ajax: requires a URL string");
        }

        if (c.loaderTarget && c.loaderTarget.nodeType !== 1) {
            throw new TypeError("ajax: 'loaderTarget' is not an HTML element");
        }

        if (Object.prototype.toString.call(c.method) === "[object String]") {
            c.method = c.method.toUpperCase();
            if (!["GET","POST","PUT","DELETE"].some(function(method) {
                return method === c.method;
            })) {
                throw new TypeError("ajax: 'method' must have one of the following values:\nGET\nPOST\nPUT\nDelete");
            }
        } else {
            throw Error("ajax: query 'method' is required");
        }

        if (c.setHeaders && Object.prototype.toString.call(c.setHeaders) !== "[object Object]") {
            throw new TypeError("ajax: 'setHeaders' is not an object");
        }

        if (c.onFailure && Object.prototype.toString.call(c.onFailure) !== "[object Function]") {
            throw new TypeError("ajax: onFailure must be a function");
        }
        if (c.onSuccess && Object.prototype.toString.call(c.onSuccess) !== "[object Function]") {
            throw new TypeError("ajax: onFailure must be a function");
        }
        if (c.onHeaders && Object.prototype.toString.call(c.onHEaders) !== "[object Function]") {
            throw new TypeError("ajax: onFailure must be a function");
        }

        if (c.responseType) {
            if (!["json","text","arraybuffer","document","blob"].some(function(value) {
                    return value === c.responseType;
                })) {
                throw new Error("ajax: responseType must have one of the following value:\njson\ntext\ndocument\nblob\narraybuffer");
            }
        }

        return true;
    }

    /**
     * @memberof ajax
     * @private
     * @summary builds the final request configuration object
     * @param c {object} configuration hash
     * @returns {
     *  {
     *   async: boolean,
     *   data: (object|null),
     *   setHeaders: (object|{}),
     *   method: string,
     *   onFailure: (function|null),
     *   onHeaders: (function|null),
     *   onSuccess: (function|null),
     *   responseType: (string),
     *   url: string,
     *   loaderTarget: (Element|null)
     *   }
     *  }
     */
    function finalizeConfig(c) {
        return {
            async: c.async !== false,
            data: c.data || null,
            setHeaders: c.setHeaders || {},
            method: c.method,
            onFailure: c.onFailure || null,
            onHeaders: c.onHeaders || null,
            onSuccess: c.onSuccess || null,
            responseType: c.responseType || "text",
            url: encodeURI(c.url).replace(/%5B/g, "[").replace(/%5D/g, "]"),
            loaderTarget: c.loaderTarget || null
        };
    }

    function query(c) {
        if (validateConfig(c)) {
            sendRequest(finalizeConfig(c));
        }
    }

    return query;
}());
<|endoftext|>


<commit_before>/**
 * @class Echo.StreamServer.Controls.Submit.Plugins.JanrainSharing
 * Plugin provides the ability to load JanRain sharing dialog after the item has been posted using the Echo Submit control.
 * Installation procedure also includes actions on Janrain side.
 *
 * Download the "rpx_xdcomm.html" file from the JanRain application dashboard (the "Deployment" -> "Social Sharing" section) and place it in the root directory of your website.
 *
 * Configure the list of the necessary social sharing providers in the JanRain application dashboard (the "Deployment" -> "Social Sharing" -> "Choose providers" section).
 *
 * 	var identityManager = {"width": 400, "height": 240, "url": "http://example.com/auth"};
 * 	new Echo.StreamServer.Controls.Stream({
 * 		"target": document.getElementById("echo-stream"),
 * 		"appkey": "test.echoenabled.com",
 * 		"plugins": [{
 * 			"name": "JanrainSharing",
 * 			"appId": "yourJanRainAppId",
 * 			"xdReceiver": "http://your-domain.com/rpx_xdcomm.html",
 * 			"activity": {
 * 				"sharePrompt": "Share your comment:",
 * 				"shareContent": "I just commented '{content}' on {domain}",
 * 				"itemURL": "http://your-domain.com/this-page.html"
 * 			}
 * 		}]
 * 	});
 * @extends Echo.Plugin
 * @inheritdoc Echo.Plugin
 */
var plugin = Echo.Plugin.manifest("JanrainSharing", "Echo.StreamServer.Controls.Submit");

if (Echo.Plugin.isDefined(plugin)) return;

plugin.enabled = function() {
	return (this.config.get("appId") && this.config.get("xdReceiver"));
};

plugin.labels = {
	"sharePrompt": "Share your comment:"
};

plugin.config = {
	// actual limit is 140, reserving some space
	// for ellipses and shortened link to the page
	"maxLength": 120,
	"reducedLength": 30,
	"maxImagesCount": 5
};

plugin.events = {
	"Echo.StreamServer.Controls.Submit.onPostComplete": function(topic, args) {
		var plugin = this;
		//TODO: using Echo.Loader when it's ready
		RPXNOW.init({
			"appId": plugin.config.get("appId"),
			"xdReceiver": plugin.config.get("xdReceiver")
		});
		RPXNOW.loadAndRun(["Social"], function () {
			var activity = new RPXNOW.Social.Activity(
				plugin.config.get("activity.sharePrompt", plugin.labels.get("sharePrompt")),
				plugin._prepareContent(args),
				plugin.config.get("activity.itemURL", args.targetURL)
			);
			RPXNOW.Social.publishActivity(plugin._prepareActivity(activity));
		});
	}
};

plugin.methods._prepareActivity = function(act) {
	var plugin = this;
	var activity = act;
	var handlers = {
		"activity.pageDescription": function(content) {
			activity.setDescription(content);
		},
		"activity.pageTitle": function(content) {
			activity.setTitle(content);
		},
		"activity.pageImages": function(content) {
			var count = 0;
			var maxCount = plugin.config.get("maxImagesCount");
			var collection = new RPXNOW.Social.ImageMediaCollection();
			$.each(content, function(key, image) {
				if (count === maxCount) return false;
				if (image.src && image.href) {
					collection.addImage(image.src, image.href);
					count++;
				}
			});
			activity.setMediaItem(collection);
		}
	};
	$.each(handlers, function(key, handler){
		if (plugin.config.get(key)) {
			handler(plugin.config.get(key));
		}
	});
	return activity;
};

plugin.methods._prepareContent = function(args) {
	var plugin = this;
	var text = Echo.Utils.stripTags(args.postData.content[0].object.content);
	var messagePattern = plugin.config.get("activity.shareContent");
	if (messagePattern) {
		return plugin.labels.get(messagePattern, {
			"domain": window.location.host,
			"content": plugin._truncate(text, plugin.config.get("reducedLength"))
		});
	}
	//if a reply to a tweet was posted
	var data = args.postData.inReplyTo;
	var maxLength = plugin.config.get("maxLength");
	if (plugin._isReplyToTweet(data)) {
		var author = plugin._getTweetAuthor(data);
		return plugin.labels.get("@{author} {content}", {
			"author": author,
			"content": plugin._truncate(text, maxLength - author.length - 2)
		});
	}
	return plugin._truncate(text, maxLength);
};

plugin.methods._truncate = function(text, limit) {
	return (limit > 0 && text.length > limit) ? text.substring(0, limit) + "..." : text;
};

plugin.methods._isReplyToTweet = function(data) {
	return !!(data && data.source && data.source.name === "Twitter");
};

plugin.methods._getTweetAuthor = function(data) {
	return data.actor.id.replace(/https?\:\/\/twitter\.com\//, "");
};

Echo.Plugin.create(plugin);<commit_msg>Added dependencies to JanrainSharing plugin<commit_after>/**
 * @class Echo.StreamServer.Controls.Submit.Plugins.JanrainSharing
 * Plugin provides the ability to load JanRain sharing dialog after the item has been posted using the Echo Submit control.
 * Installation procedure also includes actions on Janrain side.
 *
 * Download the "rpx_xdcomm.html" file from the JanRain application dashboard (the "Deployment" -> "Social Sharing" section) and place it in the root directory of your website.
 *
 * Configure the list of the necessary social sharing providers in the JanRain application dashboard (the "Deployment" -> "Social Sharing" -> "Choose providers" section).
 *
 * 	var identityManager = {"width": 400, "height": 240, "url": "http://example.com/auth"};
 * 	new Echo.StreamServer.Controls.Stream({
 * 		"target": document.getElementById("echo-stream"),
 * 		"appkey": "test.echoenabled.com",
 * 		"plugins": [{
 * 			"name": "JanrainSharing",
 * 			"appId": "yourJanRainAppId",
 * 			"xdReceiver": "http://your-domain.com/rpx_xdcomm.html",
 * 			"activity": {
 * 				"sharePrompt": "Share your comment:",
 * 				"shareContent": "I just commented '{content}' on {domain}",
 * 				"itemURL": "http://your-domain.com/this-page.html"
 * 			}
 * 		}]
 * 	});
 * @extends Echo.Plugin
 * @inheritdoc Echo.Plugin
 */
var plugin = Echo.Plugin.manifest("JanrainSharing", "Echo.StreamServer.Controls.Submit");

if (Echo.Plugin.isDefined(plugin)) return;

plugin.enabled = function() {
	return (this.config.get("appId") && this.config.get("xdReceiver"));
};

plugin.labels = {
	"sharePrompt": "Share your comment:"
};

plugin.dependencies = [{
	"loaded": function() { return !!window.RPXNOW; },
	"url": ("https:" === document.location.protocol) ?
		"https://" : "http://static." + "rpxnow.com/js/lib/rpx.js"
}];

plugin.config = {
	// actual limit is 140, reserving some space
	// for ellipses and shortened link to the page
	"maxLength": 120,
	"reducedLength": 30,
	"maxImagesCount": 5
};

plugin.events = {
	"Echo.StreamServer.Controls.Submit.onPostComplete": function(topic, args) {
		var plugin = this;
		RPXNOW.init({
			"appId": plugin.config.get("appId"),
			"xdReceiver": plugin.config.get("xdReceiver")
		});
		RPXNOW.loadAndRun(["Social"], function () {
			var activity = new RPXNOW.Social.Activity(
				plugin.config.get("activity.sharePrompt", plugin.labels.get("sharePrompt")),
				plugin._prepareContent(args),
				plugin.config.get("activity.itemURL", args.targetURL)
			);
			RPXNOW.Social.publishActivity(plugin._prepareActivity(activity));
		});
	}
};

plugin.methods._prepareActivity = function(act) {
	var plugin = this;
	var activity = act;
	var handlers = {
		"activity.pageDescription": function(content) {
			activity.setDescription(content);
		},
		"activity.pageTitle": function(content) {
			activity.setTitle(content);
		},
		"activity.pageImages": function(content) {
			var count = 0;
			var maxCount = plugin.config.get("maxImagesCount");
			var collection = new RPXNOW.Social.ImageMediaCollection();
			$.each(content, function(key, image) {
				if (count === maxCount) return false;
				if (image.src && image.href) {
					collection.addImage(image.src, image.href);
					count++;
				}
			});
			activity.setMediaItem(collection);
		}
	};
	$.each(handlers, function(key, handler){
		if (plugin.config.get(key)) {
			handler(plugin.config.get(key));
		}
	});
	return activity;
};

plugin.methods._prepareContent = function(args) {
	var plugin = this;
	var text = Echo.Utils.stripTags(args.postData.content[0].object.content);
	var messagePattern = plugin.config.get("activity.shareContent");
	if (messagePattern) {
		return plugin.labels.get(messagePattern, {
			"domain": window.location.host,
			"content": plugin._truncate(text, plugin.config.get("reducedLength"))
		});
	}
	//if a reply to a tweet was posted
	var data = args.postData.inReplyTo;
	var maxLength = plugin.config.get("maxLength");
	if (plugin._isReplyToTweet(data)) {
		var author = plugin._getTweetAuthor(data);
		return plugin.labels.get("@{author} {content}", {
			"author": author,
			"content": plugin._truncate(text, maxLength - author.length - 2)
		});
	}
	return plugin._truncate(text, maxLength);
};

plugin.methods._truncate = function(text, limit) {
	return (limit > 0 && text.length > limit) ? text.substring(0, limit) + "..." : text;
};

plugin.methods._isReplyToTweet = function(data) {
	return !!(data && data.source && data.source.name === "Twitter");
};

plugin.methods._getTweetAuthor = function(data) {
	return data.actor.id.replace(/https?\:\/\/twitter\.com\//, "");
};

Echo.Plugin.create(plugin);<|endoftext|>


<commit_before>/*global d3, utils */
"use strict";

// declaration of global object (modified by browser().load())
var VIS = {
    ready: { }, // which viz already generated?
    last: { // which subviews last shown?
        bib: { }
    },
    files: { // what data files to request
        info: "data/info.json",
        meta: "data/meta.csv.zip",  // remove .zip to use uncompressed data
        dt: "data/dt.json.zip",     // (name the actual file accordingly)
        tw: "data/tw.json",
        topic_scaled: "data/topic_scaled.csv"
    },
    aliases: {                  // simple aliasing in URLs:
        yearly: "conditional"   // #/model/yearly/... -> #/model/conditional/...
    },
    default_view: "/model", // specify the part after the #
    condition: {            // metadata variable to condition topics on
        type: "time",       // alternatives: "category" and "continuous"
        spec: {
            unit: "month",  // unit of time bins
            n: 1           // width of time bins
            // format: "%Y-%m" // can optionally specify key format (strftime)
        }
    },
    overview_words: 15,     // may need adjustment
    model_view: {
        w: 500,            // px: the minimum svg width
        aspect: 1.3333,     // for calculating height
        words: 4,           // maximum: may need adjustment
        size_range: [7, 18], // points. may need adjustment
        name_size: 18,      // points
        stroke_range: 6,    // max. perimeter thickness
        conditional: {
            w: 500,         // px: the minimum svg width
            aspect: 1.333,
            m: {
                left: 20,
                right: 20,
                top: 20,
                bottom: 20
            },
            label_threshold: 40, // px
            words: 4,
            label_words: 2 // should be <= words
        },
        list: {
            spark: { // same form as topic_view plot parameters below
                w: 70,
                h: 20,
                m: {
                    left: 2,
                    right: 2,
                    top: 2,
                    bottom: 2
                },
                time: {
                    bar: {
                        unit: "day",
                        w: 300
                    }
                }
            }
        }
    },
    topic_view: {
        words: 50,
        docs: 20,
        w: 400, // minimum in px
        aspect: 3,
        m: {
            left: 40,
            right: 20,
            top: 20,
            bottom: 20
        },
        time: { // conditional plot x-axis settings: time variable
            bar: { // width of bars
                unit: "day", // unit is used as d3.time[unit].utc
                w: 90
            },
            ticks: {
                unit: "year",
                n: 10
            }
        },
        continuous: { // continuous variable: step is calculated automatically
            bar: {
                w: 0.25, // proportion: how much x-axis bar takes up
            },
            ticks: 10
        },
        ordinal: { // categorical variable: step is calculated automatically
            bar: {
                w: 0.25 // proportion
            },
            ticks: 10
        },
        ticks_y: 10, // y axis ticks
        tx_duration: 1000 // animated transition time in ms (where applicable)
    },
    word_view: {
        n_min: 10, // words per topic
        topic_label_padding: 8, // pt
        topic_label_leading: 14, // pt
        row_height: 80, // pt
        svg_rows: 10, // * row_height gives min. height for svg element
        w: 700, // px: minimum width
        m: {
            left: 100,
            right: 40,
            top: 20,
            bottom: 0
        }
    },
    bib: {
        // default if no author delimiter supplied, but note that
        // 2014 JSTOR metadata format uses ", " instead
        author_delimiter: "\t",
        // "et al" is better for real bibliography, but it's
        // actually worth being able to search all the multiple authors
        et_al: Infinity,
        anon: "[Anon]",
    },
    bib_view: {
        window_lines: 100,
        major: "year",
        minor: "authortitle",
        dir: "up"
    },
    float_format: function (x) {
        return d3.round(x, 3);
    },
    tooltip: {              // tooltip div parameters
        offset: {
            x: 10,          // px
            y: 0
        }
    },
    percent_format: d3.format(".1%"),
    resize_refresh_delay: 100, // ms
    hidden_topics: [],      // list of 1-based topic numbers to suppress
    show_hidden_topics: false,
    annotes: [],            // list of CSS classes annotating the current view
    update: function (x) {
        return utils.deep_replace(this, x);
    }
};

<commit_msg>remove unused float_format<commit_after>/*global d3, utils */
"use strict";

// declaration of global object (modified by browser().load())
var VIS = {
    ready: { }, // which viz already generated?
    last: { // which subviews last shown?
        bib: { }
    },
    files: { // what data files to request
        info: "data/info.json",
        meta: "data/meta.csv.zip",  // remove .zip to use uncompressed data
        dt: "data/dt.json.zip",     // (name the actual file accordingly)
        tw: "data/tw.json",
        topic_scaled: "data/topic_scaled.csv"
    },
    aliases: {                  // simple aliasing in URLs:
        yearly: "conditional"   // #/model/yearly/... -> #/model/conditional/...
    },
    default_view: "/model", // specify the part after the #
    condition: {            // metadata variable to condition topics on
        type: "time",       // alternatives: "category" and "continuous"
        spec: {
            unit: "month",  // unit of time bins
            n: 1           // width of time bins
            // format: "%Y-%m" // can optionally specify key format (strftime)
        }
    },
    overview_words: 15,     // may need adjustment
    model_view: {
        w: 500,            // px: the minimum svg width
        aspect: 1.3333,     // for calculating height
        words: 4,           // maximum: may need adjustment
        size_range: [7, 18], // points. may need adjustment
        name_size: 18,      // points
        stroke_range: 6,    // max. perimeter thickness
        conditional: {
            w: 500,         // px: the minimum svg width
            aspect: 1.333,
            m: {
                left: 20,
                right: 20,
                top: 20,
                bottom: 20
            },
            label_threshold: 40, // px
            words: 4,
            label_words: 2 // should be <= words
        },
        list: {
            spark: { // same form as topic_view plot parameters below
                w: 70,
                h: 20,
                m: {
                    left: 2,
                    right: 2,
                    top: 2,
                    bottom: 2
                },
                time: {
                    bar: {
                        unit: "day",
                        w: 300
                    }
                }
            }
        }
    },
    topic_view: {
        words: 50,
        docs: 20,
        w: 400, // minimum in px
        aspect: 3,
        m: {
            left: 40,
            right: 20,
            top: 20,
            bottom: 20
        },
        time: { // conditional plot x-axis settings: time variable
            bar: { // width of bars
                unit: "day", // unit is used as d3.time[unit].utc
                w: 90
            },
            ticks: {
                unit: "year",
                n: 10
            }
        },
        continuous: { // continuous variable: step is calculated automatically
            bar: {
                w: 0.25, // proportion: how much x-axis bar takes up
            },
            ticks: 10
        },
        ordinal: { // categorical variable: step is calculated automatically
            bar: {
                w: 0.25 // proportion
            },
            ticks: 10
        },
        ticks_y: 10, // y axis ticks
        tx_duration: 1000 // animated transition time in ms (where applicable)
    },
    word_view: {
        n_min: 10, // words per topic
        topic_label_padding: 8, // pt
        topic_label_leading: 14, // pt
        row_height: 80, // pt
        svg_rows: 10, // * row_height gives min. height for svg element
        w: 700, // px: minimum width
        m: {
            left: 100,
            right: 40,
            top: 20,
            bottom: 0
        }
    },
    bib: {
        // default if no author delimiter supplied, but note that
        // 2014 JSTOR metadata format uses ", " instead
        author_delimiter: "\t",
        // "et al" is better for real bibliography, but it's
        // actually worth being able to search all the multiple authors
        et_al: Infinity,
        anon: "[Anon]",
    },
    bib_view: {
        window_lines: 100,
        major: "year",
        minor: "authortitle",
        dir: "up"
    },
    tooltip: {              // tooltip div parameters
        offset: {
            x: 10,          // px
            y: 0
        }
    },
    percent_format: d3.format(".1%"),
    resize_refresh_delay: 100, // ms
    hidden_topics: [],      // list of 1-based topic numbers to suppress
    show_hidden_topics: false,
    annotes: [],            // list of CSS classes annotating the current view
    update: function (x) {
        return utils.deep_replace(this, x);
    }
};

<|endoftext|>


<commit_before>  'use strict';

  var EventEmitter = require('./events').EventEmitter;
  var Parser = require('./parser').Parser;
  var compile = require('./compiler').compile;
  var io = require('./platform/io');
  var getPluralRule = require('./plurals').getPluralRule;

  function Context(id) {

    this.id = id;
    this.resLinks = [];
    this.isBuildtime = false;

    this.registerLocales = registerLocales;
    this.requestLocales = requestLocales;

    this.get = get;
    this.getEntity = getEntity;
    this.getEntitySource = getEntitySource;
    this.getLocale = getLocale;
    this.ready = ready;
    this.once = once;

    this.addEventListener = addEventListener;
    this.removeEventListener = removeEventListener;

    Object.defineProperty(this, 'supportedLocales', {
      get: function() { return _fallbackChain.slice(); },
      enumerable: true
    });

    // registered and available languages
    var _default = 'i-default';
    var _registered = [_default];
    var _requested = [];
    var _fallbackChain = [];
    // Locale objects corresponding to the registered languages
    var _locales = {};

    var _isReady = false;
    var _isFrozen = false;

    Object.defineProperty(this, 'isReady', {
      get: function() { return _isReady; },
      enumerable: true
    });

    var _emitter = new EventEmitter();
    this._parser = new Parser();

    this._parser.addEventListener('error', error);

    var self = this;

    function getEntitySource(id) {
      if (!_isReady) {
        throw new ContextError('Context not ready');
      }
      var cur = 0;
      var loc;
      var locale;
      while (loc = _fallbackChain[cur]) {
        locale = this.getLocale(loc);
        if (!locale.isReady) {
          // build without callback, synchronously
          locale.build(null);
        }
        if (locale.ast && locale.ast.hasOwnProperty(id)) {
          return locale.ast[id];
        }
        warn(new TranslationError('Not found', id, _fallbackChain, locale));
        cur++;
      }
      return '';
    }

    function ready(callback) {
      if (_isReady) {
        setTimeout(callback);
      }
      addEventListener('ready', callback);
    }

    function once(callback) {
      if (_isReady) {
        setTimeout(callback);
      }
      var callAndRemove = function callAndRemove() {
        removeEventListener('ready', callAndRemove);
        callback();
      };
      addEventListener('ready', callAndRemove);
    }

    function getWithFallback(id) {
      if (!_isReady) {
        throw new Error('Context not ready');
      }
      var cur = 0;
      var loc;
      var locale;
      while (loc = _fallbackChain[cur]) {
        locale = self.getLocale(loc);
        if (!locale.isReady) {
          // build without callback, synchronously
          locale.build(null);
        }
        var entry = locale.getEntry(id);
        if (entry === undefined) {
          cur++;
          warn(new TranslationError('Not found', id, _fallbackChain, locale));
          continue;
        }
        return entry;
      }
      error(new TranslationError('Unable to get translation', id,
            _fallbackChain));
      return null;
    }

    function get(id, ctxdata) {
      var entry = getWithFallback(id);
      if (entry === null) {
        return null;
      }
      if (typeof entry === 'string') {
        return entry;
      }
      return entry.getString(ctxdata);
    }

    function getEntity(id, ctxdata) {
      var entry = getWithFallback(id);
      if (entry === null) {
        return null;
      }
      if (typeof entry === 'string') {
        return {
          value: entry,
          attributes: {}
        };
      }
      return entry.get(ctxdata);
    }

    function add(text, locale) {
      var res = new Resource(null, _parser);
      res.source = text;
      locale.resources.push(res);
    }

    function registerLocales(defaultLocale, availableLocales) {
      if (_isFrozen) {
        throw new ContextError('Context is frozen');
      }

      if (defaultLocale === undefined) {
        return;
      }

      _default = defaultLocale;
      _registered = [];

      if (!availableLocales) {
        availableLocales = [];
      }
      availableLocales.push(defaultLocale);

      // uniquify `available` into `_registered`
      availableLocales.forEach(function l10n_ctx_addlocale(locale) {
        if (typeof locale !== 'string') {
          throw new ContextError('Language codes must be strings');
        }
        if (_registered.indexOf(locale) === -1) {
          _registered.push(locale);
        }
      });
    }

    function negotiate(available, requested, defaultLocale) {
      if (available.indexOf(requested[0]) === -1 ||
          requested[0] === defaultLocale) {
        return [defaultLocale];
      } else {
        return [requested[0], defaultLocale];
      }
    }

    function getLocale(code) {
      if (_locales[code]) {
        return _locales[code];
      }

      var locale = new Locale(code, this);
      _locales[code] = locale;
      return _locales[code];
    }

    function requestLocales() {
      if (_isFrozen && !_isReady) {
        throw new ContextError('Context not ready');
      }

      if (this.resLinks.length == 0) {
        warn(new ContextError('Context has no resources; not freezing'));
        return;
      }

      _isFrozen = true;
      _requested = Array.prototype.slice.call(arguments);

      if (_requested.length) {
        _requested.forEach(function l10n_throwError(locale) {
          if (typeof locale !== 'string') {
            throw new ContextError('Language codes must be strings');
          }
        });
      }

      var fallbackChain = negotiate(_registered, _requested, _default);
      // if the negotiator returned something, freeze synchronously
      if (fallbackChain) {
        freeze.call(this, fallbackChain);
      }
    }

    function freeze(fallbackChain) {
      _fallbackChain = fallbackChain;
      var locale = this.getLocale(_fallbackChain[0]);
      if (locale.isReady) {
        setReady();
      } else {
        locale.build(setReady);
      }
    }

    function setReady() {
      _isReady = true;
      _emitter.emit('ready');
    }

    function addEventListener(type, listener) {
      _emitter.addEventListener(type, listener);
    }

    function removeEventListener(type, listener) {
      _emitter.removeEventListener(type, listener);
    }

    function warn(e) {
      _emitter.emit('warning', e);
      return e;
    }

    function error(e) {
      _emitter.emit('error', e);
      return e;
    }
  }

  Context.Error = ContextError;
  Context.TranslationError = TranslationError;

  function ContextError(message) {
    this.name = 'ContextError';
    this.message = message;
  }
  ContextError.prototype = Object.create(Error.prototype);
  ContextError.prototype.constructor = ContextError;

  function TranslationError(message, id, supported, locale) {
    this.name = 'TranslationError';
    this.entity = id;
    this.supportedLocales = supported.slice();
    if (locale) {
      this.locale = locale.id;
      this.message = '[' + this.locale + '] ' + id + ': ' + message + ';';
    } else {
      this.message = id + ': ' + message + '; tried ' + supported.join(', ');
    }
  }
  TranslationError.prototype = Object.create(ContextError.prototype);
  TranslationError.prototype.constructor = TranslationError;

<commit_msg>Fix get* soon after a locale change (bug 942183)<commit_after>  'use strict';

  var EventEmitter = require('./events').EventEmitter;
  var Parser = require('./parser').Parser;
  var compile = require('./compiler').compile;
  var io = require('./platform/io');
  var getPluralRule = require('./plurals').getPluralRule;

  function Context(id) {

    this.id = id;
    this.resLinks = [];
    this.isBuildtime = false;

    this.registerLocales = registerLocales;
    this.requestLocales = requestLocales;

    this.get = get;
    this.getEntity = getEntity;
    this.getEntitySource = getEntitySource;
    this.getLocale = getLocale;
    this.ready = ready;
    this.once = once;

    this.addEventListener = addEventListener;
    this.removeEventListener = removeEventListener;

    Object.defineProperty(this, 'supportedLocales', {
      get: function() { return _fallbackChain.slice(); },
      enumerable: true
    });

    // registered and available languages
    var _default = 'i-default';
    var _registered = [_default];
    var _requested = [];
    var _fallbackChain = [];
    // Locale objects corresponding to the registered languages
    var _locales = {};

    var _isReady = false;
    var _isFrozen = false;

    Object.defineProperty(this, 'isReady', {
      get: function() { return _isReady; },
      enumerable: true
    });

    var _emitter = new EventEmitter();
    this._parser = new Parser();

    this._parser.addEventListener('error', error);

    var self = this;

    function getEntitySource(id) {
      if (!_isReady) {
        throw new ContextError('Context not ready');
      }
      var cur = 0;
      var loc;
      var locale;
      while (loc = _fallbackChain[cur]) {
        locale = this.getLocale(loc);
        if (!locale.isReady) {
          // build without callback, synchronously
          locale.build(null);
        }
        if (locale.ast && locale.ast.hasOwnProperty(id)) {
          return locale.ast[id];
        }
        warn(new TranslationError('Not found', id, _fallbackChain, locale));
        cur++;
      }
      return '';
    }

    function ready(callback) {
      if (_isReady) {
        setTimeout(callback);
      }
      addEventListener('ready', callback);
    }

    function once(callback) {
      if (_isReady) {
        setTimeout(callback);
      }
      var callAndRemove = function callAndRemove() {
        removeEventListener('ready', callAndRemove);
        callback();
      };
      addEventListener('ready', callAndRemove);
    }

    function getWithFallback(id) {
      if (!_isReady) {
        throw new Error('Context not ready');
      }
      var cur = 0;
      var loc;
      var locale;
      while (loc = _fallbackChain[cur]) {
        locale = self.getLocale(loc);
        if (!locale.isReady) {
          // build without callback, synchronously
          locale.build(null);
        }
        var entry = locale.getEntry(id);
        if (entry === undefined) {
          cur++;
          warn(new TranslationError('Not found', id, _fallbackChain, locale));
          continue;
        }
        return entry;
      }
      error(new TranslationError('Unable to get translation', id,
            _fallbackChain));
      return null;
    }

    function get(id, ctxdata) {
      var entry = getWithFallback(id);
      if (entry === null) {
        return null;
      }
      if (typeof entry === 'string') {
        return entry;
      }
      return entry.getString(ctxdata);
    }

    function getEntity(id, ctxdata) {
      var entry = getWithFallback(id);
      if (entry === null) {
        return null;
      }
      if (typeof entry === 'string') {
        return {
          value: entry,
          attributes: {}
        };
      }
      return entry.get(ctxdata);
    }

    function add(text, locale) {
      var res = new Resource(null, _parser);
      res.source = text;
      locale.resources.push(res);
    }

    function registerLocales(defaultLocale, availableLocales) {
      if (_isFrozen) {
        throw new ContextError('Context is frozen');
      }

      if (defaultLocale === undefined) {
        return;
      }

      _default = defaultLocale;
      _registered = [];

      if (!availableLocales) {
        availableLocales = [];
      }
      availableLocales.push(defaultLocale);

      // uniquify `available` into `_registered`
      availableLocales.forEach(function l10n_ctx_addlocale(locale) {
        if (typeof locale !== 'string') {
          throw new ContextError('Language codes must be strings');
        }
        if (_registered.indexOf(locale) === -1) {
          _registered.push(locale);
        }
      });
    }

    function negotiate(available, requested, defaultLocale) {
      if (available.indexOf(requested[0]) === -1 ||
          requested[0] === defaultLocale) {
        return [defaultLocale];
      } else {
        return [requested[0], defaultLocale];
      }
    }

    function getLocale(code) {
      if (_locales[code]) {
        return _locales[code];
      }

      var locale = new Locale(code, this);
      _locales[code] = locale;
      return _locales[code];
    }

    function requestLocales() {
      if (_isFrozen && !_isReady) {
        throw new ContextError('Context not ready');
      }

      if (this.resLinks.length == 0) {
        warn(new ContextError('Context has no resources; not freezing'));
        return;
      }

      _isFrozen = true;
      _requested = Array.prototype.slice.call(arguments);

      if (_requested.length) {
        _requested.forEach(function l10n_throwError(locale) {
          if (typeof locale !== 'string') {
            throw new ContextError('Language codes must be strings');
          }
        });
      }

      var fallbackChain = negotiate(_registered, _requested, _default);
      // if the negotiator returned something, freeze synchronously
      if (fallbackChain) {
        freeze.call(this, fallbackChain);
      }
    }

    function freeze(fallbackChain) {
      var locale = this.getLocale(fallbackChain[0]);
      if (locale.isReady) {
        setReady(fallbackChain);
      } else {
        locale.build(setReady.bind(null, fallbackChain));
      }
    }

    function setReady(fallbackChain) {
      _fallbackChain = fallbackChain;
      _isReady = true;
      _emitter.emit('ready');
    }

    function addEventListener(type, listener) {
      _emitter.addEventListener(type, listener);
    }

    function removeEventListener(type, listener) {
      _emitter.removeEventListener(type, listener);
    }

    function warn(e) {
      _emitter.emit('warning', e);
      return e;
    }

    function error(e) {
      _emitter.emit('error', e);
      return e;
    }
  }

  Context.Error = ContextError;
  Context.TranslationError = TranslationError;

  function ContextError(message) {
    this.name = 'ContextError';
    this.message = message;
  }
  ContextError.prototype = Object.create(Error.prototype);
  ContextError.prototype.constructor = ContextError;

  function TranslationError(message, id, supported, locale) {
    this.name = 'TranslationError';
    this.entity = id;
    this.supportedLocales = supported.slice();
    if (locale) {
      this.locale = locale.id;
      this.message = '[' + this.locale + '] ' + id + ': ' + message + ';';
    } else {
      this.message = id + ': ' + message + '; tried ' + supported.join(', ');
    }
  }
  TranslationError.prototype = Object.create(ContextError.prototype);
  TranslationError.prototype.constructor = TranslationError;

<|endoftext|>


<commit_before>/**
 * Copyright (c) 2017-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

// See https://docusaurus.io/docs/site-config for all the possible
// site configuration options.

// List of projects/orgs using your project for the users page.

const siteConfig = {
  title: 'go-echarts', // Title for your website.
  tagline: '🎨 The adorable charts library for Golang',
  url: 'https://go-echarts.github.io/go-echarts/', // Your website URL
  baseUrl: '/', // Base URL for your project */
  // For github.io type URLs, you would set the url and baseUrl like:
  //   url: 'https://facebook.github.io',
  //   baseUrl: '/test-site/',
  cname: 'go-echarts.github.io/go-echarts/',
  // Used for publishing and more
  projectName: 'go-echarts',
  organizationName: 'chenjiandongx',
  // For top-level user or org sites, the organization is still the same.
  // e.g., for the https://JoelMarcey.github.io site, it would be set like...
  //   organizationName: 'JoelMarcey'

  // For no header links in the top nav bar -> headerLinks: [],
  headerLinks: [
    {doc: 'overview', label: 'Docs'},
    {
      href: 'https://www.github.com/chenjiandongx',
      label: 'Author',
    },
    {
      href: 'https://www.github.com/go-echarts/go-echarts',
      label: 'GitHub',
    },
  ],

  /* path to images for header/footer */
  headerIcon: 'img/favicon.ico',
  footerIcon: 'img/favicon.ico',
  favicon: 'img/favicon.ico',

  /* Colors for website */
  colors: {
    primaryColor: '#2E8555',
    secondaryColor: '#205C3B',
  },

  /* Custom fonts for website */
  /*
  fonts: {
    myFont: [
      "Times New Roman",
      "Serif"
    ],
    myOtherFont: [
      "-apple-system",
      "system-ui"
    ]
  },
  */

  // This copyright info is used in /core/Footer.js and blog RSS/Atom feeds.
  copyright: `Copyright © ${new Date().getFullYear()} chenjiandongx`,

  highlight: {
    // Highlight.js theme to use for syntax highlighting in code blocks.
    theme: 'default',
  },

  // Add custom scripts here that would be placed in <script> tags.
  scripts: ['https://buttons.github.io/buttons.js'],

  // On page navigation for the current documentation page.
  onPageNav: 'separate',
  // No .html extensions for paths.
  cleanUrl: true,

  // Open Graph and Twitter card images.
  // ogImage: 'img/docusaurus.png',
  // twitterImage: 'img/docusaurus.png',

  // Show documentation's last contributor's name.
  enableUpdateBy: true,

  // Show documentation's last update time.
  enableUpdateTime: true,

  // You may provide arbitrary config keys to be used as needed by your
  // template. For example, if you need your repo's URL...
  //   repoUrl: 'https://github.com/facebook/test-site',
};

module.exports = siteConfig;
<commit_msg>Fix: base url<commit_after>/**
 * Copyright (c) 2017-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

// See https://docusaurus.io/docs/site-config for all the possible
// site configuration options.

// List of projects/orgs using your project for the users page.

const siteConfig = {
  title: 'go-echarts', // Title for your website.
  tagline: '🎨 The adorable charts library for Golang',
  url: 'https://go-echarts.github.io/go-echarts/', // Your website URL
  baseUrl: '/go-echarts/', // Base URL for your project */
  // For github.io type URLs, you would set the url and baseUrl like:
  //   url: 'https://facebook.github.io',
  //   baseUrl: '/test-site/',
  cname: 'go-echarts.github.io/go-echarts/',
  // Used for publishing and more
  projectName: 'go-echarts',
  organizationName: 'go-echarts',
  // For top-level user or org sites, the organization is still the same.
  // e.g., for the https://JoelMarcey.github.io site, it would be set like...
  //   organizationName: 'JoelMarcey'

  // For no header links in the top nav bar -> headerLinks: [],
  headerLinks: [
    {doc: 'overview', label: 'Docs'},
    {
      href: 'https://www.github.com/chenjiandongx',
      label: 'Author',
    },
    {
      href: 'https://www.github.com/go-echarts/go-echarts',
      label: 'GitHub',
    },
  ],

  /* path to images for header/footer */
  headerIcon: 'img/favicon.ico',
  footerIcon: 'img/favicon.ico',
  favicon: 'img/favicon.ico',

  /* Colors for website */
  colors: {
    primaryColor: '#2E8555',
    secondaryColor: '#205C3B',
  },

  /* Custom fonts for website */
  /*
  fonts: {
    myFont: [
      "Times New Roman",
      "Serif"
    ],
    myOtherFont: [
      "-apple-system",
      "system-ui"
    ]
  },
  */

  // This copyright info is used in /core/Footer.js and blog RSS/Atom feeds.
  copyright: `Copyright © ${new Date().getFullYear()} chenjiandongx`,

  highlight: {
    // Highlight.js theme to use for syntax highlighting in code blocks.
    theme: 'default',
  },

  // Add custom scripts here that would be placed in <script> tags.
  scripts: ['https://buttons.github.io/buttons.js'],

  // On page navigation for the current documentation page.
  onPageNav: 'separate',
  // No .html extensions for paths.
  cleanUrl: true,

  // Open Graph and Twitter card images.
  // ogImage: 'img/docusaurus.png',
  // twitterImage: 'img/docusaurus.png',

  // Show documentation's last contributor's name.
  enableUpdateBy: true,

  // Show documentation's last update time.
  enableUpdateTime: true,

  // You may provide arbitrary config keys to be used as needed by your
  // template. For example, if you need your repo's URL...
  //   repoUrl: 'https://github.com/facebook/test-site',
};

module.exports = siteConfig;
<|endoftext|>