GData Doc Picker

From Chickenfoot Script Repository

include('google-docs-ui.js');
go('about:blank');

goog.require('goog.dom');
goog.require('goog.dom.classes');
goog.require('goog.dom.selection');
goog.require('goog.events.KeyCodes');
goog.require('goog.events.KeyHandler');
goog.require('goog.events.KeyHandler.EventType');
goog.require('goog.string');
goog.require('goog.style');

var dom = new goog.dom.DomHelper(document);

/**
 * Finds all elements with the "editable" class and sets content-editable to
 * true. Adds a key handler to these editable elements and inserts CSS to
 * style the document appropriately.
 * @param {function} saveFn
 * @param {Document} doc
 */
function makeDivsContentEditable(saveFn, doc) {
  var divs = doc.querySelectorAll('.editable');
  for (var i = 0; i < divs.length; ++i) {
    var div = divs[i];
    div.contentEditable = true;
    var html = div.innerHTML;
    html = goog.string.trim(html);
    div.innerHTML = html;
  }
  var keyHandlerEl = doc.body;
  var keyHandler = new goog.events.KeyHandler(keyHandlerEl);
  goog.events.listen(keyHandler,
                     goog.events.KeyHandler.EventType.KEY,
                     goog.partial(onKeyEvent, saveFn));
  var stylesString = 'body { font-family: Arial; font-size: 13px }' +
      '.editable { padding-bottom: 8px; outline: none }' +
      '.source-code { color: green; font-family: Courier; white-space: pre}';
  goog.style.installStyles(stylesString, doc.body);
}


/**
 * @param {Element} contentEditableDiv
 * @return {number}
 */
function getCursorPosition(contentEditableDiv) {
  var dom = goog.dom.getDomHelper(contentEditableDiv);
  var win = dom.getWindow();
  var selection = win.getSelection();
  // This assumes the selection is always inside a text node and that the
  // contentEditableDiv's only child is that text node.
  return selection.anchorOffset;
}


/**
 * Handles a key event in the editor.
 * @param {function} saveFn
 * @param {goog.events.KeyEvent} e
 */
function onKeyEvent(saveFn, e) {
  var keyCode = e.keyCode;
  var contentEditableDiv = e.target;
  var cursorPosition = getCursorPosition(contentEditableDiv);
  output('keyCode: ' + e.keyCode + '; cursorPos: ' + cursorPosition);
  
  var textNode = contentEditableDiv.firstChild;
  if (textNode.nodeType != goog.dom.NodeType.TEXT) {
    output('Not a text node: ' + textNode);
    return;
  }

  if (keyCode == goog.events.KeyCodes.ENTER) {
    // ctrl-enter toggles between source-code and text.
    if (e.ctrlKey) {
      e.preventDefault();
      goog.dom.classes.toggle(contentEditableDiv, 'source-code');
      return;
    }

    // enter at the end of the line creates a new paragraph.
    if (textNode.nodeValue.length == cursorPosition) {
      output('NEW LINE!');
      e.preventDefault();
      var dom = goog.dom.getDomHelper(contentEditableDiv);
      var newDiv = dom.createElement('div');
      newDiv.contentEditable = true;
      newDiv.className = 'editable';
      newDiv.innerHTML = ' ';
      goog.dom.insertSiblingAfter(newDiv, contentEditableDiv);
      newDiv.focus();
    }
  } else if (keyCode == goog.events.KeyCodes.UP) {
    // TODO: make it possible to cursor up and down.
  } else if (keyCode == goog.events.KeyCodes.DOWN) {
  } else if (keyCode == goog.events.KeyCodes.S && e.ctrlKey) {
    // ctrl-S saves the file.
    saveFn();
  }
}

document.body.innerHTML = '<div id="picker"></div>' +
    '<div style="width: 600px; ' +
        'position: absolute; ' +
        'top: 150px; ' +
        'left: 25px;">' +
      '<div id="toolbar" style="height: 25px">' +
        '<div id="status" style="float: right"></div>' +
        '<button id="save">Save</button>' +
        ' <span id="title" style="font-weight: bold; font-family: Arial;"></span>' +
      '</div>' +
      '<div id="viewer" style="height: 800px; border: 1px solid #ccc; padding: 4px"></div>' +
    '</div>';
var viewerEl = dom.$('viewer');
var viewer = new gdata.docs.ui.DocViewer(viewerEl, { stripHeadHtml: true });

var pickerEl = dom.$('picker');
new gdata.docs.ui.DocPicker(pickerEl, viewer);

function onSave(serverResponse) {
  output(serverResponse);
  dom.$('status').innerHTML = 'Saved at: ' + (new Date());
}

function onFailedSave(errorMessage) {
  output(serverResponse);
  dom.$('status').innerHTML = 'Error while saving: ' + errorMessage;
}

function save() {
  dom.$('status').innerHTML = 'Saving...';
  viewer.save(onSave, onFailedSave);  
}

function onSaveClicked(e) {
  save();
};

var postLoadProcessor = goog.partial(makeDivsContentEditable, save);
viewer.setPostLoadProcessor(postLoadProcessor);

goog.events.listen(dom.$('save'),
                   goog.events.EventType.CLICK,
                   onSaveClicked);

goog.events.listen(viewer,
                   gdata.docs.ui.DocViewer.EventType.DOCUMENT_LOADED,
                   function(e) {
                       dom.$('title').innerHTML =
                           goog.string.htmlEscape(viewer.getEntry().getTitle());
                   });