<commit_before>'use babel';

// used variables
var SubAtom, disposables, onTouchSwipeLeft, onTouchSwipeRight, initialized, visible, treeView, treeViewEl, focusedElement, hoverEventsEnabled, currentAnimation;

initialized = false;

// some generic functions
function logError(error) {
  console.error(error.message)
}

function getConfig(key) {
  return atom.config.get(`autohide-tree-view.${key}`);
}

function setConfig(key, value) {
  atom.config.set(`autohide-tree-view.${key}`, value);
}

function toggleConfig(key) {
  setConfig(key, !getConfig(key));
}

// private API

function init() {
  if(initialized) return;
  disposables = new SubAtom();
  // wait until the tree view package is activated
  Promise.all([
    atom.packages.activatePackage('tree-view'),
    atom.packages.isPackageLoaded('atom-touch-events') && atom.packages.activatePackage('atom-touch-events')
  ]).then(function([treeViewPkg, atomTouchEventsPkg]) {
    registerTreeView(treeViewPkg);
    handleEvents(!!atomTouchEventsPkg);
    // start with pushEditor = true, we'll change it back later
    return update(true);
  }).then(function() {
    return update();
  }).then(function() {
    initialized = true;
  }).catch(logError);
}

function deinit() {
  if(!initialized) return;
  initialized = false;
  disposables.dispose();
  // the stylesheet will be removed before the animation is finished
  // making it look ugly... set minWidth on the element to prevent this
  treeViewEl.style.minWidth = '1px';
  // update with pushEditor = true for a nicer animation
  update(true).then(function() {
    // show the tree view
    return show(0);
  }).then(function() {
    // finally dispose of the tree view and reset all used variables
    resetTreeView();
    [disposables, treeView, treeViewEl, visible, focusedElement, hoverEventsEnabled, currentAnimation] = [];
  }).catch(logError);
}

// keep references to the tree view model and element
function registerTreeView(treeViewPkg) {
  treeView = treeViewPkg.mainModule.createView();
  treeViewEl = treeView.element;
  treeViewEl.classList.add('autohide');
}

// reset the styles etc. on the tree view
function resetTreeView() {
  var panelView;
  treeViewEl.classList.remove('autohide');
  treeViewEl.style.position = '';
  treeViewEl.style.minWidth = '';
  treeView.scroller[0].style.display = '';
  panelView = atom.views.getView(treeView.panel);
  if(panelView) {
    panelView.style.width = '';
  }
}

function handleEvents(touchEvents) {
  // touch events
  if(touchEvents) {
    disposables.add(onTouchSwipeLeft(swipeLeftStart, swipeLeftEnd));
    disposables.add(onTouchSwipeRight(swipeRightStart, swipeRightEnd));
  }

  // changes to these settings should trigger an update
  disposables.add(atom.config.onDidChange('autohide-tree-view.pushEditor', update));
  disposables.add(atom.config.onDidChange('autonhide-tree-view.hiddenWidth', update));
  disposables.add(atom.config.onDidChange('tree-view.showOnRightSide', update));
  disposables.add(atom.config.onDidChange('tree-view.hideIgnoredNames', update));
  disposables.add(atom.config.onDidChange('tree-view.hideVcsIgnoredFiles', update));
  disposables.add(atom.config.onDidChange('core.ignoredNames', update));

  // changes to the showOn config should enable hover events (the enableHoverEvents
  // function checks if it actually *should* enable hover events)
  disposables.add(atom.config.onDidChange('autohide-tree-view.showOn', enableHoverEvents));

  // add listeners for mouse events
  // show the tree view when it is hovered
  disposables.add(treeViewEl, 'mouseenter', mouseenter);
  disposables.add(treeViewEl, 'mouseleave', mouseleave);
  // disable the tree view from showing during text selection
  disposables.add('atom-workspace', 'mousedown', 'atom-text-editor', disableHoverEvents);
  disposables.add('atom-workspace', 'mouseup', 'atom-text-editor', enableHoverEvents);
  // toggle the tree view if it is clicked
  disposables.add(treeViewEl, 'click', click);
  disposables.add(treeView.list, 'blur', blur);

  // resize the tree view when project.paths changes
  disposables.add(atom.project.onDidChangePaths(resize));

  // add command listeners
  disposables.add(atom.commands.add('atom-workspace', {
    // own commands
    'autohide-tree-view:toggle-push-editor': function() {
      toggleConfig('pushEditor');
    },
    // core commands
    'tool-panel:unfocus': function() {
      hide(0);
    },
    // tree-view commands
    'tree-view:show': function(event) {
      event.stopImmediatePropagation();
      show(0, true);
    },
    'tree-view:hide': function(event) {
      event.stopImmediatePropagation();
      hide(0);
    },
    'tree-view:toggle': function(event) {
      event.stopImmediatePropagation();
      toggle();
    },
    'tree-view:reveal-active-file': function() {
      show(0, true);
    },
    'tree-view:toggle-focus': toggle,
    'tree-view:remove': resize,
    'tree-view:paste': resize,
    'tree-view:expand-directory': resize,
    'tree-view:recursive-expand-directory': resize,
    'tree-view:collapse-directory': resize,
    'tree-view:recursive-collapse-directory': resize
  }));

  // resize the tree view when opening/closing a directory
  disposables.add(treeViewEl, 'click', '.entry.directory', function(event) {
    event.stopPropagation();
    resize();
  });

  // hide the tree view when a file is opened by a command
  for(var direction of ['', '-right', '-left', '-up', '-down']) {
    disposables.add(atom.commands.add('atom-workspace', `tree-view:open-selected-entry${direction}`, function() {
      hide(0);
    }));
  }

  for(var i of [1, 2, 3, 4, 5, 6, 7, 8, 9]) {
    disposables.add(atom.commands.add('atom-workspace', `tree-view:open-selected-entry-in-pane-${i}`, function() {
      hide(0);
    }));
  }

  // these commands create a dialog that should keep focus
  // when the tree view hides
  for(var command of ['add-file', 'add-folder', 'duplicate', 'rename', 'move']) {
    disposables.add(atom.commands.add('atom-workspace', `tree-view:${command}`, clearFocusedElement));
  }
}

// updates styling on the .tree-view-resizer and the panel (container)
function update(pushEditor) {
  if(typeof pushEditor !== 'boolean') pushEditor = getConfig('pushEditor');
  return Promise.resolve().then(function() {
    var panelView;
    treeViewEl.style.position = pushEditor ? '' : 'absolute';
    if(panelView = atom.views.getView(treeView.panel)) {
      panelView.style.width = pushEditor ? '' : `${getConfig('hiddenWidth')}px`;
    }
  }).then(resize).catch(logError);
}

// shows the tree view
function show(delay = getConfig('showDelay'), shouldDisableHoverEvents = false) {
  visible = true;
  // disable hover events on the tree view when this
  // show is not triggered by a hover event
  if(shouldDisableHoverEvents) disableHoverEvents();
  // keep a reference to the currently focused element
  // so we can restore focus when the tree view will hide
  if(!focusedElement) storeFocusedElement();
  // show the tree view content
  treeView.scroller[0].style.display = '';
  return animate(treeView.list[0].clientWidth, delay).then(function(finished) {
    // focus the tree view if the animation
    // finished (i.e. wasn't cancelled)
    if(finished) treeView.focus();
  });
}

// hides the tree view
function hide(delay = getConfig('hideDelay')) {
  visible = false;
  // enable hover events
  enableHoverEvents();
  // focus the element that had focus when show() was triggered
  restoreFocus();
  return animate(getConfig('hiddenWidth'), delay).then(function(finished) {
    // hide the tree view content
    if(finished) treeView.scroller[0].style.display = 'none';
  });
}

// toggles the tree view
function toggle() {
  return visible ? hide(0) : show(0, true);
}

// resizes the tree view when its content width might change
function resize() {
  return Promise.resolve().then(function() {
    return visible ? show(0) : hide(0);
  });
}

// cache the element that currently has focus
function storeFocusedElement() {
  focusedElement = document.activeElement;
}

// clear the reference to the focusedElement. useful
// when we want to invalidate the next restoreFocus
function clearFocusedElement() {
  focusedElement = null;
}

// recovers focus on focusedElement
function restoreFocus() {
  if(!focusedElement) return;
  if(typeof focusedElement.focused === 'function') focusedElement.focused();
  else if(typeof focusedElement.focus === 'function') focusedElement.focus();
  clearFocusedElement();
}

// enable hover events on the tree view
// (but only if showOn is 'hover' or 'hover + click')
function enableHoverEvents() {
  hoverEventsEnabled = !!getConfig('showOn').match('hover');
}

// disable hover events on the tree view
function disableHoverEvents() {
  hoverEventsEnabled = false;
}

// fired when the mouse enters the tree view
function mouseenter() {
  if(hoverEventsEnabled) show();
}

// fired when the mouse leaves the tree view
function mouseleave() {
  if(hoverEventsEnabled) hide();
}

// fired when the tree view is clicked
function click() {
  var showOn = getConfig('showOn');
  if(showOn.match('click')) toggle();
}

// fired when the tree view is blurred
function blur() {
  if(!getConfig('showOn').match(/(click|touch)/)) return;
  // clear the focused element so the element the user
  // clicked will be focused instead
  clearFocusedElement();
  hide(0);
}

function isTreeView(target) {
  while(target != treeViewEl.parentNode && target != document.body) {
    target = target.parentNode;
  }
  return target == treeViewEl.parentNode;
}

function swipeLeftStart({source, deltaX}) {
  if(!getConfig('showOn').match('touch') || !isTreeView(source)) return;
  treeView.scroller[0].style.display = 'block'
  if(atom.config.get('tree-view.showOnRightSide')) {
    swipeShow(-deltaX);
  } else {
    swipeHide(deltaX);
  }
}

function swipeLeftEnd({source}) {
  if(!getConfig('showOn').match('touch') || !isTreeView(source)) return;
  if(atom.config.get('tree-view.showOnRightSide')) {
    show(0);
  } else {
    hide(0);
  }
}

function swipeRightStart({source, deltaX}) {
  if(!getConfig('showOn').match('touch') || !isTreeView(source)) return;
  treeView.scroller[0].style.display = 'block'
  if(atom.config.get('tree-view.showOnRightSide')) {
    swipeHide(-deltaX);
  } else {
    swipeShow(deltaX);
  }
}

function swipeRightEnd({source, deltaX}) {
  if(!getConfig('showOn').match('touch') || !isTreeView(source)) return;
  if(atom.config.get('tree-view.showOnRightSide')) {
    hide(0);
  } else {
    show(0);
  }
}

function swipeShow(deltaX) {
  newWidth = Math.min(treeView.list[0].clientWidth, treeViewEl.clientWidth + deltaX);
  requestAnimationFrame(function resizer() {
    treeViewEl.style.width = `${newWidth}px`;
  });
}

function swipeHide(deltaX) {
  newWidth = Math.max(getConfig('hiddenWidth'), treeViewEl.clientWidth + deltaX);
  requestAnimationFrame(function resizer() {
    treeViewEl.style.width = `${newWidth}px`;
  });
}

// the animation function resolves with 'true' if the
// animation finished, with 'false' if cancelled
function animate(targetWidth, delay) {
  var initialWidth, animationSpeed, duration;
  // get the initial width of the element
  initialWidth = treeViewEl.clientWidth;
  // set animationSpeed to Infinity if it equals 0
  animationSpeed = getConfig('animationSpeed') || Infinity;
  // calculate the animation duration if animationSpeed
  // equals 0 divide by Infinity for a duration of 0
  duration = Math.abs(targetWidth - initialWidth) / animationSpeed;

  // cancel any current animation
  if(currentAnimation && currentAnimation.playState !== 'finished') {
    currentAnimation.cancel();
    delay = 0; // immediately trigger the next animation
  }

  return new Promise(function(resolve) {
    var animation;
    // check if animation necessary
    if(duration === 0) return void setTimeout(function() {
      treeViewEl.style.width = `${targetWidth}px`;
      resolve(true);
    }, delay);

    // cache the current animationPlayer so we can
    // cancel it as soon as another animation begins
    animation = currentAnimation = treeViewEl.animate([
      {width: initialWidth}, {width: targetWidth}
    ], {duration, delay});

    animation.addEventListener('finish', function finish() {
      animation.removeEventListener('finish', finish);
      // if cancelled, resolve with false
      if(animation.playState !== 'finished') return resolve(false);
      // prevent tree view from resetting its width to initialWidth
      treeViewEl.style.width = `${targetWidth}px`;
      // reset the currentAnimation reference
      currentAnimation = null;
      resolve(true);
    });
  }).catch(logError);
}

// public API

module.exports = {
  config: {
    showOn: {
      description: 'The type of event that triggers the tree view to show or hide. The touch events require atom-touch-events (https://atom.io/packages/atom-touch-events) to be installed.',
      type: 'string',
      default: 'hover',
      enum: [
        'hover',
        'click',
        'touch',
        'hover + click',
        'hover + touch',
        'click + touch',
        'hover + click + touch',
        'none'
      ],
      order: 0
    },
    showDelay: {
      description: 'The delay in milliseconds before the tree view will show. Only applies to hover events.',
      type: 'integer',
      default: 200,
      minimum: 0,
      order: 1
    },
    hideDelay: {
      description: 'The delay in milliseconds before the tree view will hide. Only applies to hover events.',
      type: 'integer',
      default: 200,
      minimum: 0,
      order: 2
    },
    hiddenWidth: {
      description: 'The width in pixels of the tree view when it is hidden.',
      type: 'integer',
      default: 5,
      minimum: 1,
      order: 3
    },
    animationSpeed: {
      description: 'The speed in 1000 pixels per second of the animation. Set to 0 to disable the animation.',
      type: 'number',
      default: 1,
      minimum: 0,
      order: 4
    },
    pushEditor: {
      description: 'Push the edge of the editor around to keep the entire editor contents visible.',
      type: 'boolean',
      default: false,
      order: 5
    }
  },

  activate: function activate() {
    if(!SubAtom) SubAtom = require('sub-atom');
    init();

    // these commands are handled here, because we don't want to dispose them on deinit()
    this.commands = atom.commands.add('atom-workspace', {
      'autohide-tree-view:enable': init,
      'autohide-tree-view:disable': deinit
    });
  },

  deactivate: function deactivate() {
    this.commands.dispose();
    deinit();
  },

  // provide service for other packages to
  provideService: function provideService() {
    return {
      show: function(delay, shouldDisableHoverEvents) {
        return show(delay, shouldDisableHoverEvents);
      },
      hide: function(delay) {
        return hide(delay);
      },
      enable: function() {
        return init();
      },
      disable: function() {
        return deinit();
      }
    }
  },

  consumeTouchSwipeLeftService: function consumeTouchSwipeLeftService(onDidTouchSwipeLeft) {
    onTouchSwipeLeft = onDidTouchSwipeLeft;
  },

  consumeTouchSwipeRightService: function consumeTouchSwipeRightService(onDidTouchSwipeRight) {
    onTouchSwipeRight = onDidTouchSwipeRight;
  }
};
<commit_msg>fix some issues<commit_after>'use babel';

// used variables
var SubAtom, disposables, onTouchSwipeLeft, onTouchSwipeRight, initialized, visible, treeView, treeViewEl, focusedElement, hoverEventsEnabled, currentAnimation;

initialized = false;

// some generic functions
function logError(error) {
  console.error(error.message)
}

function getConfig(key) {
  return atom.config.get(`autohide-tree-view.${key}`);
}

function setConfig(key, value) {
  atom.config.set(`autohide-tree-view.${key}`, value);
}

function toggleConfig(key) {
  setConfig(key, !getConfig(key));
}

// private API

function init() {
  if(initialized) return;
  disposables = new SubAtom();
  // wait until the tree view package is activated
  Promise.all([
    atom.packages.activatePackage('tree-view'),
    atom.packages.isPackageLoaded('atom-touch-events') && atom.packages.activatePackage('atom-touch-events')
  ]).then(function([treeViewPkg, atomTouchEventsPkg]) {
    registerTreeView(treeViewPkg);
    handleEvents(!!atomTouchEventsPkg);
    // start with pushEditor = true, we'll change it back later
    return update(true);
  }).then(function() {
    return update();
  }).then(function() {
    initialized = true;
  }).catch(logError);
}

function deinit() {
  if(!initialized) return;
  initialized = false;
  disposables.dispose();
  // the stylesheet will be removed before the animation is finished
  // making it look ugly... set minWidth on the element to prevent this
  treeViewEl.style.minWidth = '1px';
  // update with pushEditor = true for a nicer animation
  update(true).then(function() {
    // show the tree view
    return show(0);
  }).then(function() {
    // finally dispose of the tree view and reset all used variables
    resetTreeView();
    [disposables, treeView, treeViewEl, visible, focusedElement, hoverEventsEnabled, currentAnimation] = [];
  }).catch(logError);
}

// keep references to the tree view model and element
function registerTreeView(treeViewPkg) {
  treeView = treeViewPkg.mainModule.createView();
  treeViewEl = treeView.element;
  treeViewEl.classList.add('autohide');
}

// reset the styles etc. on the tree view
function resetTreeView() {
  var panelView;
  treeViewEl.classList.remove('autohide');
  treeViewEl.style.position = '';
  treeViewEl.style.minWidth = '';
  treeView.scroller[0].style.display = '';
  panelView = atom.views.getView(treeView.panel);
  if(panelView) {
    panelView.style.width = '';
  }
}

function handleEvents(touchEvents) {
  // changes to these settings should trigger an update
  disposables.add(atom.config.onDidChange('autohide-tree-view.pushEditor', update));
  disposables.add(atom.config.onDidChange('autohide-tree-view.hiddenWidth', update));
  disposables.add(atom.config.onDidChange('tree-view.showOnRightSide', update));
  disposables.add(atom.config.onDidChange('tree-view.hideIgnoredNames', update));
  disposables.add(atom.config.onDidChange('tree-view.hideVcsIgnoredFiles', update));
  disposables.add(atom.config.onDidChange('core.ignoredNames', update));

  // changes to the showOn config should enable hover events (the enableHoverEvents
  // function checks if it actually *should* enable hover events)
  disposables.add(atom.config.onDidChange('autohide-tree-view.showOn', enableHoverEvents));

  // add listeners for mouse events
  // show the tree view when it is hovered
  disposables.add(treeViewEl, 'mouseenter', mouseenter);
  disposables.add(treeViewEl, 'mouseleave', mouseleave);
  // disable the tree view from showing during text selection
  disposables.add('atom-workspace', 'mousedown', 'atom-text-editor', disableHoverEvents);
  disposables.add('atom-workspace', 'mouseup', 'atom-text-editor', enableHoverEvents);
  // toggle the tree view if it is clicked
  disposables.add(treeViewEl, 'click', click);
  disposables.add(treeView.list, 'blur', blur);

  // add support for touch events if the atom-touch-events
  // package is enabled
  if(touchEvents) {
    disposables.add(onTouchSwipeLeft(swipeLeftStart, swipeLeftEnd));
    disposables.add(onTouchSwipeRight(swipeRightStart, swipeRightEnd));
  }

  // resize the tree view when project.paths changes
  disposables.add(atom.project.onDidChangePaths(resize));

  // add command listeners
  disposables.add(atom.commands.add('atom-workspace', {
    // own commands
    'autohide-tree-view:toggle-push-editor': function() {
      toggleConfig('pushEditor');
    },
    // core commands
    'tool-panel:unfocus': function() {
      hide(0);
    },
    // tree-view commands
    'tree-view:show': function(event) {
      event.stopImmediatePropagation();
      show(0, true);
    },
    'tree-view:hide': function(event) {
      event.stopImmediatePropagation();
      hide(0);
    },
    'tree-view:toggle': function(event) {
      event.stopImmediatePropagation();
      toggle();
    },
    'tree-view:reveal-active-file': function() {
      show(0, true);
    },
    'tree-view:toggle-focus': toggle,
    'tree-view:remove': resize,
    'tree-view:paste': resize,
    'tree-view:expand-directory': resize,
    'tree-view:recursive-expand-directory': resize,
    'tree-view:collapse-directory': resize,
    'tree-view:recursive-collapse-directory': resize
  }));

  // resize the tree view when opening/closing a directory
  disposables.add(treeViewEl, 'click', '.entry.directory', function(event) {
    event.stopPropagation();
    resize();
  });

  // hide the tree view when a file is opened by a command
  for(var direction of ['', '-right', '-left', '-up', '-down']) {
    disposables.add(atom.commands.add('atom-workspace', `tree-view:open-selected-entry${direction}`, function() {
      hide(0);
    }));
  }

  for(var i of [1, 2, 3, 4, 5, 6, 7, 8, 9]) {
    disposables.add(atom.commands.add('atom-workspace', `tree-view:open-selected-entry-in-pane-${i}`, function() {
      hide(0);
    }));
  }

  // these commands create a dialog that should keep focus
  // when the tree view hides
  for(var command of ['add-file', 'add-folder', 'duplicate', 'rename', 'move']) {
    disposables.add(atom.commands.add('atom-workspace', `tree-view:${command}`, clearFocusedElement));
  }
}

// updates styling on the .tree-view-resizer and the panel (container)
function update(pushEditor) {
  if(typeof pushEditor !== 'boolean') pushEditor = getConfig('pushEditor');
  console.log(pushEditor);
  return Promise.resolve().then(function() {
    var panelView;
    treeViewEl.style.position = pushEditor ? '' : 'absolute';
    if(panelView = atom.views.getView(treeView.panel)) {
      panelView.style.width = pushEditor ? '' : `${getConfig('hiddenWidth')}px`;
    }
  }).then(resize).catch(logError);
}

// shows the tree view
function show(delay = getConfig('showDelay'), shouldDisableHoverEvents = false) {
  visible = true;
  // disable hover events on the tree view when this
  // show is not triggered by a hover event
  if(shouldDisableHoverEvents) disableHoverEvents();
  // keep a reference to the currently focused element
  // so we can restore focus when the tree view will hide
  if(!focusedElement) storeFocusedElement();
  // show the tree view content
  treeView.scroller[0].style.display = '';
  return animate(treeView.list[0].clientWidth, delay).then(function(finished) {
    // focus the tree view if the animation
    // finished (i.e. wasn't cancelled)
    if(finished) treeView.focus();
  });
}

// hides the tree view
function hide(delay = getConfig('hideDelay')) {
  visible = false;
  // enable hover events
  enableHoverEvents();
  // focus the element that had focus when show() was triggered
  restoreFocus();
  return animate(getConfig('hiddenWidth'), delay).then(function(finished) {
    // hide the tree view content
    if(finished) treeView.scroller[0].style.display = 'none';
  });
}

// toggles the tree view
function toggle() {
  return visible ? hide(0) : show(0, true);
}

// resizes the tree view when its content width might change
function resize() {
  return Promise.resolve().then(function() {
    return visible ? show(0) : hide(0);
  });
}

// cache the element that currently has focus
function storeFocusedElement() {
  focusedElement = document.activeElement;
}

// clear the reference to the focusedElement. useful
// when we want to invalidate the next restoreFocus
function clearFocusedElement() {
  focusedElement = null;
}

// recovers focus on focusedElement
function restoreFocus() {
  if(!focusedElement) return;
  if(typeof focusedElement.focused === 'function') focusedElement.focused();
  else if(typeof focusedElement.focus === 'function') focusedElement.focus();
  clearFocusedElement();
}

// enable hover events on the tree view
// (but only if showOn is 'hover' or 'hover + click')
function enableHoverEvents() {
  hoverEventsEnabled = !!getConfig('showOn').match('hover');
}

// disable hover events on the tree view
function disableHoverEvents() {
  hoverEventsEnabled = false;
}

// fired when the mouse enters the tree view
function mouseenter() {
  if(hoverEventsEnabled) show();
}

// fired when the mouse leaves the tree view
function mouseleave() {
  if(hoverEventsEnabled) hide();
}

// fired when the tree view is clicked
function click() {
  var showOn = getConfig('showOn');
  if(showOn.match('click')) toggle();
}

// fired when the tree view is blurred
function blur() {
  if(!getConfig('showOn').match(/(click|touch)/)) return;
  // clear the focused element so the element the user
  // clicked will be focused instead
  clearFocusedElement();
  hide(0);
}

function isTreeView(target) {
  while(target != treeViewEl.parentNode && target != document.body) {
    target = target.parentNode;
  }
  return target == treeViewEl.parentNode;
}

function swipeLeftStart({source, deltaX}) {
  if(!getConfig('showOn').match('touch') || !isTreeView(source)) return;
  treeView.scroller[0].style.display = 'block'
  if(atom.config.get('tree-view.showOnRightSide')) {
    swipeShow(-deltaX);
  } else {
    swipeHide(deltaX);
  }
}

function swipeLeftEnd({source}) {
  if(!getConfig('showOn').match('touch') || !isTreeView(source)) return;
  if(atom.config.get('tree-view.showOnRightSide')) {
    show(0);
  } else {
    hide(0);
  }
}

function swipeRightStart({source, deltaX}) {
  if(!getConfig('showOn').match('touch') || !isTreeView(source)) return;
  treeView.scroller[0].style.display = 'block'
  if(atom.config.get('tree-view.showOnRightSide')) {
    swipeHide(-deltaX);
  } else {
    swipeShow(deltaX);
  }
}

function swipeRightEnd({source}) {
  if(!getConfig('showOn').match('touch') || !isTreeView(source)) return;
  if(atom.config.get('tree-view.showOnRightSide')) {
    hide(0);
  } else {
    show(0);
  }
}

function swipeShow(deltaX) {
  newWidth = Math.min(treeView.list[0].clientWidth, treeViewEl.clientWidth + deltaX);
  requestAnimationFrame(function resizer() {
    treeViewEl.style.width = `${newWidth}px`;
  });
}

function swipeHide(deltaX) {
  newWidth = Math.max(getConfig('hiddenWidth'), treeViewEl.clientWidth + deltaX);
  requestAnimationFrame(function resizer() {
    treeViewEl.style.width = `${newWidth}px`;
  });
}

// the animation function resolves with 'true' if the
// animation finished, with 'false' if cancelled
function animate(targetWidth, delay) {
  var initialWidth, animationSpeed, duration;
  // get the initial width of the element
  initialWidth = treeViewEl.clientWidth;
  // set animationSpeed to Infinity if it equals 0
  animationSpeed = getConfig('animationSpeed') || Infinity;
  // calculate the animation duration if animationSpeed
  // equals 0 divide by Infinity for a duration of 0
  duration = Math.abs(targetWidth - initialWidth) / animationSpeed;

  // cancel any current animation
  if(currentAnimation && currentAnimation.playState !== 'finished') {
    currentAnimation.cancel();
    delay = 0; // immediately trigger the next animation
  }

  return new Promise(function(resolve) {
    var animation;
    // check if animation necessary
    if(duration === 0) return void setTimeout(function() {
      treeViewEl.style.width = `${targetWidth}px`;
      resolve(true);
    }, delay);

    // cache the current animationPlayer so we can
    // cancel it as soon as another animation begins
    animation = currentAnimation = treeViewEl.animate([
      {width: initialWidth}, {width: targetWidth}
    ], {duration, delay});

    animation.addEventListener('finish', function finish() {
      animation.removeEventListener('finish', finish);
      // if cancelled, resolve with false
      if(animation.playState !== 'finished') return resolve(false);
      // prevent tree view from resetting its width to initialWidth
      treeViewEl.style.width = `${targetWidth}px`;
      // reset the currentAnimation reference
      currentAnimation = null;
      resolve(true);
    });
  }).catch(logError);
}

// public API

module.exports = {
  config: {
    showOn: {
      description: 'The type of event that triggers the tree view to show or hide. The touch events require atom-touch-events (https://atom.io/packages/atom-touch-events) to be installed. You\'ll need to restart this package after installing atom-touch-events for touch events to become available.',
      type: 'string',
      default: 'hover',
      enum: [
        'hover',
        'click',
        'touch',
        'hover + click',
        'hover + touch',
        'click + touch',
        'hover + click + touch',
        'none'
      ],
      order: 0
    },
    showDelay: {
      description: 'The delay in milliseconds before the tree view will show. Only applies to hover events.',
      type: 'integer',
      default: 200,
      minimum: 0,
      order: 1
    },
    hideDelay: {
      description: 'The delay in milliseconds before the tree view will hide. Only applies to hover events.',
      type: 'integer',
      default: 200,
      minimum: 0,
      order: 2
    },
    hiddenWidth: {
      description: 'The width in pixels of the tree view when it is hidden.',
      type: 'integer',
      default: 5,
      minimum: 1,
      order: 3
    },
    animationSpeed: {
      description: 'The speed in 1000 pixels per second of the animation. Set to 0 to disable the animation.',
      type: 'number',
      default: 1,
      minimum: 0,
      order: 4
    },
    pushEditor: {
      description: 'Push the edge of the editor around to keep the entire editor contents visible.',
      type: 'boolean',
      default: false,
      order: 5
    }
  },

  activate: function activate() {
    if(!SubAtom) SubAtom = require('sub-atom');
    init();

    // these commands are handled here, because we don't want to dispose them on deinit()
    this.commands = atom.commands.add('atom-workspace', {
      'autohide-tree-view:enable': init,
      'autohide-tree-view:disable': deinit
    });
  },

  deactivate: function deactivate() {
    this.commands.dispose();
    deinit();
  },

  // provide service for other packages to
  provideService: function provideService() {
    return {
      show: function(delay, shouldDisableHoverEvents) {
        return show(delay, shouldDisableHoverEvents);
      },
      hide: function(delay) {
        return hide(delay);
      },
      enable: function() {
        return init();
      },
      disable: function() {
        return deinit();
      }
    }
  },

  consumeTouchSwipeLeftService: function consumeTouchSwipeLeftService(onDidTouchSwipeLeft) {
    onTouchSwipeLeft = onDidTouchSwipeLeft;
  },

  consumeTouchSwipeRightService: function consumeTouchSwipeRightService(onDidTouchSwipeRight) {
    onTouchSwipeRight = onDidTouchSwipeRight;
  }
};
<|endoftext|>


<commit_before>var HTTP_STATUS_CODES = require('http').STATUS_CODES;

var fs = require('fs');
var os = require('os');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var request = require('request');
var xmlbuilder = require('xmlbuilder');
var stackTrace = require('stack-trace');
var hashish = require('hashish');
var querystring = require('querystring');

module.exports = Airbrake;
util.inherits(Airbrake, EventEmitter);
function Airbrake() {
  this.key = null;

  this.host = 'http://' + os.hostname();
  this.env = process.env.NODE_ENV || 'development';
  this.projectRoot = null;
  this.appVersion = null;
  this.timeout = 30 * 1000;
  this.developmentEnvironments = [];
  this.dieOnError = true;

  this.protocol = 'http';
  this.serviceHost = 'api.airbrake.io';
}

Airbrake.PACKAGE = (function() {
  var json = fs.readFileSync(__dirname + '/../package.json', 'utf8');
  return JSON.parse(json);
})();

Airbrake.createClient = function(key, env) {
  var instance = new this();
  instance.key = key;
  instance.env = env || instance.env;
  return instance;
};

Airbrake.prototype.expressHandler = function() {
  var self = this;

  return function errorHandler(err, req, res, next) {
    if (res.statusCode < 400) res.statusCode = 500;
    err.url = req.url;
    err.component = req.url;
    err.action = req.method;
    err.params = req.params;
    err.session = req.session;

    self.onError(err);
    next(err);
  }
}

Airbrake.prototype.onError = function(err) {
  var self = this;
  self.log('Airbrake: Uncaught exception, sending notification for:');
  self.log(err.stack);

  self.notify(err, function(notifyErr, url, devMode) {
    if (notifyErr) {
      self.log('Airbrake: Could not notify service.');
      self.log(notifyErr.stack);
    } else if (url) {
      self.log('Airbrake: Notified service: ' + url);
    } else {
      self.log('Airbrake: Dev mode, did not send.');
    }

    if (self.dieOnError) {
      process.exit(1);
    }
  });
}

Airbrake.prototype.handleExceptions = function() {
  var self = this;
  process.on('uncaughtException', function(err) {
    self.onError(err)
  });
};

Airbrake.prototype.log = function(str) {
  console.error(str);
};

Airbrake.prototype.notify = function(err, cb) {
  var callback = this._callback(cb);
  // log errors instead of posting to airbrake if a dev enviroment
  if (this.developmentEnvironments.indexOf(this.env) != -1) {
    this.log(err);
    return callback(null, null, true);
  }

  var body = this.notifyXml(err);

  var options = {
    method: 'POST',
    url: this.url('/notifier_api/v2/notices'),
    body: body,
    timeout: this.timeout,
    headers: {
      'Content-Length': body.length,
      'Content-Type': 'text/xml',
    },
  };

  request(options, function(err, res, body) {
    if (err) {
      return callback(err);
    }

    if (res.statusCode >= 300) {
      var status = HTTP_STATUS_CODES[res.statusCode];

      var explanation = body.match(/<error>([^<]+)/i);
      explanation = (explanation)
        ? ': ' + explanation[1]
        : ': ' + body;

      return callback(new Error(
        'Notification failed: ' + res.statusCode + ' ' + status + explanation
      ));
    }

    // Give me a break, this is legit : )
    var m = body.match(/<url>([^<]+)/i);
    var url = (m)
      ? m[1]
      : null;

    callback(null, url);
  });
};

Airbrake.prototype._callback = function(cb) {
  var self = this;
  return function(err) {
    if (cb) {
      cb.apply(self, arguments);
      return;
    }

    if (err) {
      self.emit('error', err);
    }
  };
};

Airbrake.prototype.url = function(path) {
  return this.protocol + '://' + this.serviceHost + path;
};

Airbrake.prototype.notifyXml = function(err, pretty) {
  var notice = xmlbuilder.create().begin('notice', {
    version: '1.0',
    encoding: 'UTF-8'
  });

  this.appendHeaderXml(notice);
  this.appendErrorXml(notice, err);
  this.appendRequestXml(notice, err);
  this.appendServerEnvironmentXml(notice);

  return notice.up().toString({pretty: pretty});
};

Airbrake.prototype.appendHeaderXml = function(notice) {
  notice
    .att('version', '2.1')
    .ele('api-key')
      .txt(this.key || '-')
    .up()
    .ele('notifier')
      .ele('name')
        .txt(Airbrake.PACKAGE.name)
      .up()
      .ele('version')
        .txt(Airbrake.PACKAGE.version)
      .up()
      .ele('url')
        .txt(Airbrake.PACKAGE.homepage)
      .up()
    .up();
};

Airbrake.prototype.appendErrorXml = function(notice, err) {
  var trace = stackTrace.parse(err);
  var error = notice
    .ele('error')
      .ele('class')
        .txt(err.type || 'Error')
      .up()
      .ele('message')
        .txt(err.message || '-')
      .up()
      .ele('backtrace')

  trace.forEach(function(callSite) {
    error
      .ele('line')
        .att('method', callSite.getFunctionName() || '')
        .att('file', callSite.getFileName() || '')
        .att('number', callSite.getLineNumber() || '')
  });
};

Airbrake.prototype.appendRequestXml = function(notice, err) {
  var request = notice.ele('request');

  var self = this;
  ['url', 'component', 'action'].forEach(function(nodeName) {
    var node = request.ele(nodeName);
    var val = err[nodeName];

    if (nodeName === 'url') {
      if (!val) {
        val = self.host;
      } else if (val.substr(0, 1) === '/') {
        val = self.host + val;
      }
    }

    if (val) {
      node.txt(val);
    }
  });

  this.addRequestVars(request, 'cgi-data', this.cgiDataVars(err));
  this.addRequestVars(request, 'session', this.sessionVars(err));
  this.addRequestVars(request, 'params', this.paramsVars(err));
};

Airbrake.prototype.addRequestVars = function(request, type, vars) {
  this.emit('vars', type, vars);

  var node;
  Object.keys(vars).forEach(function(key) {
    node = node || request.ele(type);
    node
      .ele('var')
      .att('key', key)
      .txt(util.inspect(vars[key]));
  });
};

Airbrake.prototype.cgiDataVars = function(err) {
  var cgiData = {};
  Object.keys(process.env).forEach(function(key) {
    cgiData[key] = process.env[key];
  });

  var exclude = [
    'type',
    'message',
    'arguments',
    'stack',
    'url',
    'session',
    'params',
    'component',
    'action',
  ];

  Object.keys(err).forEach(function(key) {
    if (exclude.indexOf(key) >= 0) {
      return;
    }

    cgiData['err.' + key] = err[key];
  });

  cgiData['process.pid'] = process.pid;
  cgiData['process.uid'] = process.getuid();
  cgiData['process.gid'] = process.getgid();
  cgiData['process.cwd'] = process.cwd();
  cgiData['process.execPath'] = process.execPath;
  cgiData['process.version'] = process.version;
  cgiData['process.argv'] = process.argv;
  cgiData['process.memoryUsage'] = process.memoryUsage();
  cgiData['os.loadavg'] = os.loadavg();
  cgiData['os.uptime'] = os.uptime();

  return cgiData;
};

Airbrake.prototype.sessionVars = function(err) {
  return (err.session instanceof Object)
    ? err.session
    : {};
};

Airbrake.prototype.paramsVars = function(err) {
  return (err.params instanceof Object)
    ? err.params
    : {};
};

Airbrake.prototype.appendServerEnvironmentXml = function(notice) {
  var serverEnvironment = notice.ele('server-environment');

  if (this.projectRoot) {
    serverEnvironment
      .ele('project-root')
      .txt(this.projectRoot);
  }

  serverEnvironment
      .ele('environment-name')
      .txt(this.env)

  if (this.appVersion) {
    serverEnvironment
      .ele('app-version')
      .txt(this.appVersion);
  }
};

Airbrake.prototype.trackDeployment = function(params, cb) {
  if (typeof params === 'function') {
    cb = params;
    params = {};
  }

  params = hashish.merge({
    key: this.key,
    env: this.env,
    user: process.env.USER,
    rev: '',
    repo: '',
  }, params);

  var body = this.deploymentPostData(params);

  var options = {
    method: 'POST',
    url: this.url('/deploys.txt'),
    body: body,
    timeout: this.timeout,
    headers: {
      'Content-Length': body.length,
      'Content-Type': 'application/x-www-form-urlencoded',
    },
  };

  var callback = this._callback(cb);

  request(options, function(err, res, body) {
    if (err) {
      return callback(err);
    }

    if (res.statusCode >= 300) {
      var status = HTTP_STATUS_CODES[res.statusCode];
      return callback(new Error(
        'Deployment failed: ' + res.statusCode + ' ' + status + ': ' + body
      ));
    }

    callback(null, params);
  });
};

Airbrake.prototype.deploymentPostData = function(params) {
  return querystring.stringify({
    'api_key': params.key,
    'deploy[rails_env]': params.env,
    'deploy[local_username]': params.user,
    'deploy[scm_revision]': params.rev,
    'deploy[scm_repository]': params.repo,
  });
};
<commit_msg>Version up to 2.2 of the API<commit_after>var HTTP_STATUS_CODES = require('http').STATUS_CODES;

var fs = require('fs');
var os = require('os');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var request = require('request');
var xmlbuilder = require('xmlbuilder');
var stackTrace = require('stack-trace');
var hashish = require('hashish');
var querystring = require('querystring');

module.exports = Airbrake;
util.inherits(Airbrake, EventEmitter);
function Airbrake() {
  this.key = null;

  this.host = 'http://' + os.hostname();
  this.env = process.env.NODE_ENV || 'development';
  this.projectRoot = null;
  this.appVersion = null;
  this.timeout = 30 * 1000;
  this.developmentEnvironments = [];
  this.dieOnError = true;

  this.protocol = 'http';
  this.serviceHost = 'api.airbrake.io';
}

Airbrake.PACKAGE = (function() {
  var json = fs.readFileSync(__dirname + '/../package.json', 'utf8');
  return JSON.parse(json);
})();

Airbrake.createClient = function(key, env) {
  var instance = new this();
  instance.key = key;
  instance.env = env || instance.env;
  return instance;
};

Airbrake.prototype.expressHandler = function() {
  var self = this;

  return function errorHandler(err, req, res, next) {
    if (res.statusCode < 400) res.statusCode = 500;
    err.url = req.url;
    err.component = req.url;
    err.action = req.method;
    err.params = req.params;
    err.session = req.session;

    self.onError(err);
    next(err);
  }
}

Airbrake.prototype.onError = function(err) {
  var self = this;
  self.log('Airbrake: Uncaught exception, sending notification for:');
  self.log(err.stack);

  self.notify(err, function(notifyErr, url, devMode) {
    if (notifyErr) {
      self.log('Airbrake: Could not notify service.');
      self.log(notifyErr.stack);
    } else if (url) {
      self.log('Airbrake: Notified service: ' + url);
    } else {
      self.log('Airbrake: Dev mode, did not send.');
    }

    if (self.dieOnError) {
      process.exit(1);
    }
  });
}

Airbrake.prototype.handleExceptions = function() {
  var self = this;
  process.on('uncaughtException', function(err) {
    self.onError(err)
  });
};

Airbrake.prototype.log = function(str) {
  console.error(str);
};

Airbrake.prototype.notify = function(err, cb) {
  var callback = this._callback(cb);
  // log errors instead of posting to airbrake if a dev enviroment
  if (this.developmentEnvironments.indexOf(this.env) != -1) {
    this.log(err);
    return callback(null, null, true);
  }

  var body = this.notifyXml(err);

  var options = {
    method: 'POST',
    url: this.url('/notifier_api/v2/notices'),
    body: body,
    timeout: this.timeout,
    headers: {
      'Content-Length': body.length,
      'Content-Type': 'text/xml',
    },
  };

  request(options, function(err, res, body) {
    if (err) {
      return callback(err);
    }

    if (res.statusCode >= 300) {
      var status = HTTP_STATUS_CODES[res.statusCode];

      var explanation = body.match(/<error>([^<]+)/i);
      explanation = (explanation)
        ? ': ' + explanation[1]
        : ': ' + body;

      return callback(new Error(
        'Notification failed: ' + res.statusCode + ' ' + status + explanation
      ));
    }

    // Give me a break, this is legit : )
    var m = body.match(/<url>([^<]+)/i);
    var url = (m)
      ? m[1]
      : null;

    callback(null, url);
  });
};

Airbrake.prototype._callback = function(cb) {
  var self = this;
  return function(err) {
    if (cb) {
      cb.apply(self, arguments);
      return;
    }

    if (err) {
      self.emit('error', err);
    }
  };
};

Airbrake.prototype.url = function(path) {
  return this.protocol + '://' + this.serviceHost + path;
};

Airbrake.prototype.notifyXml = function(err, pretty) {
  var notice = xmlbuilder.create().begin('notice', {
    version: '1.0',
    encoding: 'UTF-8'
  });

  this.appendHeaderXml(notice);
  this.appendErrorXml(notice, err);
  this.appendRequestXml(notice, err);
  this.appendServerEnvironmentXml(notice);

  return notice.up().toString({pretty: pretty});
};

Airbrake.prototype.appendHeaderXml = function(notice) {
  notice
    .att('version', '2.2')
    .ele('api-key')
      .txt(this.key || '-')
    .up()
    .ele('notifier')
      .ele('name')
        .txt(Airbrake.PACKAGE.name)
      .up()
      .ele('version')
        .txt(Airbrake.PACKAGE.version)
      .up()
      .ele('url')
        .txt(Airbrake.PACKAGE.homepage)
      .up()
    .up();
};

Airbrake.prototype.appendErrorXml = function(notice, err) {
  var trace = stackTrace.parse(err);
  var error = notice
    .ele('error')
      .ele('class')
        .txt(err.type || 'Error')
      .up()
      .ele('message')
        .txt(err.message || '-')
      .up()
      .ele('backtrace')

  trace.forEach(function(callSite) {
    error
      .ele('line')
        .att('method', callSite.getFunctionName() || '')
        .att('file', callSite.getFileName() || '')
        .att('number', callSite.getLineNumber() || '')
  });
};

Airbrake.prototype.appendRequestXml = function(notice, err) {
  var request = notice.ele('request');

  var self = this;
  ['url', 'component', 'action'].forEach(function(nodeName) {
    var node = request.ele(nodeName);
    var val = err[nodeName];

    if (nodeName === 'url') {
      if (!val) {
        val = self.host;
      } else if (val.substr(0, 1) === '/') {
        val = self.host + val;
      }
    }

    if (val) {
      node.txt(val);
    }
  });

  this.addRequestVars(request, 'cgi-data', this.cgiDataVars(err));
  this.addRequestVars(request, 'session', this.sessionVars(err));
  this.addRequestVars(request, 'params', this.paramsVars(err));
};

Airbrake.prototype.addRequestVars = function(request, type, vars) {
  this.emit('vars', type, vars);

  var node;
  Object.keys(vars).forEach(function(key) {
    node = node || request.ele(type);
    node
      .ele('var')
      .att('key', key)
      .txt(util.inspect(vars[key]));
  });
};

Airbrake.prototype.cgiDataVars = function(err) {
  var cgiData = {};
  Object.keys(process.env).forEach(function(key) {
    cgiData[key] = process.env[key];
  });

  var exclude = [
    'type',
    'message',
    'arguments',
    'stack',
    'url',
    'session',
    'params',
    'component',
    'action',
  ];

  Object.keys(err).forEach(function(key) {
    if (exclude.indexOf(key) >= 0) {
      return;
    }

    cgiData['err.' + key] = err[key];
  });

  cgiData['process.pid'] = process.pid;
  cgiData['process.uid'] = process.getuid();
  cgiData['process.gid'] = process.getgid();
  cgiData['process.cwd'] = process.cwd();
  cgiData['process.execPath'] = process.execPath;
  cgiData['process.version'] = process.version;
  cgiData['process.argv'] = process.argv;
  cgiData['process.memoryUsage'] = process.memoryUsage();
  cgiData['os.loadavg'] = os.loadavg();
  cgiData['os.uptime'] = os.uptime();

  return cgiData;
};

Airbrake.prototype.sessionVars = function(err) {
  return (err.session instanceof Object)
    ? err.session
    : {};
};

Airbrake.prototype.paramsVars = function(err) {
  return (err.params instanceof Object)
    ? err.params
    : {};
};

Airbrake.prototype.appendServerEnvironmentXml = function(notice) {
  var serverEnvironment = notice.ele('server-environment');

  if (this.projectRoot) {
    serverEnvironment
      .ele('project-root')
      .txt(this.projectRoot);
  }

  serverEnvironment
      .ele('environment-name')
      .txt(this.env)

  if (this.appVersion) {
    serverEnvironment
      .ele('app-version')
      .txt(this.appVersion);
  }
};

Airbrake.prototype.trackDeployment = function(params, cb) {
  if (typeof params === 'function') {
    cb = params;
    params = {};
  }

  params = hashish.merge({
    key: this.key,
    env: this.env,
    user: process.env.USER,
    rev: '',
    repo: '',
  }, params);

  var body = this.deploymentPostData(params);

  var options = {
    method: 'POST',
    url: this.url('/deploys.txt'),
    body: body,
    timeout: this.timeout,
    headers: {
      'Content-Length': body.length,
      'Content-Type': 'application/x-www-form-urlencoded',
    },
  };

  var callback = this._callback(cb);

  request(options, function(err, res, body) {
    if (err) {
      return callback(err);
    }

    if (res.statusCode >= 300) {
      var status = HTTP_STATUS_CODES[res.statusCode];
      return callback(new Error(
        'Deployment failed: ' + res.statusCode + ' ' + status + ': ' + body
      ));
    }

    callback(null, params);
  });
};

Airbrake.prototype.deploymentPostData = function(params) {
  return querystring.stringify({
    'api_key': params.key,
    'deploy[rails_env]': params.env,
    'deploy[local_username]': params.user,
    'deploy[scm_revision]': params.rev,
    'deploy[scm_repository]': params.repo,
  });
};
<|endoftext|>


<commit_before>/**
 * var connection = new Connection({ tag:             'droonga',
 *                                   hostName:        'localhost',
 *                                   port:            24224,
 *                                   receiveHostName: 'localhost',
 *                                   receivePort:     10030 });
 */

var EventEmitter = require('events').EventEmitter;
var fluent = require('fluent-logger');
var FluentReceiver = require('./receiver').FluentReceiver;

var DEFAULT_FLUENT_TAG =
      Connection.DEFAULT_FLUENT_TAG =
        'droonga';
var DEFAULT_FLUENT_HOST_NAME =
      Connection.DEFAULT_FLUENT_HOST_NAME =
        'localhost';
var DEFAULT_FLUENT_PORT =
      Connection.DEFAULT_FLUENT_PORT =
        24224;
var DEFAULT_RECEIVE_HOST_NAME =
      Connection.DEFAULT_RECEIVE_HOST_NAME =
        'localhost';

var ERROR_GATEWAY_TIMEOUT =
      Connection.ERROR_GATEWAY_TIMEOUT =
        504;

var DEFAULT_RESPONSE_TIMEOUT =
      Connection.DEFAULT_RESPONSE_TIMEOUT =
        60 * 1000;

function Connection(params) {
  this._params = params || {};
  this._init();
}

Connection.prototype = new EventEmitter();

Connection.prototype._init = function() {
  this._callbacks = {};
  this.tag = this._params.tag || DEFAULT_FLUENT_TAG;
  this._initSender();
  this._initReceiver();
};

Connection.prototype._initSender = function(wait) {
  var options = { host: this._params.hostName || DEFAULT_FLUENT_HOST_NAME,
                  port: this._params.port || DEFAULT_FLUENT_PORT };
  var sender = fluent.createFluentSender(this.tag, options);
  this._sender = sender;
  this._sender.on('error', (function(error) {
    this.emit('error', error);
  }).bind(this));
};

Connection.prototype._initReceiver = function() {
  this.receiveHostName = this._params.receiveHostName || DEFAULT_RECEIVE_HOST_NAME;
  this.receivePort = this._params.receivePort;

  var receiver = new FluentReceiver(this.receivePort);
  receiver.listen((function() {
    this.receivePort = receiver.port;
  }).bind(this));

  this._receiver = receiver;
  this._receiver.on(this.tag + '.message',
                    this._handleMessage.bind(this));
};

function isSuccess(code) {
  return Math.floor(code / 100) == 2;
}

Connection.prototype._handleMessage = function(envelope) {
  var inReplyTo = envelope.inReplyTo;
  if (inReplyTo) {
    var errorCode = envelope.statusCode;
    if (!errorCode || isSuccess(errorCode))
      errorCode = null;
    this.emit('reply:' + inReplyTo, errorCode, envelope);
  } else {
    this.emit(envelope.type, envelope.body);
  }
};

var count = 0;
function createId() {
  return Date.now() + ':' + (count++);
}

function getCurrentTime() {
  // The method toISOString() returns a GMT (ex. 2013-01-10T08:34:41.252Z)
  // on node. However, a local time (ex. 2013-01-10T17:34:41.252+09:00) is
  // more helpful for debugging. We should use it in the feature...
  return new Date().toISOString();
}

function toPositiveInteger(number) {
  if (!number)
    return 0;

  var integer = parseInt(number);
  if (isNaN(integer))
    return 0;

  return Math.max(integer, 0);
}

Connection.prototype.emitMessage = function(type, body, callback, options) {
  options = options || {};
  var id = createId();
  var envelope = {
    id:         id,
    date:       getCurrentTime(),
    replyTo:    this.receiveHostName + ':' + this.receivePort,
    statusCode: 200,
    type:       type,
    body:       body
  };
  if (callback) {
    var event = 'reply:' + id;
    this.once(event, callback);
    options.timeout = toPositiveInteger(options.timeout) ||
                        DEFAULT_RESPONSE_TIMEOUT;
    setTimeout((function() {
      if (this.listeners(event).length) {
        this.removeAllListeners(event);
        callback(ERROR_GATEWAY_TIMEOUT, null);
      }
    }).bind(this), options.timeout);
  }
  this._sender.emit('message', envelope);
  return envelope;
};

Connection.prototype.close = function() {
  this.removeAllListeners();

  if (this._sender && typeof this._sender.end == 'function') {
    this._sender.end();
    this._sender.removeAllListeners();
    delete this._sender;
  }

  if (this._receiver && typeof this._receiver.close == 'function') {
    this._receiver.close();
    this._receiver.removeAllListeners();
    delete this._receiver;
  }
};

exports.Connection = Connection;
<commit_msg>Provide full information of the receiver socket via "replyTo" header, for the fluentd<commit_after>/**
 * var connection = new Connection({ tag:             'droonga',
 *                                   hostName:        'localhost',
 *                                   port:            24224,
 *                                   receiveHostName: 'localhost',
 *                                   receivePort:     10030 });
 */

var EventEmitter = require('events').EventEmitter;
var fluent = require('fluent-logger');
var FluentReceiver = require('./receiver').FluentReceiver;

var DEFAULT_FLUENT_TAG =
      Connection.DEFAULT_FLUENT_TAG =
        'droonga';
var DEFAULT_FLUENT_HOST_NAME =
      Connection.DEFAULT_FLUENT_HOST_NAME =
        'localhost';
var DEFAULT_FLUENT_PORT =
      Connection.DEFAULT_FLUENT_PORT =
        24224;
var DEFAULT_RECEIVE_HOST_NAME =
      Connection.DEFAULT_RECEIVE_HOST_NAME =
        'localhost';

var ERROR_GATEWAY_TIMEOUT =
      Connection.ERROR_GATEWAY_TIMEOUT =
        504;

var DEFAULT_RESPONSE_TIMEOUT =
      Connection.DEFAULT_RESPONSE_TIMEOUT =
        60 * 1000;

function Connection(params) {
  this._params = params || {};
  this._init();
}

Connection.prototype = new EventEmitter();

Connection.prototype._init = function() {
  this._callbacks = {};
  this._id = Date.now();
  this.tag = this._params.tag || DEFAULT_FLUENT_TAG;
  this._initSender();
  this._initReceiver();
};

Connection.prototype._initSender = function(wait) {
  var options = { host: this._params.hostName || DEFAULT_FLUENT_HOST_NAME,
                  port: this._params.port || DEFAULT_FLUENT_PORT };
  var sender = fluent.createFluentSender(this.tag, options);
  this._sender = sender;
  this._sender.on('error', (function(error) {
    this.emit('error', error);
  }).bind(this));
};

Connection.prototype._initReceiver = function() {
  this.receiveHostName = this._params.receiveHostName || DEFAULT_RECEIVE_HOST_NAME;
  this.receivePort = this._params.receivePort;

  var receiver = new FluentReceiver(this.receivePort);
  receiver.listen((function() {
    this.receivePort = receiver.port;
  }).bind(this));

  this._receiver = receiver;
  this._receiver.on(this.tag + '.message',
                    this._handleMessage.bind(this));
};

function isSuccess(code) {
  return Math.floor(code / 100) == 2;
}

Connection.prototype._handleMessage = function(envelope) {
  var inReplyTo = envelope.inReplyTo;
  if (inReplyTo) {
    var errorCode = envelope.statusCode;
    if (!errorCode || isSuccess(errorCode))
      errorCode = null;
    this.emit('reply:' + inReplyTo, errorCode, envelope);
  } else {
    this.emit(envelope.type, envelope.body);
  }
};

var count = 0;
function createId() {
  return Date.now() + ':' + (count++);
}

function getCurrentTime() {
  // The method toISOString() returns a GMT (ex. 2013-01-10T08:34:41.252Z)
  // on node. However, a local time (ex. 2013-01-10T17:34:41.252+09:00) is
  // more helpful for debugging. We should use it in the feature...
  return new Date().toISOString();
}

function toPositiveInteger(number) {
  if (!number)
    return 0;

  var integer = parseInt(number);
  if (isNaN(integer))
    return 0;

  return Math.max(integer, 0);
}

Connection.prototype.emitMessage = function(type, body, callback, options) {
  options = options || {};
  var id = createId();
  var replyTo = this.receiveHostName + ':' + this.receivePort + '/' +
                  this.tag + '?sessionid=' + this._id;
  var envelope = {
    id:         id,
    date:       getCurrentTime(),
    replyTo:    replyTo,
    statusCode: 200,
    type:       type,
    body:       body
  };
  if (callback) {
    var event = 'reply:' + id;
    this.once(event, callback);
    options.timeout = toPositiveInteger(options.timeout) ||
                        DEFAULT_RESPONSE_TIMEOUT;
    setTimeout((function() {
      if (this.listeners(event).length) {
        this.removeAllListeners(event);
        callback(ERROR_GATEWAY_TIMEOUT, null);
      }
    }).bind(this), options.timeout);
  }
  this._sender.emit('message', envelope);
  return envelope;
};

Connection.prototype.close = function() {
  this.removeAllListeners();

  if (this._sender && typeof this._sender.end == 'function') {
    this._sender.end();
    this._sender.removeAllListeners();
    delete this._sender;
  }

  if (this._receiver && typeof this._receiver.close == 'function') {
    this._receiver.close();
    this._receiver.removeAllListeners();
    delete this._receiver;
  }
};

exports.Connection = Connection;
<|endoftext|>


<commit_before>var colors = require('colors')

  , types = Object.keys(colors).filter(function (k) {
      return /^[a-z]+$/.test(k) && typeof colors[k] == 'function'
    })

  , translators = types.map(function (type) {
      var re = new RegExp('\\{' + type + '\\}(.*)\\{/' + type + '\\}')
      return function (str) {
        return str.replace(re, '$1'[type])
      }
    })

  , render = function (str) {
      return [str].concat(translators).reduce(function (str, fn) {
        return fn(str)
      })
    }

module.exports.render = render<commit_msg>licence<commit_after>/*!
 * The MIT License (MIT)
 *
 * Copyright (c) 2012 Rod Vagg <rod@vagg.org> @rvagg
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
 * persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

var colors = require('colors')

  , types = Object.keys(colors).filter(function (k) {
      return /^[a-z]+$/.test(k) && typeof colors[k] == 'function'
    })

  , translators = types.map(function (type) {
      var re = new RegExp('\\{' + type + '\\}(.*)\\{/' + type + '\\}')
      return function (str) {
        return str.replace(re, '$1'[type])
      }
    })

  , render = function (str) {
      return translators.reduce(
          function (str, fn) { return fn(str) }
        , str
      )
    }

module.exports.render = render<|endoftext|>


<commit_before>'use strict';

var
FP          = require('filepath'),
Promise     = require('./promise'),
U           = require('./u'),
errors      = require('./errors'),
application = require('./application'),

packageJSONLoader  = require('./package_json_loader'),
clArgsLoader       = require('./cl_args_loader'),
configsFilesLoader = require('./configs_files_loader');

exports.DEFAULTS = {
  ENVIRONMENT: 'development'
};

// args.usageString
// args.helpString
// args.options
// args.appdir = FP.create().resolve(process.argv[1]).dirname();
// args.sysconfigsdir
// args.name
// args.version
// args.environment
exports.load = function (args) {
  var
  packageJSON, argv, environment, configs, app;

  packageJSON = packageJSONLoader.readPackageJSON({
    appdir: args.appdir
  });

  argv = clArgsLoader.loadArgv({
    usageString : args.usageString,
    helpString  : args.helpString,
    options     : args.options,
    argv        : process.argv
  });

  environment = argv.environment ||
                process.env.ENVIRONMENT ||
                process.env.NODE_ENV ||
                args.environment ||
                exports.DEFAULTS.ENVIRONMENT;

  configs = configsFilesLoader.loadConfigs({
    environment   : environment,
    appdir        : args.appdir,
    sysconfigsdir : args.sysconfigsdir
  });

  app = application.create({
    name          : packageJSON.name || args.name,
    version       : packageJSON.version || args.version,
    appdir        : args.appdir,
    sysconfigsdir : args.sysconfigsdir,
    packageJSON   : packageJSON,
    environment   : environment,
    configs       : configs,
    argv          : argv
  });
};

function loadInitializers(app) {
  var
  promises,
  pluginsDir  = app.appdir.append('initializers'),
  pluginFiles = [];

  if (pluginsDir.isDirectory()) {
    pluginFiles = pluginsDir.list();
  }

  promises = U.compact(pluginFiles.map(U.partial(loadPlugin, app)));
  return Promise.all(promises);
}

function loadInitializer(app, path) {
  var plugin;

  if (path.isFile()) {
    path = path.toString();
    plugin = require(path);

    if (typeof plugin !== 'function') {
      throw new errors.ArgumentError('Initializer exports must be a function: '+ path);
    }

    return Promise.resolve(plugin(app));
  }

  return null;
}
<commit_msg>new pass at the applicatio loader.<commit_after>'use strict';

var
Promise     = require('./promise'),
U           = require('./u'),
errors      = require('./errors'),
application = require('./application'),

packageJSONLoader  = require('./package_json_loader'),
clArgsLoader       = require('./cl_args_loader'),
configsFilesLoader = require('./configs_files_loader');

exports.DEFAULTS = {
  ENVIRONMENT: 'development',
  INITIALIZER_PATH: 'initializers'
};

// args.usageString
// args.helpString
// args.options
// args.appdir = FP.create().resolve(process.argv[1]).dirname();
// args.sysconfigsdir
// args.name
// args.version
// args.environment
exports.load = function (args) {
  Promise.resolve(args)
    .then(loadPackageJSON)
    .then(loadCommandLineArgs)
    .then(setEnvironment)
    .then(loadFileConfigs)
    .then(createApplication)
    .then(loadInitializers)
    .then(function (args) {
      return args.app;
    });
};

// sets args.packageJSON
function loadPackageJSON(args) {
  args.packageJSON = packageJSONLoader.readPackageJSON({
    appdir: args.appdir
  });

  return args;
}

// sets args.argv
function loadCommandLineArgs(args) {
  args.argv = clArgsLoader.loadArgv({
    usageString : args.usageString,
    helpString  : args.helpString,
    options     : args.options,
    argv        : process.argv
  });

  return args;
}

// sets args.environment
function setEnvironment(args) {
  args.environment = args.argv.environment ||
                process.env.ENVIRONMENT ||
                process.env.NODE_ENV ||
                args.environment ||
                exports.DEFAULTS.ENVIRONMENT;
  return args;
}

// sets args.configs
function loadFileConfigs(args) {
  args.configs = configsFilesLoader.loadConfigs({
    environment   : args.environment,
    appdir        : args.appdir,
    sysconfigsdir : args.sysconfigsdir
  });

  return args;
}

// sets args.app
function createApplication(args) {
  args.app = application.create({
    name          : args.packageJSON.name || args.name,
    version       : args.packageJSON.version || args.version,
    appdir        : args.appdir,
    sysconfigsdir : args.sysconfigsdir,
    packageJSON   : args.packageJSON,
    environment   : args.environment,
    configs       : args.configs,
    argv          : args.argv
  });

  return args;
}

function loadInitializers(args) {
  var
  promises,
  pluginsDir  = args.app.appdir.append(exports.DEFAULTS.INITIALIZER_PATH),
  pluginFiles = [];

  if (pluginsDir.isDirectory()) {
    pluginFiles = pluginsDir.list();
  }

  promises = U.compact(pluginFiles.map(U.partial(loadInitializer, args.app)));
  return Promise.all(promises).then(U.constant(args));
}

function loadInitializer(app, path) {
  var plugin;

  if (path.isFile()) {
    path = path.toString();
    plugin = require(path);

    if (typeof plugin !== 'function') {
      throw new errors.ArgumentError('Initializer exports must be a function: '+ path);
    }

    return Promise.resolve(plugin(app));
  }

  return null;
}
<|endoftext|>


<commit_before>'use strict';

!function($) {

Foundation.Box = {
  ImNotTouchingYou: ImNotTouchingYou,
  GetDimensions: GetDimensions,
  GetOffsets: GetOffsets
}

/**
 * Compares the dimensions of an element to a container and determines collision events with container.
 * @function
 * @param {jQuery} element - jQuery object to test for collisions.
 * @param {jQuery} parent - jQuery object to use as bounding container.
 * @param {Boolean} lrOnly - set to true to check left and right values only.
 * @param {Boolean} tbOnly - set to true to check top and bottom values only.
 * @default if no parent object passed, detects collisions with `window`.
 * @returns {Boolean} - true if collision free, false if a collision in any direction.
 */
function ImNotTouchingYou(element, parent, lrOnly, tbOnly) {
  var eleDims = GetDimensions(element),
      top, bottom, left, right;

  if (parent) {
    var parDims = GetDimensions(parent);

    bottom = (eleDims.offset.top + eleDims.height <= parDims.height + parDims.offset.top);
    top    = (eleDims.offset.top >= parDims.offset.top);
    left   = (eleDims.offset.left >= parDims.offset.left);
    right  = (eleDims.offset.left + eleDims.width <= parDims.width);
  }
  else {
    bottom = (eleDims.offset.top + eleDims.height <= eleDims.windowDims.height + eleDims.windowDims.offset.top);
    top    = (eleDims.offset.top >= eleDims.windowDims.offset.top);
    left   = (eleDims.offset.left >= eleDims.windowDims.offset.left);
    right  = (eleDims.offset.left + eleDims.width <= eleDims.windowDims.width);
  }

  var allDirs = [bottom, top, left, right];

  if (lrOnly) {
    return left === right === true;
  }

  if (tbOnly) {
    return top === bottom === true;
  }

  return allDirs.indexOf(false) === -1;
};

/**
 * Uses native methods to return an object of dimension values.
 * @function
 * @param {jQuery || HTML} element - jQuery object or DOM element for which to get the dimensions. Can be any element other that document or window.
 * @returns {Object} - nested object of integer pixel values
 * TODO - if element is window, return only those values.
 */
function GetDimensions(elem, test){
  elem = elem.length ? elem[0] : elem;

  if (elem === window || elem === document) {
    throw new Error("I'm sorry, Dave. I'm afraid I can't do that.");
  }

  var rect = elem.getBoundingClientRect(),
      parRect = elem.parentNode.getBoundingClientRect(),
      winRect = document.body.getBoundingClientRect(),
      winY = window.pageYOffset,
      winX = window.pageXOffset;

  return {
    width: rect.width,
    height: rect.height,
    offset: {
      top: rect.top + winY,
      left: rect.left + winX
    },
    parentDims: {
      width: parRect.width,
      height: parRect.height,
      offset: {
        top: parRect.top + winY,
        left: parRect.left + winX
      }
    },
    windowDims: {
      width: winRect.width,
      height: winRect.height,
      offset: {
        top: winY,
        left: winX
      }
    }
  }
}

/**
 * Returns an object of top and left integer pixel values for dynamically rendered elements,
 * such as: Tooltip, Reveal, and Dropdown
 * @function
 * @param {jQuery} element - jQuery object for the element being positioned.
 * @param {jQuery} anchor - jQuery object for the element's anchor point.
 * @param {String} position - a string relating to the desired position of the element, relative to it's anchor
 * @param {Number} vOffset - integer pixel value of desired vertical separation between anchor and element.
 * @param {Number} hOffset - integer pixel value of desired horizontal separation between anchor and element.
 * @param {Boolean} isOverflow - if a collision event is detected, sets to true to default the element to full width - any desired offset.
 * TODO alter/rewrite to work with `em` values as well/instead of pixels
 */
function GetOffsets(element, anchor, position, vOffset, hOffset, isOverflow) {
  var $eleDims = GetDimensions(element),
      $anchorDims = anchor ? GetDimensions(anchor) : null;

  switch (position) {
    case 'top':
      return {
        left: (Foundation.rtl() ? $anchorDims.offset.left - $eleDims.width + $anchorDims.width : $anchorDims.offset.left),
        top: $anchorDims.offset.top - ($eleDims.height + vOffset)
      }
      break;
    case 'left':
      return {
        left: $anchorDims.offset.left - ($eleDims.width + hOffset),
        top: $anchorDims.offset.top
      }
      break;
    case 'right':
      return {
        left: $anchorDims.offset.left + $anchorDims.width + hOffset,
        top: $anchorDims.offset.top
      }
      break;
    case 'center top':
      return {
        left: ($anchorDims.offset.left + ($anchorDims.width / 2)) - ($eleDims.width / 2),
        top: $anchorDims.offset.top - ($eleDims.height + vOffset)
      }
      break;
    case 'center bottom':
      return {
        left: isOverflow ? hOffset : (($anchorDims.offset.left + ($anchorDims.width / 2)) - ($eleDims.width / 2)),
        top: $anchorDims.offset.top + $anchorDims.height + vOffset
      }
      break;
    case 'center left':
      return {
        left: $anchorDims.offset.left - ($eleDims.width + hOffset),
        top: ($anchorDims.offset.top + ($anchorDims.height / 2)) - ($eleDims.height / 2)
      }
      break;
    case 'center right':
      return {
        left: $anchorDims.offset.left + $anchorDims.width + hOffset + 1,
        top: ($anchorDims.offset.top + ($anchorDims.height / 2)) - ($eleDims.height / 2)
      }
      break;
    case 'center':
      return {
        left: ($eleDims.windowDims.offset.left + ($eleDims.windowDims.width / 2)) - ($eleDims.width / 2),
        top: ($eleDims.windowDims.offset.top + ($eleDims.windowDims.height / 2)) - ($eleDims.height / 2)
      }
      break;
    case 'reveal':
      return {
        left: ($eleDims.windowDims.width - $eleDims.width) / 2,
        top: $eleDims.windowDims.offset.top + vOffset
      }
    case 'reveal full':
      return {
        left: $eleDims.windowDims.offset.left,
        top: $eleDims.windowDims.offset.top
      }
      break;
    default:
      return {
        left: (Foundation.rtl() ? $anchorDims.offset.left - $eleDims.width + $anchorDims.width : $anchorDims.offset.left),
        top: $anchorDims.offset.top + $anchorDims.height + vOffset
      }
  }
}

}(jQuery);
<commit_msg>Incorrect calculation for container right overlap<commit_after>'use strict';

!function($) {

Foundation.Box = {
  ImNotTouchingYou: ImNotTouchingYou,
  GetDimensions: GetDimensions,
  GetOffsets: GetOffsets
}

/**
 * Compares the dimensions of an element to a container and determines collision events with container.
 * @function
 * @param {jQuery} element - jQuery object to test for collisions.
 * @param {jQuery} parent - jQuery object to use as bounding container.
 * @param {Boolean} lrOnly - set to true to check left and right values only.
 * @param {Boolean} tbOnly - set to true to check top and bottom values only.
 * @default if no parent object passed, detects collisions with `window`.
 * @returns {Boolean} - true if collision free, false if a collision in any direction.
 */
function ImNotTouchingYou(element, parent, lrOnly, tbOnly) {
  var eleDims = GetDimensions(element),
      top, bottom, left, right;

  if (parent) {
    var parDims = GetDimensions(parent);

    bottom = (eleDims.offset.top + eleDims.height <= parDims.height + parDims.offset.top);
    top    = (eleDims.offset.top >= parDims.offset.top);
    left   = (eleDims.offset.left >= parDims.offset.left);
    right  = (eleDims.offset.left + eleDims.width <= parDims.width + parDims.offset.left);
  }
  else {
    bottom = (eleDims.offset.top + eleDims.height <= eleDims.windowDims.height + eleDims.windowDims.offset.top);
    top    = (eleDims.offset.top >= eleDims.windowDims.offset.top);
    left   = (eleDims.offset.left >= eleDims.windowDims.offset.left);
    right  = (eleDims.offset.left + eleDims.width <= eleDims.windowDims.width);
  }

  var allDirs = [bottom, top, left, right];

  if (lrOnly) {
    return left === right === true;
  }

  if (tbOnly) {
    return top === bottom === true;
  }

  return allDirs.indexOf(false) === -1;
};

/**
 * Uses native methods to return an object of dimension values.
 * @function
 * @param {jQuery || HTML} element - jQuery object or DOM element for which to get the dimensions. Can be any element other that document or window.
 * @returns {Object} - nested object of integer pixel values
 * TODO - if element is window, return only those values.
 */
function GetDimensions(elem, test){
  elem = elem.length ? elem[0] : elem;

  if (elem === window || elem === document) {
    throw new Error("I'm sorry, Dave. I'm afraid I can't do that.");
  }

  var rect = elem.getBoundingClientRect(),
      parRect = elem.parentNode.getBoundingClientRect(),
      winRect = document.body.getBoundingClientRect(),
      winY = window.pageYOffset,
      winX = window.pageXOffset;

  return {
    width: rect.width,
    height: rect.height,
    offset: {
      top: rect.top + winY,
      left: rect.left + winX
    },
    parentDims: {
      width: parRect.width,
      height: parRect.height,
      offset: {
        top: parRect.top + winY,
        left: parRect.left + winX
      }
    },
    windowDims: {
      width: winRect.width,
      height: winRect.height,
      offset: {
        top: winY,
        left: winX
      }
    }
  }
}

/**
 * Returns an object of top and left integer pixel values for dynamically rendered elements,
 * such as: Tooltip, Reveal, and Dropdown
 * @function
 * @param {jQuery} element - jQuery object for the element being positioned.
 * @param {jQuery} anchor - jQuery object for the element's anchor point.
 * @param {String} position - a string relating to the desired position of the element, relative to it's anchor
 * @param {Number} vOffset - integer pixel value of desired vertical separation between anchor and element.
 * @param {Number} hOffset - integer pixel value of desired horizontal separation between anchor and element.
 * @param {Boolean} isOverflow - if a collision event is detected, sets to true to default the element to full width - any desired offset.
 * TODO alter/rewrite to work with `em` values as well/instead of pixels
 */
function GetOffsets(element, anchor, position, vOffset, hOffset, isOverflow) {
  var $eleDims = GetDimensions(element),
      $anchorDims = anchor ? GetDimensions(anchor) : null;

  switch (position) {
    case 'top':
      return {
        left: (Foundation.rtl() ? $anchorDims.offset.left - $eleDims.width + $anchorDims.width : $anchorDims.offset.left),
        top: $anchorDims.offset.top - ($eleDims.height + vOffset)
      }
      break;
    case 'left':
      return {
        left: $anchorDims.offset.left - ($eleDims.width + hOffset),
        top: $anchorDims.offset.top
      }
      break;
    case 'right':
      return {
        left: $anchorDims.offset.left + $anchorDims.width + hOffset,
        top: $anchorDims.offset.top
      }
      break;
    case 'center top':
      return {
        left: ($anchorDims.offset.left + ($anchorDims.width / 2)) - ($eleDims.width / 2),
        top: $anchorDims.offset.top - ($eleDims.height + vOffset)
      }
      break;
    case 'center bottom':
      return {
        left: isOverflow ? hOffset : (($anchorDims.offset.left + ($anchorDims.width / 2)) - ($eleDims.width / 2)),
        top: $anchorDims.offset.top + $anchorDims.height + vOffset
      }
      break;
    case 'center left':
      return {
        left: $anchorDims.offset.left - ($eleDims.width + hOffset),
        top: ($anchorDims.offset.top + ($anchorDims.height / 2)) - ($eleDims.height / 2)
      }
      break;
    case 'center right':
      return {
        left: $anchorDims.offset.left + $anchorDims.width + hOffset + 1,
        top: ($anchorDims.offset.top + ($anchorDims.height / 2)) - ($eleDims.height / 2)
      }
      break;
    case 'center':
      return {
        left: ($eleDims.windowDims.offset.left + ($eleDims.windowDims.width / 2)) - ($eleDims.width / 2),
        top: ($eleDims.windowDims.offset.top + ($eleDims.windowDims.height / 2)) - ($eleDims.height / 2)
      }
      break;
    case 'reveal':
      return {
        left: ($eleDims.windowDims.width - $eleDims.width) / 2,
        top: $eleDims.windowDims.offset.top + vOffset
      }
    case 'reveal full':
      return {
        left: $eleDims.windowDims.offset.left,
        top: $eleDims.windowDims.offset.top
      }
      break;
    default:
      return {
        left: (Foundation.rtl() ? $anchorDims.offset.left - $eleDims.width + $anchorDims.width : $anchorDims.offset.left),
        top: $anchorDims.offset.top + $anchorDims.height + vOffset
      }
  }
}

}(jQuery);
<|endoftext|>


<commit_before>var util = require('util');
var Readable = require('stream').Readable;

var test = require('tape');

var LogicFilter = require('../index');

var TestStream = function() {
  Readable.call(this, {objectMode: true});
};
util.inherits(TestStream, Readable);

TestStream.prototype._read = function() {
};

test('test simple rule', function(t) {
  var r = new TestStream,
      lf = new LogicFilter(),
      counter = 0;

  lf.add('simpleRule1', {'foo': 'bar'});

  lf.on('data', function(obj) {
    counter++;
  });

  lf.on('end', function() {
    t.equal(counter, 2, '2 objects passed through the filter');
    t.end();
  });

  r.pipe(lf);

  r.push({'foo': 'bar'});
  r.push({'foo': 'baz'});
  r.push({'foo': 'qux'});
  r.push({'foo': 'bar'});
  r.push({'bar': 'foo'});
  r.push(null);
});

test('test and rule', function(t) {
  var r = new TestStream,
      lf = new LogicFilter(),
      counter = 0;

  lf.add('simpleRule1', {
    and: {
      'foo': 'bar',
      'bar': 'qux'
    }
  });

  lf.on('data', function(obj) {
    counter++;
  });

  lf.on('end', function() {
    t.equal(counter, 2, '2 objects passed through the filter');
    t.end();
  });

  r.pipe(lf);

  r.push({'foo': 'bar', 'bar': 'qux'});
  r.push({'foo': 'baz', 'bar': 'foo'});
  r.push({'foo': 'qux', 'baz': 'qux'});
  r.push({'foo': 'bar', 'bar': 'qux'});
  r.push({'bar': 'foo', 'qux': 'bar'});
  r.push(null);
});
<commit_msg>fix(tests): Write directly to the logic filter instead of creating an extra stream to pipe from.<commit_after>var test = require('tape');

var LogicFilter = require('../index');

test('test simple rule', function(t) {
  var lf = new LogicFilter(),
      counter = 0;

  lf.add('simpleRule1', {'foo': 'bar'});

  lf.on('data', function(obj) {
    counter++;
  });

  lf.on('end', function() {
    t.equal(counter, 2, '2 objects passed through the filter');
    t.end();
  });

  lf.write({'foo': 'bar'});
  lf.write({'foo': 'baz'});
  lf.write({'foo': 'qux'});
  lf.write({'foo': 'bar'});
  lf.write({'bar': 'foo'});
  lf.end();
});

test('test and rule', function(t) {
  var lf = new LogicFilter(),
      counter = 0;

  lf.add('simpleRule1', {
    and: {
      'foo': 'bar',
      'bar': 'qux'
    }
  });

  lf.on('data', function(obj) {
    counter++;
  });

  lf.on('end', function() {
    t.equal(counter, 2, '2 objects passed through the filter');
    t.end();
  });

  lf.write({'foo': 'bar', 'bar': 'qux'});
  lf.write({'foo': 'baz', 'bar': 'foo'});
  lf.write({'foo': 'qux', 'baz': 'qux'});
  lf.write({'foo': 'bar', 'bar': 'qux'});
  lf.write({'bar': 'foo', 'qux': 'bar'});
  lf.end();
});
<|endoftext|>