<commit_before>'use strict';

var emitter = require('contra/emitter');
var crossvent = require('crossvent');

function dragula (initialContainers, options) {
  var len = arguments.length;
  if (len === 1 && Array.isArray(initialContainers) === false) {
    options = initialContainers;
    initialContainers = [];
  }
  var body = document.body;
  var documentElement = document.documentElement;
  var _mirror; // mirror image
  var _source; // source container
  var _item; // item being dragged
  var _offsetX; // reference x
  var _offsetY; // reference y
  var _clientX; // cache client x, init at grab, update at drag
  var _clientY; // cache client y, init at grab, update at drag
  var _initialSibling; // reference sibling when grabbed
  var _currentSibling; // reference sibling now
  var _copy; // item used for copying
  var _renderTimer; // timer for setTimeout renderMirrorImage

  var o = options || {};
  if (o.moves === void 0) { o.moves = always; }
  if (o.accepts === void 0) { o.accepts = always; }
  if (o.invalid === void 0) { o.invalid = invalidTarget; }
  if (o.containers === void 0) { o.containers = initialContainers || []; }
  if (o.isContainer === void 0) { o.isContainer = never; }
  if (o.copy === void 0) { o.copy = false; }
  if (o.revertOnSpill === void 0) { o.revertOnSpill = false; }
  if (o.removeOnSpill === void 0) { o.removeOnSpill = false; }
  if (o.direction === void 0) { o.direction = 'vertical'; }
  if (o.delay === void 0) { o.delay = false; }
  if (o.delay === true) { o.delay = 300; }

  var api = emitter({
    containers: o.containers,
    addContainer: addContainer,
    removeContainer: removeContainer,
    start: start,
    end: end,
    cancel: cancel,
    remove: remove,
    destroy: destroy,
    dragging: false
  });

  events();

  return api;

  function addContainer (all) {
    var changes = Array.isArray(all) ? all : [all];
    api.containers = api.containers.concat(changes);
    console.warn && console.warn('drake.addContainer is deprecated. please access drake.containers directly, instead');
  }
  function removeContainer (all) {
    var changes = Array.isArray(all) ? all : [all];
    api.containers = api.containers.filter(keepable);
    console.warn && console.warn('drake.removeContainer is deprecated. please access drake.containers directly, instead');
    function keepable (container) {
      return changes.indexOf(container) === -1;
    }
  }

  function isContainer (el) {
    return api.containers.indexOf(el) !== -1 || o.isContainer(el);
  }

  function events (remove) {
    var op = remove ? 'remove' : 'add';
    touchy(documentElement, op, 'mousedown', grab);
    touchy(documentElement, op, 'mouseup', release);
  }

  function destroy () {
    events(true);
    release({});
  }

  function grab (e) {
    var item = e.target;
    var ignore = (e.which !== 0 && e.which !== 1) || e.metaKey || e.ctrlKey;
    if (ignore) {
      return; // we only care about honest-to-god left clicks and touch events
    }
    if (start(item) !== true) {
      return;
    }

    var offset = getOffset(_item);
    _offsetX = getCoord('pageX', e) - offset.left;
    _offsetY = getCoord('pageY', e) - offset.top;
    _clientX = getCoord('clientX', e);
    _clientY = getCoord('clientY', e);

    if (typeof o.delay === 'number') {
      _renderTimer = setTimeout(renderMirrorAndDrag, o.delay);
    } else {
      renderMirrorAndDrag();
    }
    e.preventDefault();
  }

  function renderMirrorAndDrag () {
    addClass(_copy || _item, 'gu-transit');
    renderMirrorImage();
    drag();
  }

  function start (item) {
    var handle = item;

    if (api.dragging && _mirror) {
      return;
    }

    if (isContainer(item)) {
      return; // don't drag container itself
    }
    while (item.parentElement && isContainer(item.parentElement) === false) {
      if (o.invalid(item, handle)) {
        return;
      }
      item = item.parentElement; // drag target should be a top element
      if (!item) {
        return;
      }
    }
    var container = item.parentElement;
    if (!container) {
      return;
    }
    if (o.invalid(item, handle)) {
      return;
    }

    var movable = o.moves(item, container, handle);
    if (!movable) {
      return;
    }

    end();

    if (o.copy) {
      _copy = item.cloneNode(true);
      api.emit('cloned', _copy, item);
    }

    _source = container;
    _item = item;
    _initialSibling = _currentSibling = nextEl(item);

    api.dragging = true;
    api.emit('drag', _item, _source);

    return true;
  }

  function invalidTarget (el) {
    return el.tagName === 'A' || el.tagName === 'BUTTON';
  }

  function end () {
    if (!api.dragging) {
      return;
    }
    var item = _copy || _item;
    drop(item, item.parentElement);
  }

  function release (e) {
    if (!api.dragging) {
      return;
    }

    var item = _copy || _item;
    var clientX = getCoord('clientX', e);
    var clientY = getCoord('clientY', e);
    var elementBehindCursor = getElementBehindPoint(_mirror, clientX, clientY);
    var dropTarget = findDropTarget(elementBehindCursor, clientX, clientY);
    if (dropTarget && (o.copy === false || dropTarget !== _source)) {
      drop(item, dropTarget);
    } else if (o.removeOnSpill) {
      remove();
    } else {
      cancel();
    }
  }

  function drop (item, target) {
    if (isInitialPlacement(target)) {
      api.emit('cancel', item, _source);
    } else {
      api.emit('drop', item, target, _source);
    }
    cleanup();
  }

  function remove () {
    if (!api.dragging) {
      return;
    }
    var item = _copy || _item;
    var parent = item.parentElement;
    if (parent) {
      parent.removeChild(item);
    }
    api.emit(o.copy ? 'cancel' : 'remove', item, parent);
    cleanup();
  }

  function cancel (revert) {
    if (!api.dragging) {
      return;
    }
    var reverts = arguments.length > 0 ? revert : o.revertOnSpill;
    var item = _copy || _item;
    var parent = item.parentElement;
    if (parent === _source && o.copy) {
      parent.removeChild(_copy);
    }
    var initial = isInitialPlacement(parent);
    if (initial === false && o.copy === false && reverts) {
      _source.insertBefore(item, _initialSibling);
    }
    if (initial || reverts) {
      api.emit('cancel', item, _source);
    } else {
      api.emit('drop', item, parent, _source);
    }
    cleanup();
  }

  function cleanup () {
    var item = _copy || _item;
    removeMirrorImage();
    if (item) {
      rmClass(item, 'gu-transit');
    }
    if (_renderTimer) {
      clearTimeout(_renderTimer);
    }
    _source = _item = _copy = _initialSibling = _currentSibling = _renderTimer = null;
    api.dragging = false;
    api.emit('dragend', item);
  }

  function isInitialPlacement (target, s) {
    var sibling;
    if (s !== void 0) {
      sibling = s;
    } else if (_mirror) {
      sibling = _currentSibling;
    } else {
      sibling = nextEl(_item || _copy);
    }
    return target === _source && sibling === _initialSibling;
  }

  function findDropTarget (elementBehindCursor, clientX, clientY) {
    var target = elementBehindCursor;
    while (target && !accepted()) {
      target = target.parentElement;
    }
    return target;

    function accepted () {
      var droppable = isContainer(target);
      if (droppable === false) {
        return false;
      }

      var immediate = getImmediateChild(target, elementBehindCursor);
      var reference = getReference(target, immediate, clientX, clientY);
      var initial = isInitialPlacement(target, reference);
      if (initial) {
        return true; // should always be able to drop it right back where it was
      }
      return o.accepts(_item, target, _source, reference);
    }
  }

  function drag (e) {
    if (!_mirror) {
      return;
    }
    if (e) {
      _clientX = getCoord('clientX', e);
      _clientY = getCoord('clientY', e);
    }
    var x = _clientX - _offsetX;
    var y = _clientY - _offsetY;

    _mirror.style.left = x + 'px';
    _mirror.style.top  = y + 'px';

    var item = _copy || _item;
    var elementBehindCursor = getElementBehindPoint(_mirror, _clientX, _clientY);
    var dropTarget = findDropTarget(elementBehindCursor, _clientX, _clientY);
    if (dropTarget === _source && o.copy) {
      if (item.parentElement) {
        item.parentElement.removeChild(item);
      }
      return;
    }
    var reference;
    var immediate = getImmediateChild(dropTarget, elementBehindCursor);
    if (immediate !== null) {
      reference = getReference(dropTarget, immediate, _clientX, _clientY);
    } else if (o.revertOnSpill === true && !o.copy) {
      reference = _initialSibling;
      dropTarget = _source;
    } else {
      if ((o.copy || o.removeOnSpill === true) && item.parentElement !== null) {
        item.parentElement.removeChild(item);
      }
      return;
    }
    if (reference === null || reference !== item && reference !== nextEl(item)) {
      _currentSibling = reference;
      dropTarget.insertBefore(item, reference);
      api.emit('shadow', item, dropTarget);
    }
  }

  function renderMirrorImage () {
    if (_mirror) {
      return;
    }
    var rect = _item.getBoundingClientRect();
    _mirror = _item.cloneNode(true);
    _mirror.style.width = getRectWidth(rect) + 'px';
    _mirror.style.height = getRectHeight(rect) + 'px';
    rmClass(_mirror, 'gu-transit');
    addClass(_mirror, ' gu-mirror');
    body.appendChild(_mirror);
    touchy(documentElement, 'add', 'mousemove', drag);
    addClass(body, 'gu-unselectable');
    api.emit('cloned', _mirror, _item);
  }

  function removeMirrorImage () {
    if (_mirror) {
      rmClass(body, 'gu-unselectable');
      touchy(documentElement, 'remove', 'mousemove', drag);
      _mirror.parentElement.removeChild(_mirror);
      _mirror = null;
    }
  }

  function getImmediateChild (dropTarget, target) {
    var immediate = target;
    while (immediate !== dropTarget && immediate.parentElement !== dropTarget) {
      immediate = immediate.parentElement;
    }
    if (immediate === documentElement) {
      return null;
    }
    return immediate;
  }

  function getReference (dropTarget, target, x, y) {
    var horizontal = o.direction === 'horizontal';
    var reference = target !== dropTarget ? inside() : outside();
    return reference;

    function outside () { // slower, but able to figure out any position
      var len = dropTarget.children.length;
      var i;
      var el;
      var rect;
      for (i = 0; i < len; i++) {
        el = dropTarget.children[i];
        rect = el.getBoundingClientRect();
        if (horizontal && rect.left > x) { return el; }
        if (!horizontal && rect.top > y) { return el; }
      }
      return null;
    }

    function inside () { // faster, but only available if dropped inside a child element
      var rect = target.getBoundingClientRect();
      if (horizontal) {
        return resolve(x > rect.left + getRectWidth(rect) / 2);
      }
      return resolve(y > rect.top + getRectHeight(rect) / 2);
    }

    function resolve (after) {
      return after ? nextEl(target) : target;
    }
  }
}

function touchy (el, op, type, fn) {
  var touch = {
    mouseup: 'touchend',
    mousedown: 'touchstart',
    mousemove: 'touchmove'
  };
  var microsoft = {
    mouseup: 'MSPointerUp',
    mousedown: 'MSPointerDown',
    mousemove: 'MSPointerMove'
  };
  if (global.navigator.msPointerEnabled) {
    crossvent[op](el, microsoft[type], fn);
  }
  crossvent[op](el, touch[type], fn);
  crossvent[op](el, type, fn);
}

function getOffset (el) {
  var rect = el.getBoundingClientRect();
  return {
    left: rect.left + getScroll('scrollLeft', 'pageXOffset'),
    top: rect.top + getScroll('scrollTop', 'pageYOffset')
  };
}

function getScroll (scrollProp, offsetProp) {
  if (typeof global[offsetProp] !== 'undefined') {
    return global[offsetProp];
  }
  var documentElement = document.documentElement;
  if (documentElement.clientHeight) {
    return documentElement[scrollProp];
  }
  var body = document.body;
  return body[scrollProp];
}

function getElementBehindPoint (point, x, y) {
  if (!x && !y) {
    return null;
  }
  var p = point || {};
  var state = p.className;
  var el;
  p.className += ' gu-hide';
  el = document.elementFromPoint(x, y);
  p.className = state;
  return el;
}

function never () {
  return false;
}

function always () {
  return true;
}

function nextEl (el) {
  return el.nextElementSibling || manually();
  function manually () {
    var sibling = el;
    do {
      sibling = sibling.nextSibling;
    } while (sibling && sibling.nodeType !== 1);
    return sibling;
  }
}

function addClass (el, className) {
  if (el.className.indexOf(' ' + className) === -1) {
    el.className += ' ' + className;
  }
}

function rmClass (el, className) {
  el.className = el.className.replace(new RegExp(' ' + className, 'g'), '');
}

function getEventHost (e) {
  // on touchend event, we have to use `e.changedTouches`
  // see http://stackoverflow.com/questions/7192563/touchend-event-properties
  // see https://github.com/bevacqua/dragula/issues/34
  if (e.targetTouches && e.targetTouches.length) {
    return e.targetTouches[0];
  }
  if (e.changedTouches && e.changedTouches.length) {
    return e.changedTouches[0];
  }
  return e;
}

function getCoord (coord, e) {
  var host = getEventHost(e);
  var missMap = {
    pageX: 'clientX', // IE8
    pageY: 'clientY' // IE8
  };
  if (coord in missMap && !(coord in host) && missMap[coord] in host) {
    coord = missMap[coord];
  }
  return host[coord];
}

function getRectWidth (rect) {
  return rect.width || (rect.right - rect.left);
}

function getRectHeight (rect) {
  return rect.height || (rect.bottom - rect.top);
}

module.exports = dragula;
<commit_msg>Added copy option as polymorphic option, accepts boolean and function<commit_after>'use strict';

var emitter = require('contra/emitter');
var crossvent = require('crossvent');

function dragula (initialContainers, options) {
  var len = arguments.length;
  if (len === 1 && Array.isArray(initialContainers) === false) {
    options = initialContainers;
    initialContainers = [];
  }
  var body = document.body;
  var documentElement = document.documentElement;
  var _mirror; // mirror image
  var _source; // source container
  var _item; // item being dragged
  var _offsetX; // reference x
  var _offsetY; // reference y
  var _clientX; // cache client x, init at grab, update at drag
  var _clientY; // cache client y, init at grab, update at drag
  var _initialSibling; // reference sibling when grabbed
  var _currentSibling; // reference sibling now
  var _copy; // item used for copying
  var _renderTimer; // timer for setTimeout renderMirrorImage

  var o = options || {};
  if (o.moves === void 0) { o.moves = always; }
  if (o.accepts === void 0) { o.accepts = always; }
  if (o.invalid === void 0) { o.invalid = invalidTarget; }
  if (o.containers === void 0) { o.containers = initialContainers || []; }
  if (o.isContainer === void 0) { o.isContainer = never; }
  if (o.copy === void 0) { o.copy = false; }
  if (o.revertOnSpill === void 0) { o.revertOnSpill = false; }
  if (o.removeOnSpill === void 0) { o.removeOnSpill = false; }
  if (o.direction === void 0) { o.direction = 'vertical'; }
  if (o.delay === void 0) { o.delay = false; }
  if (o.delay === true) { o.delay = 300; }

  var api = emitter({
    containers: o.containers,
    addContainer: addContainer,
    removeContainer: removeContainer,
    start: start,
    end: end,
    cancel: cancel,
    remove: remove,
    destroy: destroy,
    dragging: false
  });

  events();

  return api;

  function addContainer (all) {
    var changes = Array.isArray(all) ? all : [all];
    api.containers = api.containers.concat(changes);
    console.warn && console.warn('drake.addContainer is deprecated. please access drake.containers directly, instead');
  }
  function removeContainer (all) {
    var changes = Array.isArray(all) ? all : [all];
    api.containers = api.containers.filter(keepable);
    console.warn && console.warn('drake.removeContainer is deprecated. please access drake.containers directly, instead');
    function keepable (container) {
      return changes.indexOf(container) === -1;
    }
  }

  function isContainer (el) {
    return api.containers.indexOf(el) !== -1 || o.isContainer(el);
  }

  function events (remove) {
    var op = remove ? 'remove' : 'add';
    touchy(documentElement, op, 'mousedown', grab);
    touchy(documentElement, op, 'mouseup', release);
  }

  function destroy () {
    events(true);
    release({});
  }

  function grab (e) {
    var item = e.target;
    var ignore = (e.which !== 0 && e.which !== 1) || e.metaKey || e.ctrlKey;
    if (ignore) {
      return; // we only care about honest-to-god left clicks and touch events
    }
    if (start(item) !== true) {
      return;
    }

    var offset = getOffset(_item);
    _offsetX = getCoord('pageX', e) - offset.left;
    _offsetY = getCoord('pageY', e) - offset.top;
    _clientX = getCoord('clientX', e);
    _clientY = getCoord('clientY', e);

    if (typeof o.delay === 'number') {
      _renderTimer = setTimeout(renderMirrorAndDrag, o.delay);
    } else {
      renderMirrorAndDrag();
    }
    e.preventDefault();
  }

  function renderMirrorAndDrag () {
    addClass(_copy || _item, 'gu-transit');
    renderMirrorImage();
    drag();
  }

  function start (item) {
    var handle = item;

    if (api.dragging && _mirror) {
      return;
    }

    if (isContainer(item)) {
      return; // don't drag container itself
    }
    while (item.parentElement && isContainer(item.parentElement) === false) {
      if (o.invalid(item, handle)) {
        return;
      }
      item = item.parentElement; // drag target should be a top element
      if (!item) {
        return;
      }
    }
    var container = item.parentElement;
    if (!container) {
      return;
    }
    if (o.invalid(item, handle)) {
      return;
    }

    var movable = o.moves(item, container, handle);
    if (!movable) {
      return;
    }

    end();

    if (isCopy(o, item, container)) {
      _copy = item.cloneNode(true);
      api.emit('cloned', _copy, item);
    }

    _source = container;
    _item = item;
    _initialSibling = _currentSibling = nextEl(item);

    api.dragging = true;
    api.emit('drag', _item, _source);

    return true;
  }

  function invalidTarget (el) {
    return el.tagName === 'A' || el.tagName === 'BUTTON';
  }

  function end () {
    if (!api.dragging) {
      return;
    }
    var item = _copy || _item;
    drop(item, item.parentElement);
  }

  function release (e) {
    if (!api.dragging) {
      return;
    }

    var item = _copy || _item;
    var clientX = getCoord('clientX', e);
    var clientY = getCoord('clientY', e);
    var elementBehindCursor = getElementBehindPoint(_mirror, clientX, clientY);
    var dropTarget = findDropTarget(elementBehindCursor, clientX, clientY);
    if (dropTarget && (isCopy(o, item, null, dropTarget) === false || dropTarget !== _source)) {
      drop(item, dropTarget);
    } else if (o.removeOnSpill) {
      remove();
    } else {
      cancel();
    }
  }

  function drop (item, target) {
    if (isInitialPlacement(target)) {
      api.emit('cancel', item, _source);
    } else {
      api.emit('drop', item, target, _source);
    }
    cleanup();
  }

  function remove () {
    if (!api.dragging) {
      return;
    }
    var item = _copy || _item;
    var parent = item.parentElement;
    if (parent) {
      parent.removeChild(item);
    }
    api.emit(isCopy(o, item) ? 'cancel' : 'remove', item, parent);
    cleanup();
  }

  function cancel (revert) {
    if (!api.dragging) {
      return;
    }
    var reverts = arguments.length > 0 ? revert : o.revertOnSpill;
    var item = _copy || _item;
    var parent = item.parentElement;
    if (parent === _source && isCopy(o, item)) {
      parent.removeChild(_copy);
    }
    var initial = isInitialPlacement(parent);
    if (initial === false && isCopy(o, item) === false && reverts) {
      _source.insertBefore(item, _initialSibling);
    }
    if (initial || reverts) {
      api.emit('cancel', item, _source);
    } else {
      api.emit('drop', item, parent, _source);
    }
    cleanup();
  }

  function cleanup () {
    var item = _copy || _item;
    removeMirrorImage();
    if (item) {
      rmClass(item, 'gu-transit');
    }
    if (_renderTimer) {
      clearTimeout(_renderTimer);
    }
    _source = _item = _copy = _initialSibling = _currentSibling = _renderTimer = null;
    api.dragging = false;
    api.emit('dragend', item);
  }

  function isInitialPlacement (target, s) {
    var sibling;
    if (s !== void 0) {
      sibling = s;
    } else if (_mirror) {
      sibling = _currentSibling;
    } else {
      sibling = nextEl(_item || _copy);
    }
    return target === _source && sibling === _initialSibling;
  }

  function findDropTarget (elementBehindCursor, clientX, clientY) {
    var target = elementBehindCursor;
    while (target && !accepted()) {
      target = target.parentElement;
    }
    return target;

    function accepted () {
      var droppable = isContainer(target);
      if (droppable === false) {
        return false;
      }

      var immediate = getImmediateChild(target, elementBehindCursor);
      var reference = getReference(target, immediate, clientX, clientY);
      var initial = isInitialPlacement(target, reference);
      if (initial) {
        return true; // should always be able to drop it right back where it was
      }
      return o.accepts(_item, target, _source, reference);
    }
  }

  function drag (e) {
    if (!_mirror) {
      return;
    }
    if (e) {
      _clientX = getCoord('clientX', e);
      _clientY = getCoord('clientY', e);
    }
    var x = _clientX - _offsetX;
    var y = _clientY - _offsetY;

    _mirror.style.left = x + 'px';
    _mirror.style.top  = y + 'px';

    var item = _copy || _item;
    var elementBehindCursor = getElementBehindPoint(_mirror, _clientX, _clientY);
    var dropTarget = findDropTarget(elementBehindCursor, _clientX, _clientY);
    if (dropTarget === _source && isCopy(o, item, dropTarget)) {
      if (item.parentElement) {
        item.parentElement.removeChild(item);
      }
      return;
    }
    var reference;
    var immediate = getImmediateChild(dropTarget, elementBehindCursor);
    if (immediate !== null) {
      reference = getReference(dropTarget, immediate, _clientX, _clientY);
    } else if (o.revertOnSpill === true && !isCopy(o)) {
      reference = _initialSibling;
      dropTarget = _source;
    } else {
      if ((isCopy(o) || o.removeOnSpill === true) && item.parentElement !== null) {
        item.parentElement.removeChild(item);
      }
      return;
    }
    if (reference === null || reference !== item && reference !== nextEl(item)) {
      _currentSibling = reference;
      dropTarget.insertBefore(item, reference);
      api.emit('shadow', item, dropTarget);
    }
  }

  function renderMirrorImage () {
    if (_mirror) {
      return;
    }
    var rect = _item.getBoundingClientRect();
    _mirror = _item.cloneNode(true);
    _mirror.style.width = getRectWidth(rect) + 'px';
    _mirror.style.height = getRectHeight(rect) + 'px';
    rmClass(_mirror, 'gu-transit');
    addClass(_mirror, ' gu-mirror');
    body.appendChild(_mirror);
    touchy(documentElement, 'add', 'mousemove', drag);
    addClass(body, 'gu-unselectable');
    api.emit('cloned', _mirror, _item);
  }

  function removeMirrorImage () {
    if (_mirror) {
      rmClass(body, 'gu-unselectable');
      touchy(documentElement, 'remove', 'mousemove', drag);
      _mirror.parentElement.removeChild(_mirror);
      _mirror = null;
    }
  }

  function getImmediateChild (dropTarget, target) {
    var immediate = target;
    while (immediate !== dropTarget && immediate.parentElement !== dropTarget) {
      immediate = immediate.parentElement;
    }
    if (immediate === documentElement) {
      return null;
    }
    return immediate;
  }

  function getReference (dropTarget, target, x, y) {
    var horizontal = o.direction === 'horizontal';
    var reference = target !== dropTarget ? inside() : outside();
    return reference;

    function outside () { // slower, but able to figure out any position
      var len = dropTarget.children.length;
      var i;
      var el;
      var rect;
      for (i = 0; i < len; i++) {
        el = dropTarget.children[i];
        rect = el.getBoundingClientRect();
        if (horizontal && rect.left > x) { return el; }
        if (!horizontal && rect.top > y) { return el; }
      }
      return null;
    }

    function inside () { // faster, but only available if dropped inside a child element
      var rect = target.getBoundingClientRect();
      if (horizontal) {
        return resolve(x > rect.left + getRectWidth(rect) / 2);
      }
      return resolve(y > rect.top + getRectHeight(rect) / 2);
    }

    function resolve (after) {
      return after ? nextEl(target) : target;
    }
  }
}

function touchy (el, op, type, fn) {
  var touch = {
    mouseup: 'touchend',
    mousedown: 'touchstart',
    mousemove: 'touchmove'
  };
  var microsoft = {
    mouseup: 'MSPointerUp',
    mousedown: 'MSPointerDown',
    mousemove: 'MSPointerMove'
  };
  if (global.navigator.msPointerEnabled) {
    crossvent[op](el, microsoft[type], fn);
  }
  crossvent[op](el, touch[type], fn);
  crossvent[op](el, type, fn);
}

function getOffset (el) {
  var rect = el.getBoundingClientRect();
  return {
    left: rect.left + getScroll('scrollLeft', 'pageXOffset'),
    top: rect.top + getScroll('scrollTop', 'pageYOffset')
  };
}

function getScroll (scrollProp, offsetProp) {
  if (typeof global[offsetProp] !== 'undefined') {
    return global[offsetProp];
  }
  var documentElement = document.documentElement;
  if (documentElement.clientHeight) {
    return documentElement[scrollProp];
  }
  var body = document.body;
  return body[scrollProp];
}

function getElementBehindPoint (point, x, y) {
  if (!x && !y) {
    return null;
  }
  var p = point || {};
  var state = p.className;
  var el;
  p.className += ' gu-hide';
  el = document.elementFromPoint(x, y);
  p.className = state;
  return el;
}

function never () {
  return false;
}

function always () {
  return true;
}

function nextEl (el) {
  return el.nextElementSibling || manually();
  function manually () {
    var sibling = el;
    do {
      sibling = sibling.nextSibling;
    } while (sibling && sibling.nodeType !== 1);
    return sibling;
  }
}

function addClass (el, className) {
  if (el.className.indexOf(' ' + className) === -1) {
    el.className += ' ' + className;
  }
}

function rmClass (el, className) {
  el.className = el.className.replace(new RegExp(' ' + className, 'g'), '');
}

function getEventHost (e) {
  // on touchend event, we have to use `e.changedTouches`
  // see http://stackoverflow.com/questions/7192563/touchend-event-properties
  // see https://github.com/bevacqua/dragula/issues/34
  if (e.targetTouches && e.targetTouches.length) {
    return e.targetTouches[0];
  }
  if (e.changedTouches && e.changedTouches.length) {
    return e.changedTouches[0];
  }
  return e;
}

function getCoord (coord, e) {
  var host = getEventHost(e);
  var missMap = {
    pageX: 'clientX', // IE8
    pageY: 'clientY' // IE8
  };
  if (coord in missMap && !(coord in host) && missMap[coord] in host) {
    coord = missMap[coord];
  }
  return host[coord];
}

function getRectWidth (rect) {
  return rect.width || (rect.right - rect.left);
}

function getRectHeight (rect) {
  return rect.height || (rect.bottom - rect.top);
}

function isCopy (o, item, container, target) {
  if (typeof o.copy === 'boolean') {
    return o.copy;
  }
  return o.copy(item, container, target);
}

module.exports = dragula;
<|endoftext|>


<commit_before>/**
 * @license Copyright (c) 2010-2011 Brian Cavalier
 * LICENSE: see the LICENSE.txt file. If file is missing, this file is subject
 * to the MIT License at: http://www.opensource.org/licenses/mit-license.php.
 */

/*
	File: base.js
	Base wire plugin that provides properties, init, and destroy facets, and a
	proxy for plain JS objects.
*/
(function(define) {
define(['when'], function(when) {
	var tos, createObject;
	tos = Object.prototype.toString;

	// In case Object.create isn't available
	function T() {}

	function objectCreate(prototype) {
		T.prototype = prototype;
		return new T();
	}

	createObject = Object.create || objectCreate;

	function reject(resolver) {
		return function(err) {
			resolver.reject(err);
		};
	}

	function resolve(resolver) {
		return function(result) {
			resolver.resolve(result);
		};
	}

	function invoke(promise, func, target, args, wire) {
		var f, rejecter;

		f = target[func];

		rejecter = reject(promise);

		if(typeof f == 'function') {
			if(args) {
				wire(args).then(
					function(resolvedArgs) {
						try {
							var result = f.apply(target, (tos.call(resolvedArgs) == '[object Array]')
								? resolvedArgs
								: [resolvedArgs]);

							promise.resolve(result);
						} catch(e) {
							rejecter(e);
						}
					},
					rejecter
				);
			}
		}
	}

	function invokeAll(promise, facet, wire) {
		var target, options;

		target  = facet.target;
		options = facet.options;

		if(typeof options == 'string') {
			invoke(promise, options, target, [], wire);

		} else {
			var promises, p, func;
			promises = [];

			for(func in options) {
				p = when.defer();
				promises.push(p);
				invoke(p, func, target, options[func], wire);
			}

			when.all(promises, resolve(promise), reject(promise));
		}
	}

    /**
     * Factory that handles cases where you need to create an object literal
     * that has a property whose name would trigger another wire factory.
     * For example, if you need an object literal with a property named "create",
     * which would normally cause wire to try to construct an instance using
     * a constructor or other function, and will probably result in an error,
     * or an unexpected result:
     * myObject: {
     *      create: "foo"
     *    ...
     * }
     *
     * You can use the literal factory to force creation of an object literal:
     * myObject: {
     *    literal: {
     *      create: "foo"
     *    }
     * }
     *
     * which will result in myObject.create == "foo" rather than attempting
     * to create an instance of an AMD module whose id is "foo".
     */
	function literalFactory(promise, spec /*, wire */) {
		promise.resolve(spec.literal);
	}

	function protoFactory(resolver, spec, wire) {
		var parentRef, promise;

        parentRef = spec.prototype;

        promise = typeof parentRef === 'string'
                ? wire.resolveRef(parentRef)
                : wire(parentRef);

        when(promise,
			function(parent) {
				var child = createObject(parent);
				resolver.resolve(child);
			},
			reject(resolver)
		);
	}

	function propertiesFacet(promise, facet, wire) {
		var options, promises, prop;
		promises = [];
		options = facet.options;

		for(prop in options) {
			promises.push(setProperty(facet, prop, options[prop], wire));
		}

        when.all(promises, resolve(promise), reject(promise));
	}

	function setProperty(proxy, name, val, wire) {
		var promise = wire(val, name, proxy.path);

		when(promise, function(resolvedValue) {
			proxy.set(name, resolvedValue);
		});

		return promise;
	}

	function initFacet(promise, facet, wire) {
		invokeAll(promise, facet, wire);
	}

	function pojoProxy(object /*, spec */) {
		return {
			get: function(property) {
				return object[property];
			},
			set: function(property, value) {
				object[property] = value;
				return value;
			},
			invoke: function(method, args) {
				if(typeof method === 'string') {
					method = object[method];
				}

				return method.apply(object, args);
			},
			destroy: function() {}
		};
	}

	return {
		wire$plugin: function(ready, destroyed /*, options */) {
            // Components in the current context that will be destroyed
            // when this context is destroyed
			var destroyFuncs = [];

			when(destroyed, function() {
				for(var i = 0, destroy; (destroy = destroyFuncs[i++]);) {
					destroy();
				}
				destroyFuncs = [];
			});

			function destroyFacet(promise, facet, wire) {
				promise.resolve();

				var target, options, w;

				target = facet.target;
				options = facet.options;
				w = wire;

				destroyFuncs.push(function destroyObject() {
					invokeAll(when.defer(), { options: options, target: target }, w);
				});
			}

			return {
				factories: {
					literal: literalFactory,
					prototype: protoFactory
				},
				facets: {
					// properties facet.  Sets properties on components
					// after creation.
					properties: {
						configure: propertiesFacet
					},
					// init facet.  Invokes methods on components after
					// they have been configured
					init: {
						initialize: initFacet
					},
					// destroy facet.  Registers methods to be invoked
					// on components when the enclosing context is destroyed
					destroy: {
						ready: destroyFacet
					}
				},
				proxies: [
					pojoProxy
				]
			};
		}
	};
});
})(typeof define != 'undefined'
	// use define for AMD if available
	? define
	// If no define or module, attach to current context.
	: function(deps, factory) { this.wire_base = factory(); }
);
<commit_msg>Promise streamlining in base plugin<commit_after>/**
 * @license Copyright (c) 2010-2011 Brian Cavalier
 * LICENSE: see the LICENSE.txt file. If file is missing, this file is subject
 * to the MIT License at: http://www.opensource.org/licenses/mit-license.php.
 */

/*
	File: base.js
	Base wire plugin that provides properties, init, and destroy facets, and a
	proxy for plain JS objects.
*/
(function(define) {
define(['when'], function(when) {
	var tos, createObject, whenAll, chain;
	tos = Object.prototype.toString;

    whenAll = when.all;
    chain = when.chain;

	// In case Object.create isn't available
	function T() {}

	function objectCreate(prototype) {
		T.prototype = prototype;
		return new T();
	}

	createObject = Object.create || objectCreate;

    function invoke(func, target, args, wire) {
        var f;

        f = target[func];

        return typeof f == 'function'
            ? when(wire(args),
                function (resolvedArgs) {
                    return f.apply(target, (tos.call(resolvedArgs) == '[object Array]')
                        ? resolvedArgs
                        : [resolvedArgs]);
                })
            : f;
    }

    function invokeAll(resolver, facet, wire) {
		var target, options;

		target  = facet.target;
		options = facet.options;

		if(typeof options == 'string') {
			chain(invoke(options, target, [], wire), resolver);

		} else {
			var promises, func;
			promises = [];

			for(func in options) {
				promises.push(invoke(func, target, options[func], wire));
			}

			whenAll(promises, resolver.resolve, resolver.reject);
		}
	}

    /**
     * Factory that handles cases where you need to create an object literal
     * that has a property whose name would trigger another wire factory.
     * For example, if you need an object literal with a property named "create",
     * which would normally cause wire to try to construct an instance using
     * a constructor or other function, and will probably result in an error,
     * or an unexpected result:
     * myObject: {
     *      create: "foo"
     *    ...
     * }
     *
     * You can use the literal factory to force creation of an object literal:
     * myObject: {
     *    literal: {
     *      create: "foo"
     *    }
     * }
     *
     * which will result in myObject.create == "foo" rather than attempting
     * to create an instance of an AMD module whose id is "foo".
     */
	function literalFactory(resolver, spec /*, wire */) {
		resolver.resolve(spec.literal);
	}

	function protoFactory(resolver, spec, wire) {
		var parentRef, promise;

        parentRef = spec.prototype;

        promise = typeof parentRef === 'string'
                ? wire.resolveRef(parentRef)
                : wire(parentRef);

        when(promise,
			function(parent) {
				var child = createObject(parent);
				resolver.resolve(child);
			},
            resolver.reject
		);
	}

	function propertiesFacet(resolver, facet, wire) {
		var options, promises, prop;
		promises = [];
		options = facet.options;

		for(prop in options) {
			promises.push(setProperty(facet, prop, options[prop], wire));
		}

        whenAll(promises, resolver.resolve, resolver.reject);
	}

	function setProperty(proxy, name, val, wire) {
        return when(wire(val, name, proxy.path),
            function(resolvedValue) {
			    proxy.set(name, resolvedValue);
		    }
        );
	}

	function initFacet(resolver, facet, wire) {
		invokeAll(resolver, facet, wire);
	}

	function pojoProxy(object /*, spec */) {
		return {
			get: function(property) {
				return object[property];
			},
			set: function(property, value) {
				object[property] = value;
				return value;
			},
			invoke: function(method, args) {
				if(typeof method === 'string') {
					method = object[method];
				}

				return method.apply(object, args);
			},
			destroy: function() {}
		};
	}

	return {
		wire$plugin: function(ready, destroyed /*, options */) {
            // Components in the current context that will be destroyed
            // when this context is destroyed
			var destroyFuncs = [];

			when(destroyed, function() {
				for(var i = 0, destroy; (destroy = destroyFuncs[i++]);) {
					destroy();
				}
				destroyFuncs = [];
			});

			function destroyFacet(promise, facet, wire) {
				promise.resolve();

				var target, options, w;

				target = facet.target;
				options = facet.options;
				w = wire;

				destroyFuncs.push(function destroyObject() {
					invokeAll(when.defer(), { options: options, target: target }, w);
				});
			}

			return {
				factories: {
					literal: literalFactory,
					prototype: protoFactory
				},
				facets: {
					// properties facet.  Sets properties on components
					// after creation.
					properties: {
						configure: propertiesFacet
					},
					// init facet.  Invokes methods on components after
					// they have been configured
					init: {
						initialize: initFacet
					},
					// destroy facet.  Registers methods to be invoked
					// on components when the enclosing context is destroyed
					destroy: {
						ready: destroyFacet
					}
				},
				proxies: [
					pojoProxy
				]
			};
		}
	};
});
})(typeof define != 'undefined'
	// use define for AMD if available
	? define
	// If no define or module, attach to current context.
	: function(deps, factory) { this.wire_base = factory(); }
);
<|endoftext|>


<commit_before>//
//  action types
//

export const REQUEST_BUS_STOPS_AROUND_ME = 'REQUEST_BUS_STOPS_AROUND_ME'

//
// other constants
//

export loadingState = false

//
//  action creators
//

export function requestBusStopsAroundMe(meters, coors) {
  return {
    type: REQUEST_BUS_STOPS_AROUND_ME,
    text: 'get all the routes and bus stops around user geolocalization',
    meters: meters,
    latitude: coors.laitude,
    longitude: coors.longitude
  }
}
<commit_msg>switch to ES6 syntax and add new helpers<commit_after>import { routeActions } from 'react-router-redux';
import fetch from 'isomorphic-fetch';

//
//  actions types
//

export const REQUEST_BUS_STOPS_AROUND_ME = 'REQUEST_BUS_STOPS_AROUND_ME'

//
//  actions helpers
//

function requestBusStopsAroundMe( coors, meters ) {
  fetch( 'secret-depths-4660.herokuapp/paradas?lt=' + coors.latitude + '&ln=' + coors.longitude + '&r=' + meters )
    .then( function(){
      dispatch( routeActions.push( '/loading' ) );
    })
    .then( function( response ) {
      if ( response.status >= 400 ) {
        dispatch( routeActions.push( '/errors' ) );
        return {
          meters: meters,
          coors: coors,
          busStops: {},
          error: {
            type: response.status,
            message: response.message
          }
        }
      }
      dispatch( routeActions.push( '/results' ) );
      return {
        meters: meters,
        coors: coors,
        busStops: response.json(),
        error: {}
      }
    })
}

//
//  actions creators
//

export function getBusStopsAroundMe( coors, meters ) {
  var busStopsApiResponse = requestBusStopsAroundMe( coors, meters );
  return {
    type: REQUEST_BUS_STOPS_AROUND_ME,
    busStopsAroundMe: busStopsApiResponse
  };
}
<|endoftext|>


<commit_before>/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
 * full list of contributors). Published under the Clear BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */

/**
 * @requires OpenLayers/BaseTypes/Class.js
 */

/**
 * Class: OpenLayers.Icon
 *
 * The icon represents a graphical icon on the screen.  Typically used in
 * conjunction with a <OpenLayers.Marker> to represent markers on a screen.
 *
 * An icon has a url, size and position.  It also contains an offset which
 * allows the center point to be represented correctly.  This can be
 * provided either as a fixed offset or a function provided to calculate
 * the desired offset.
 *
 */
OpenLayers.Icon = OpenLayers.Class({

    /**
     * Property: url
     * {String}  image url
     */
    url: null,

    /**
     * Property: size
     * {<OpenLayers.Size>|Object} An OpenLayers.Size or
     * an object with a 'w' and 'h' properties.
     */
    size: null,

    /**
     * Property: offset
     * {<OpenLayers.Pixel>|Object} distance in pixels to offset the
     * image when being rendered. An OpenLayers.Pixel or an object
     * with a 'x' and 'y' properties.
     */
    offset: null,

    /**
     * Property: calculateOffset
     * {Function} Function to calculate the offset (based on the size)
     */
    calculateOffset: null,

    /**
     * Property: imageDiv
     * {DOMElement}
     */
    imageDiv: null,

    /**
     * Property: px
     * {<OpenLayers.Pixel>}
     */
    px: null,

    /**
     * Constructor: OpenLayers.Icon
     * Creates an icon, which is an image tag in a div.
     *
     * url - {String}
     * size - {<OpenLayers.Size>|Object} An OpenLayers.Size or an
     *                                   object with a 'w' and 'h'
     *                                   properties.
     * offset - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or an
     *                                      object with a 'x' and 'y'
     *                                      properties.
     * calculateOffset - {Function}
     */
    initialize: function(url, size, offset, calculateOffset) {
        this.url = url;
        this.size = size || {w: 20, h: 20};
        this.offset = offset || {x: -(this.size.w/2), y: -(this.size.h/2)};
        this.calculateOffset = calculateOffset;

        var id = OpenLayers.Util.createUniqueID("OL_Icon_");
        this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id);
    },

    /**
     * Method: destroy
     * Nullify references and remove event listeners to prevent circular
     * references and memory leaks
     */
    destroy: function() {
        // erase any drawn elements
        this.erase();

        OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);
        this.imageDiv.innerHTML = "";
        this.imageDiv = null;
    },

    /**
     * Method: clone
     *
     * Returns:
     * {<OpenLayers.Icon>} A fresh copy of the icon.
     */
    clone: function() {
        return new OpenLayers.Icon(this.url,
                                   this.size,
                                   this.offset,
                                   this.calculateOffset);
    },

    /**
     * Method: setSize
     *
     * Parameters:
     * size - {<OpenLayers.Size>}
     */
    setSize: function(size) {
        if (size != null) {
            this.size = size;
        }
        this.draw();
    },

    /**
     * Method: setUrl
     *
     * Parameters:
     * url - {String}
     */
    setUrl: function(url) {
        if (url != null) {
            this.url = url;
        }
        this.draw();
    },

    /**
     * Method: draw
     * Move the div to the given pixel.
     *
     * Parameters:
     * px - {<OpenLayers.Pixel>}
     *
     * Returns:
     * {DOMElement} A new DOM Image of this icon set at the location passed-in
     */
    draw: function(px) {
        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,
                                            null,
                                            null,
                                            this.size,
                                            this.url,
                                            "absolute");
        this.moveTo(px);
        return this.imageDiv;
    },

    /**
     * Method: erase
     * Erase the underlying image element.
     *
     */
    erase: function() {
        if (this.imageDiv != null && this.imageDiv.parentNode != null) {
            OpenLayers.Element.remove(this.imageDiv);
        }
    },

    /**
     * Method: setOpacity
     * Change the icon's opacity
     *
     * Parameters:
     * opacity - {float}
     */
    setOpacity: function(opacity) {
        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null,
                                            null, null, null, null, opacity);

    },

    /**
     * Method: moveTo
     * move icon to passed in px.
     *
     * Parameters:
     * px - {<OpenLayers.Pixel>}
     */
    moveTo: function (px) {
        //if no px passed in, use stored location
        if (px != null) {
            this.px = px;
        }

        if (this.imageDiv != null) {
            if (this.px == null) {
                this.display(false);
            } else {
                if (this.calculateOffset) {
                    this.offset = this.calculateOffset(this.size);
                }
                var offsetPx = this.px.offset(this.offset);
                OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, offsetPx);
            }
        }
    },

    /**
     * Method: display
     * Hide or show the icon
     *
     * Parameters:
     * display - {Boolean}
     */
    display: function(display) {
        this.imageDiv.style.display = (display) ? "" : "none";
    },

    /**
     * APIMethod: isDrawn
     *
     * Returns:
     * {Boolean} Whether or not the icon is drawn.
     */
    isDrawn: function() {
        // nodeType 11 for ie, whose nodes *always* have a parentNode
        // (of type document fragment)
        var isDrawn = (this.imageDiv && this.imageDiv.parentNode &&
                       (this.imageDiv.parentNode.nodeType != 11));

        return isDrawn;
    },

    CLASS_NAME: "OpenLayers.Icon"
});
<commit_msg>Fix OpenLayers.Icon apidoc<commit_after>/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
 * full list of contributors). Published under the Clear BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */

/**
 * @requires OpenLayers/BaseTypes/Class.js
 */

/**
 * Class: OpenLayers.Icon
 *
 * The icon represents a graphical icon on the screen.  Typically used in
 * conjunction with a <OpenLayers.Marker> to represent markers on a screen.
 *
 * An icon has a url, size and position.  It also contains an offset which
 * allows the center point to be represented correctly.  This can be
 * provided either as a fixed offset or a function provided to calculate
 * the desired offset.
 *
 */
OpenLayers.Icon = OpenLayers.Class({

    /**
     * Property: url
     * {String}  image url
     */
    url: null,

    /**
     * Property: size
     * {<OpenLayers.Size>|Object} An OpenLayers.Size or
     * an object with a 'w' and 'h' properties.
     */
    size: null,

    /**
     * Property: offset
     * {<OpenLayers.Pixel>|Object} distance in pixels to offset the
     * image when being rendered. An OpenLayers.Pixel or an object
     * with a 'x' and 'y' properties.
     */
    offset: null,

    /**
     * Property: calculateOffset
     * {Function} Function to calculate the offset (based on the size)
     */
    calculateOffset: null,

    /**
     * Property: imageDiv
     * {DOMElement}
     */
    imageDiv: null,

    /**
     * Property: px
     * {<OpenLayers.Pixel>}
     */
    px: null,

    /**
     * Constructor: OpenLayers.Icon
     * Creates an icon, which is an image tag in a div.
     *
     * url - {String}
     * size - {<OpenLayers.Size>|Object} An OpenLayers.Size or an
     *                                   object with a 'w' and 'h'
     *                                   properties.
     * offset - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or an
     *                                      object with a 'x' and 'y'
     *                                      properties.
     * calculateOffset - {Function}
     */
    initialize: function(url, size, offset, calculateOffset) {
        this.url = url;
        this.size = size || {w: 20, h: 20};
        this.offset = offset || {x: -(this.size.w/2), y: -(this.size.h/2)};
        this.calculateOffset = calculateOffset;

        var id = OpenLayers.Util.createUniqueID("OL_Icon_");
        this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id);
    },

    /**
     * Method: destroy
     * Nullify references and remove event listeners to prevent circular
     * references and memory leaks
     */
    destroy: function() {
        // erase any drawn elements
        this.erase();

        OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);
        this.imageDiv.innerHTML = "";
        this.imageDiv = null;
    },

    /**
     * Method: clone
     *
     * Returns:
     * {<OpenLayers.Icon>} A fresh copy of the icon.
     */
    clone: function() {
        return new OpenLayers.Icon(this.url,
                                   this.size,
                                   this.offset,
                                   this.calculateOffset);
    },

    /**
     * Method: setSize
     *
     * Parameters:
     * size - {<OpenLayers.Size>|Object} An OpenLayers.Size or
     * an object with a 'w' and 'h' properties.
     */
    setSize: function(size) {
        if (size != null) {
            this.size = size;
        }
        this.draw();
    },

    /**
     * Method: setUrl
     *
     * Parameters:
     * url - {String}
     */
    setUrl: function(url) {
        if (url != null) {
            this.url = url;
        }
        this.draw();
    },

    /**
     * Method: draw
     * Move the div to the given pixel.
     *
     * Parameters:
     * px - {<OpenLayers.Pixel>}
     *
     * Returns:
     * {DOMElement} A new DOM Image of this icon set at the location passed-in
     */
    draw: function(px) {
        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,
                                            null,
                                            null,
                                            this.size,
                                            this.url,
                                            "absolute");
        this.moveTo(px);
        return this.imageDiv;
    },

    /**
     * Method: erase
     * Erase the underlying image element.
     *
     */
    erase: function() {
        if (this.imageDiv != null && this.imageDiv.parentNode != null) {
            OpenLayers.Element.remove(this.imageDiv);
        }
    },

    /**
     * Method: setOpacity
     * Change the icon's opacity
     *
     * Parameters:
     * opacity - {float}
     */
    setOpacity: function(opacity) {
        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null,
                                            null, null, null, null, opacity);

    },

    /**
     * Method: moveTo
     * move icon to passed in px.
     *
     * Parameters:
     * px - {<OpenLayers.Pixel>}
     */
    moveTo: function (px) {
        //if no px passed in, use stored location
        if (px != null) {
            this.px = px;
        }

        if (this.imageDiv != null) {
            if (this.px == null) {
                this.display(false);
            } else {
                if (this.calculateOffset) {
                    this.offset = this.calculateOffset(this.size);
                }
                var offsetPx = this.px.offset(this.offset);
                OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, offsetPx);
            }
        }
    },

    /**
     * Method: display
     * Hide or show the icon
     *
     * Parameters:
     * display - {Boolean}
     */
    display: function(display) {
        this.imageDiv.style.display = (display) ? "" : "none";
    },

    /**
     * APIMethod: isDrawn
     *
     * Returns:
     * {Boolean} Whether or not the icon is drawn.
     */
    isDrawn: function() {
        // nodeType 11 for ie, whose nodes *always* have a parentNode
        // (of type document fragment)
        var isDrawn = (this.imageDiv && this.imageDiv.parentNode &&
                       (this.imageDiv.parentNode.nodeType != 11));

        return isDrawn;
    },

    CLASS_NAME: "OpenLayers.Icon"
});
<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');
var DEBUG = false;

function getAccountsFileName() {
  const accountsFile = path.resolve(__dirname, '../accounts.json');

  const useDefault = (() => {
    var _useDefault = true;
    if (fs.existsSync(accountsFile)) {
      DEBUG && console.log('--- account file exists');
      try {
        var accountsFileRead = fs.readFileSync(accountsFile).toString();
        if (!accountsFileRead) {
          DEBUG && console.log('--- account file is empty');
          throw 'empty accounts.json file';
        }

        var accountData = JSON.parse(accountsFileRead);
        if (
          accountData
          && accountData.hasOwnProperty('balance')
          && accountData.hasOwnProperty('assets')
          && accountData.hasOwnProperty('liabilities')
        ) {
          DEBUG && console.log('--- accounts file does not have proper props');
          _useDefault = false;
        }
      } catch (e) {
        DEBUG && console.log('--- error while checking accounts file:\n', e);
        // nothing to do, just use default
      }
    }
    return _useDefault
  })();

  DEBUG && console.log('Will use accounts.default.json: ', useDefault);

  return useDefault
    ? path.join(__dirname, '/../accounts.default.json')
    : accountsFile;
}

function updateGroups(accounts){
    var groupedLiabs = accounts.liabilities
      .filter(x => x.type === 'group')
      .reduce((all, one) => all.concat(one.items.map(i=>i.title)), []);
    accounts.liabilities.forEach(function(element) {
      if(element.type === 'group'){
        return;
      }
      element.type = undefined;
      if(groupedLiabs.includes(element.title)){
        element.type = 'grouped';
      }
    });
    return accounts;
}

function updateAccounts(accounts) {
  var u = JSON.parse(JSON.stringify(accounts));

  // AUTO MARK DUE and PAID
  var today = new Date();
  var oneWeekAhead = new Date().setDate(today.getDate() + 7);
  u.liabilities = u.liabilities.map(function (item) {
    if (!item.status || item.type === 'group'){
      item.status = 'paid';
      return item;
    }

    if (item.status.toLowerCase() === 'paid' && new Date(item.date) <= oneWeekAhead) {
      item.status = "due";
      //console.log(item);
      if(item.auto){
        item.status = "pending";
      }
    }
    return item;
  });

  // auto-mark group status based on child items
  u.liabilities = u.liabilities.map(function (item) {
    if (item.type !== 'group'){
      return item;
    }

    const groupedItemsNames = item.items.map(x => x.title);
    const groupedItems = u.liabilities.reduce((all, account) => {
      if (groupedItemsNames.includes(account.title)){
        all.push(account);
      }
      return all;
    }, []);

    const groupStatus = groupedItems.reduce((status, g) => {
      status = g.status.toLowerCase() === 'due' ? 'due' : status;
      status = g.status.toLowerCase() === 'pending' && status !== 'due'
        ? 'pending'
        : status;
      return status;
    }, item.status);
    item.status = groupStatus;

    return item;
  });

  // SORT LIABILITIES
  var pending = u.liabilities.filter(function (a) {
    return a.status && a.status.toLowerCase() === 'pending'
  }).sort(function (a, b) {
    return new Date(a.date) - new Date(b.date);
  });
  var paid = u.liabilities.filter(function (a) {
    return a.status ? a.status.toLowerCase() === 'paid' : a.status
  }).sort(function (a, b) {
    return new Date(a.date) - new Date(b.date);
  });
  var due = u.liabilities.filter(function (a) {
    return a.status && a.status.toLowerCase() === 'due'
  }).sort(function (a, b) {
    return new Date(a.date) - new Date(b.date);
  });
  u.liabilities = [].concat(due, pending, paid);

  u.totals = {};
  u.totals.pendingTotal = pending
    .filter(item => !(JSON.parse(item.hidden) || item.type === 'group'))
    .reduce((all, one) => all + Number(one.amount), 0);
  u.totals.dueTotal = due
    .filter(item => !(JSON.parse(item.hidden) || item.type === 'group'))
    .reduce((all, one) => all + Number(one.amount), 0);
  u.totals.assetsTotal = u.assets
    .filter(item => !JSON.parse(item.hidden))
    .reduce((all, one) => all + Number(one.amount), 0);
  u.totals.debts = u.liabilities
    .filter(item => !(JSON.parse(item.hidden) || item.type === 'group'))
    .reduce((all, one) => all + Number(one.amount), 0);
  u.totals.debtsTotal = u.liabilities
    .filter(item => !(JSON.parse(item.hidden) || item.type === 'group'))
    .reduce((all, one) => all - Number(one.total_owed), 0);

  u = updateGroups(u);

  return u;
}

module.exports = {
  getAccountsFileName,
  updateAccounts
};<commit_msg>missed from previous commit<commit_after>var fs = require('fs');
var path = require('path');
var DEBUG = false;

function getAccountsFileName() {
  const accountsFile = path.resolve(__dirname, '../accounts.json');

  const useDefault = (() => {
    var _useDefault = true;
    if (fs.existsSync(accountsFile)) {
      DEBUG && console.log('--- account file exists');
      try {
        var accountsFileRead = fs.readFileSync(accountsFile).toString();
        if (!accountsFileRead) {
          DEBUG && console.log('--- account file is empty');
          throw 'empty accounts.json file';
        }

        var accountData = JSON.parse(accountsFileRead);
        if (
          accountData
          && accountData.hasOwnProperty('balance')
          && accountData.hasOwnProperty('assets')
          && accountData.hasOwnProperty('liabilities')
        ) {
          DEBUG && console.log('--- accounts file does not have proper props');
          _useDefault = false;
        }
      } catch (e) {
        DEBUG && console.log('--- error while checking accounts file:\n', e);
        // nothing to do, just use default
      }
    }
    return _useDefault
  })();

  DEBUG && console.log('Will use accounts.default.json: ', useDefault);

  return useDefault
    ? path.join(__dirname, '/../accounts.default.json')
    : accountsFile;
}

function updateGroups(accounts){
    var groupedLiabs = accounts.liabilities
      .filter(x => x.type === 'group')
      .reduce((all, one) => all.concat(one.items.map(i=>i.title)), []);
    accounts.liabilities.forEach(function(element) {
      if(element.type === 'group'){
        return;
      }
      element.type = undefined;
      if(groupedLiabs.includes(element.title)){
        element.type = 'grouped';
      }
    });
    return accounts;
}

function updateAccounts(accounts) {
  var u = JSON.parse(JSON.stringify(accounts));

  // AUTO MARK DUE and PAID
  var today = new Date();
  var oneWeekAhead = new Date().setDate(today.getDate() + 7);
  var paycheck = accounts.assets
    .filter(x => x.title.toLowerCase() === 'paycheck')[0];
  var payDate = new Date(paycheck.date);
  u.liabilities = u.liabilities.map(function (item) {
    if (!item.status || item.type === 'group'){
      item.status = 'paid';
      return item;
    }

    if (item.status.toLowerCase() === 'paid' && new Date(item.date) <= oneWeekAhead && new Date(item.date) < payDate) {
      console.log('item.date', item.date);
      console.log('paycheck.date', paycheck.date);
      item.status = "due";
      //console.log(item);
      if(item.auto){
        item.status = "pending";
      }
    }
    return item;
  });

  // auto-mark group status based on child items
  u.liabilities = u.liabilities.map(function (item) {
    if (item.type !== 'group'){
      return item;
    }

    const groupedItemsNames = item.items.map(x => x.title);
    const groupedItems = u.liabilities.reduce((all, account) => {
      if (groupedItemsNames.includes(account.title)){
        all.push(account);
      }
      return all;
    }, []);

    const groupStatus = groupedItems.reduce((status, g) => {
      status = g.status.toLowerCase() === 'due' ? 'due' : status;
      status = g.status.toLowerCase() === 'pending' && status !== 'due'
        ? 'pending'
        : status;
      return status;
    }, item.status);
    item.status = groupStatus;

    return item;
  });

  // SORT LIABILITIES
  var pending = u.liabilities.filter(function (a) {
    return a.status && a.status.toLowerCase() === 'pending'
  }).sort(function (a, b) {
    return new Date(a.date) - new Date(b.date);
  });
  var paid = u.liabilities.filter(function (a) {
    return a.status ? a.status.toLowerCase() === 'paid' : a.status
  }).sort(function (a, b) {
    return new Date(a.date) - new Date(b.date);
  });
  var due = u.liabilities.filter(function (a) {
    return a.status && a.status.toLowerCase() === 'due'
  }).sort(function (a, b) {
    return new Date(a.date) - new Date(b.date);
  });
  u.liabilities = [].concat(due, pending, paid);

  u.totals = {};
  u.totals.pendingTotal = pending
    .filter(item => !(JSON.parse(item.hidden) || item.type === 'group'))
    .reduce((all, one) => all + Number(one.amount), 0);
  u.totals.dueTotal = due
    .filter(item => !(JSON.parse(item.hidden) || item.type === 'group'))
    .reduce((all, one) => all + Number(one.amount), 0);
  u.totals.assetsTotal = u.assets
    .filter(item => !JSON.parse(item.hidden))
    .reduce((all, one) => all + Number(one.amount), 0);
  u.totals.debts = u.liabilities
    .filter(item => !(JSON.parse(item.hidden) || item.type === 'group'))
    .reduce((all, one) => all + Number(one.amount), 0);
  u.totals.debtsTotal = u.liabilities
    .filter(item => !(JSON.parse(item.hidden) || item.type === 'group'))
    .reduce((all, one) => all - Number(one.total_owed), 0);

  u = updateGroups(u);

  return u;
}

module.exports = {
  getAccountsFileName,
  updateAccounts
};<|endoftext|>


<commit_before>(function(){
  'use strict'

  angular.module('ToDo')
  .controller('ToDoController',ToDoController);

  ToDoController.$inject = ['$q','firebaseService','profileService'];
  function ToDoController($q,firebaseService,profileService){
    var vm = this;
    /*====================== Delegation Variables =========================== */
    vm.addItem = addItem;
    vm.addItemAction = addItemAction;
    vm.editItem = editItem;
    vm.addList = addList;
    vm.addListAction = addListAction;
    vm.createNewListAction = createNewListAction;
    vm.deleteListAction = deleteListAction;
    vm.editModeAction = editModeAction;
    vm.exitEditMode = exitEditMode;
    vm.saveAction = saveAction;
    vm.searchListsAction = searchListsAction;
    vm.selectListAction = selectListAction;
    vm.signInAction = signInAction;
    vm.signOutAction = signOutAction;
    vm.signUpAction = signUpAction;
    vm.removeItem = removeItem;
    /*====================== public Variables =============================== */
    vm.displayList = [{value:" "},{value:" "}];
    vm.inputData = "";
    vm.list = [{value:" ",done:false},{value:" ",done:false}];
    vm.tabs = null;//[{name:"testList",colour:"",tags:["test","tasks"]}];
    vm.indexer = 0;
    //vm.logedIn = false;
    //<!> move to profile.controler
    vm.profileMode = "signIn";//<!> temp
    vm.listCreation = false;
    vm.tabName ="";//<!>
    vm.tabTags = "";
    //vm.user;
    //vm.userEmail = "";//<!> add encryption
    //vm.userPassword = ""///<!> add encryption
    //</!> move to profile.controler
    vm.pageSize = 25;
    /*====================== private Variables ============================== */
    var oldTabName;
    /*====================== Services ======================================= */
    var fbSvc = firebaseService;
    var pSvc = profileService;
    /*====================== Public Methods ================================= */
    function addItem(index,item){
        vm.list.splice(index,0,item);
        vm.inputData = "";
        addItemToDisplayList(index,item);
        saveAction();
    }
    function addItemAction($event){
        if($event.code === 'Enter'){
          var item = {value:vm.inputData, done: false, editMode: false};
          addItem(vm.list.length,item);
        }
    }
    function addList(_tab){
      vm.tabs.push(_tab);
      sortTabList();
      //console.log(vm.tabs);
      var index = 0;
      for(let i=0,l=vm.tabs.length; i<l; i++){
        if(vm.tabs[i].name == _tab.name){
          index = i;
        }
      }
      saveTab();
      selectListAction(index);
    }
    function addListAction(){
      //switches content to create list
      vm.listCreation = !vm.listCreation;
      vm.tabName ="";
    }
    function createNewListAction(){//$event){
      //if($event.code === 'Enter'){
        var _name = vm.tabName;
        var _tags = vm.tabTags.split(',');
        var tab_ = {name:_name,colour:"",tags:_tags}
        //console.log(tab_);
        addList(tab_);
        //vm.list = [];
        //console.log(vm.tabs);
      //}
    }
    function deleteListAction($index){
      //vm.tabs.splice($index,1);
      //console.log(vm.tabs[$index].name);

      var defer = $q.defer();
      let path ="users/"+pSvc.user.uid+"/lists/"+vm.tabs[$index].name;
      //console.log(path);
      fbSvc.removeDataPoint(path)
      .then(function(){
        //path = "users/"+pSvc.user.uid+"/tabs/"+$index;//vm.tabs[$index].name;
        //console.log(path);
        vm.tabs.splice($index,1);
        //fbSvc.removeDataPoint(path);

        //vm.indexer = 0;
        saveTab();
        //loadTabs(pSvc.user.uid);
        selectListAction(0);
        defer.resolve();
      },function(error){
        defer.reject();
      });
      return defer.promise();
    }
    function editItem(index, content,_done){
      vm.list[index].value = content;
      vm.list[index].done = _done;
      vm.displayList[index].value = content;
      vm.displayList[index].done = _done;
      if(vm.displayList[index].done){
        vm.displayList[index].line = 'line-through';
      } else {
        vm.displayList[index].line = '';
      }
      saveAction();
    }
    function editModeAction($index){
      if(vm.displayList[$index].editMode){
        //console.log(vm.list[$index].value);
        editItem($index,vm.displayList[$index].value,vm.displayList[$index].done);
        //console.log(vm.list[$index].value);
      }
      vm.displayList[$index].editMode = !vm.displayList[$index].editMode;
    }
    function exitEditMode($event,$index){
      if($event.code === 'Enter'){
        editModeAction($index);
      }
    }
    function removeItem(index){
      vm.list.splice(index,1);
      clearDisplay();
      loadList();
      saveAction();
    }
    function saveAction(){
      //console.log("ping;");
      //saveTab();
      //set up save list
      //to get rid of angular hash key and keys used only client side
      var list_ = []
      for(let i =0, l =vm.list.length; i < l; i++){
        list_.push({value:vm.list[i].value, done: vm.list[i].done});
      }
      //console.log(list_);
      saveList(list_);
    }
    function searchListsAction($event){
      if($event.code === 'Enter' && vm.search != ""){
        for(let i = 0, l = vm.tabs.length; i<l; i++){
          let tab = vm.tabs[i].invisible = true;
        }
        var filterdByName = filterByName();
        var filterdByTags = filterByTags();
        //console.log(filterdByName);
        console.log(filterdByTags);
        console.log(vm.tabs);
        for(let i =0, l = filterdByName.length; i<l; i++){
            vm.tabs[filterdByName[i]].invisible = false;
        }
        for(let i =0, l = filterdByTags.length; i<l; i++){
            vm.tabs[filterdByTags[i]].invisible = false;
        }
      } else if($event.code === 'Enter' && vm.search == ""){
        for(let i = 0, l = vm.tabs.length; i<l; i++){
          let tab = vm.tabs[i].invisible = false;
        }
      }
    }
    function selectListAction(_indexer){
      vm.listCreation = false;
      vm.indexer = _indexer;
      //console.log(vm.tabs[_indexer].name);
      loadListData(pSvc.user.uid);
    }
    function signInAction(){
      if(pSvc.profileMode == "signIn"){
        //console.log(pSvc.profileMode);
        //console.log(pSvc.userEmail);
        fbSvc.signInUser(pSvc.userEmail,pSvc.userPassword)
        .then(function(userData){
          //console.log("success!");
          //console.log(userData);
          if(!userData.emailVerified){
            //console.log("not verified");
            alert("user not verified");
            let resend = confirm("resend verification?")
            if(confirm != null ||confirm != "" ){
              //call fbSvc.emailConfirm
              //console.log("confirming email");
              fbSvc.emailConfirm(userData);
            }
            signOutAction();
          }else{
            userDataCheck(userData);//<!> replace to profile controler call
            //<!>move to load list data function
            loadTabs(userData.uid);
            //loadListData(userData.uid);
            pSvc.profileMode = "profile";
            vm.profileMode = "profile";
          }
        });
      }
    }
    function signOutAction(){
      fbSvc.signOutUser()
      .then(function(user){
        pSvc.profileMode = "signIn";
        vm.profileMode = "signIn";
        clearDisplay();
        pSvc.ClearUserData();
      });
    }
    function signUpAction(){
      if(pSvc.profileMode == "signIn"){
        fbSvc.signUpUser(pSvc.userEmail,pSvc.userPassword)
        .then(function(user){
          //console.log(userData);
          alert("please verify user via the recived email, and then try login in, thank you! :) /n no need to refresh either.")
          //pSvc.profileMode = "profile";
        });
      }
    }
    function userDataCheck(_user){
      pSvc.user = _user;
      if(pSvc.user.displayName == "" || pSvc.user.displayName == null){
        var displayName = pSvc.user.email.split('@')[0];
        displayName = prompt("Enter your desired display name",displayName);
        pSvc.user.updateProfile({
          displayName: displayName,
          photoURL: ""
        }).then(function() {
          // Profile updated successfully!
          // "Jane Q. User"
           displayName = pSvc.user.displayName;
           //photoURL = user.photoURL;
        }, function(error) {
          // An error happened.
          console.error("display name could not be updated please contact support");
        });
      }else{
        //console.log(pSvc.user.displayName);
      }
    }
    /*====================== Private Methods ================================ */
    function addItemToDisplayList(index, item){//clunky way of getting around my lack of html finise ;)
      //console.log(item);
      //console.log(item);
      var line_;
      if(item.done){
        line_ = 'line-through';
      } else {
        line_ = '';
      }
      vm.displayList[index] = {value:item.value, done: item.done, editMode: false, line:line_};
    }
    function clearDisplay(){
      vm.displayList = [];
      vm.displayList = createEmptyList(vm.pageSize);
      vm.inputData = "";
    }
    function createEmptyList(_size){
      //create empty list at variable size!
      var list_ = [];//out going list
      for(let i =0, l = _size; i<l; i++){
        list_.push({value:" ",empty:true, editMode: false});
      }
      return list_
    }
    function filterByName(){ //<!>currently only does full matchs
      var nums_ = [];
      for(let i =0, l= vm.tabs.length; i<l;i++){
        if(vm.tabs[i].name == vm.search){
          nums_.push(i);
        }
      }
      return nums_;
    }
    function filterByTags(){ //<!>currently only does full matchs
      var nums_ = [];
      for(let i =0, l= vm.tabs.length; i<l;i++){
        for(let n =0, c = vm.tabs[i].tags.length ;n<c; n++){
          if(vm.tabs[i].tags[n] == vm.search){
            nums_.push(i);
          }
        }
      }
      return nums_;
    }
    function init(){
      vm.indexer = 0;
      vm.displayList = createEmptyList(vm.pageSize);
      vm.list = [];
      fbSvc.initializeFireBase();
      fbSvc.checkUserSession().then(function(user){
        pSvc.user = user;
        userDataCheck(user);
        loadTabs(user.uid);
        //loadListData(user.uid);
        //.then(function(_test){
          //console.log(_test);
          //console.log(vm.tabs);
        //});
        pSvc.profileMode = "profile";
        vm.profileMode = "profile";
      },function(){

      });
      //console.log();
    }

    function loadListData(_uid){
      //console.log(vm.tabs);
      //console.log(vm.indexer);
      // if(oldTabName != "" || oldTabName == undefined || oldTabName == null)
      //   fbSvc.readDataOff('users/'+_uid+"/lists/"+oldTabName);
      var tab = vm.tabs[vm.indexer];
      //oldTabName = tab.name;
      //console.log(vm.tabs);
      //console.log(oldTabName);
      //console.log(tab);
      //console.log(tab.name);
      //clearDisplay();
      // fbSvc.readDataOn('users/'+_uid+"/lists/"+tab.name,
      //   function(_list){
      //     clearDisplay();
      //     vm.list = _list;
      //     loadList();
      // });
      fbSvc.readDataOnce('users/'+_uid+"/lists/"+tab.name)
      .then(function(_list){
        //console.log(vm.list);
        vm.list = _list;
        loadList();
      },function(error){
      });
    }
    function loadList(){
      if(vm.list == null) vm.list = [];
      clearDisplay();
      for(let i=0,l=vm.list.length;i<l;i++){
        addItemToDisplayList(i,vm.list[i]);
      }
      //console.log(vm.displayList);
      //console.log("loaded");
      sortTabList();
    }
    function loadTabs(_uid){
      //loadTabData(_uid)
      fbSvc.readDataOn("users/"+_uid+"/tabs/",loadTabData);
      // .then(function(_tabs){
      //   if(_tabs == null){
      //     vm.tabs = [];
      //     vm.list = [];
      //   } else {
      //     vm.tabs = _tabs;
      //     loadListData(_uid);
      //   }

        // let keys = Object.keys(_tabs);
        // for(let i = 0, l = keys.length; i<l; i++){
        //   let tab = {name:keys[i],colour:_tabs[keys[i]].colour,tags:_tabs[keys[i]].tags}
        //   //console.log(tab);
        //   vm.tabs.push(tab);
        // }
        //vm.indexer = 0;
        //sortTabList();
      //});
    }
    function loadTabData(_tabs){
      if(_tabs == null ){
        vm.tabs = [];
        vm.list = [];
      } else {
        vm.tabs = _tabs;
        loadListData(pSvc.user.uid);
      }

      //console.log("loading tabs");
      // var deferred = $q.defer();
      // let tabs;
      // //vm.tabs = [];
      // .then(function(data){
      //   //console.log(data);
      //   tabs = data;
      //   //console.log(tabs);
      //   //vm.tabs = tabs;
      //   deferred.resolve(tabs);
      // },function(error){
      //   console.error(error.code);
      //   console.error(error.meesage);
      //   deferred.reject();
      // });
      // return deferred.promise;
    }

    function saveList(_list){
    //  let promise = new Promise((resolve, reject) => {
      //  if (/* some async task is all good */) {
      //    resolve('Success!');
      //  } else {
      //    reject('Oops... something went wrong');
      //  }
      //});
      /* ^ default promise
       Q/promise notes
       as promiseVar.then(resolutionFunction(),RegectionFunction(error))
       both results are q/promises
       promises are native to JS since 2015, as well as angulars Q
      */
      //vm.tab.list = _list;
      // console.log(vm.displayList);
      // console.log(vm.list);
      // console.log(_list);
      var defer = $q.defer();
      fbSvc.writeData("users/"+pSvc.user.uid+"/lists/"+vm.tabs[vm.indexer].name,_list)
      .then(function(){
        //console.log("saved");
        defer.resolve();
      },function(rejected){
        console.log(rejected.message);
        defer.reject();
      });

      return defer.promise;
    }

    function saveTab(){
      //var tab_ = {colour:vm.tabs[vm.indexer].colour,tags:vm.tabs[vm.indexer].tags};
      //var tabName_ = vm.tabs[vm.indexer].name;
      var defer = $q.defer();
      var tabs_ = [];
      for(let i =0, l=vm.tabs.length; i<l; i++){
        let tab_ = {name:vm.tabs[i].name,colour:vm.tabs[i].colour,tags:vm.tabs[i].tags};
        tabs_.push(tab_);
      }
      //console.log(vm.tabs);
      fbSvc.writeData(pSvc.user.uid+"/tabs/",tabs_) //need to sit down and re normalize this
      .then(function(){
        defer.resolve();
      },function(rejected){
        console.log(rejected.message);
        defer.reject();
      });

      return defer.promise;
    }

    function sortTabList(){
      if(vm.tabs.length>=2){
        vm.tabs.sort(function(a,b){

          if(a.name < b.name)//if
            return -1;
          if(a.name > b.name)//else
            return 1;
          return 0//else
        });
      }

    }
    /*====================== Actions ======================================== */
    init();
  }
})();
<commit_msg>fixed pathing error in save tabs<commit_after>(function(){
  'use strict'

  angular.module('ToDo')
  .controller('ToDoController',ToDoController);

  ToDoController.$inject = ['$q','firebaseService','profileService'];
  function ToDoController($q,firebaseService,profileService){
    var vm = this;
    /*====================== Delegation Variables =========================== */
    vm.addItem = addItem;
    vm.addItemAction = addItemAction;
    vm.editItem = editItem;
    vm.addList = addList;
    vm.addListAction = addListAction;
    vm.createNewListAction = createNewListAction;
    vm.deleteListAction = deleteListAction;
    vm.editModeAction = editModeAction;
    vm.exitEditMode = exitEditMode;
    vm.saveAction = saveAction;
    vm.searchListsAction = searchListsAction;
    vm.selectListAction = selectListAction;
    vm.signInAction = signInAction;
    vm.signOutAction = signOutAction;
    vm.signUpAction = signUpAction;
    vm.removeItem = removeItem;
    /*====================== public Variables =============================== */
    vm.displayList = [{value:" "},{value:" "}];
    vm.inputData = "";
    vm.list = [{value:" ",done:false},{value:" ",done:false}];
    vm.tabs = null;//[{name:"testList",colour:"",tags:["test","tasks"]}];
    vm.indexer = 0;
    //vm.logedIn = false;
    //<!> move to profile.controler
    vm.profileMode = "signIn";//<!> temp
    vm.listCreation = false;
    vm.tabName ="";//<!>
    vm.tabTags = "";
    //vm.user;
    //vm.userEmail = "";//<!> add encryption
    //vm.userPassword = ""///<!> add encryption
    //</!> move to profile.controler
    vm.pageSize = 25;
    /*====================== private Variables ============================== */
    var oldTabName;
    /*====================== Services ======================================= */
    var fbSvc = firebaseService;
    var pSvc = profileService;
    /*====================== Public Methods ================================= */
    function addItem(index,item){
        vm.list.splice(index,0,item);
        vm.inputData = "";
        addItemToDisplayList(index,item);
        saveAction();
    }
    function addItemAction($event){
        if($event.code === 'Enter'){
          var item = {value:vm.inputData, done: false, editMode: false};
          addItem(vm.list.length,item);
        }
    }
    function addList(_tab){
      vm.tabs.push(_tab);
      sortTabList();
      //console.log(vm.tabs);
      var index = 0;
      for(let i=0,l=vm.tabs.length; i<l; i++){
        if(vm.tabs[i].name == _tab.name){
          index = i;
        }
      }
      saveTab();
      selectListAction(index);
    }
    function addListAction(){
      //switches content to create list
      vm.listCreation = !vm.listCreation;
      vm.tabName ="";
    }
    function createNewListAction(){//$event){
      //if($event.code === 'Enter'){
        var _name = vm.tabName;
        var _tags = vm.tabTags.split(',');
        var tab_ = {name:_name,colour:"",tags:_tags}
        //console.log(tab_);
        addList(tab_);
        //vm.list = [];
        //console.log(vm.tabs);
      //}
    }
    function deleteListAction($index){
      //vm.tabs.splice($index,1);
      //console.log(vm.tabs[$index].name);

      var defer = $q.defer();
      let path ="users/"+pSvc.user.uid+"/lists/"+vm.tabs[$index].name;
      //console.log(path);
      fbSvc.removeDataPoint(path)
      .then(function(){
        //path = "users/"+pSvc.user.uid+"/tabs/"+$index;//vm.tabs[$index].name;
        //console.log(path);
        vm.tabs.splice($index,1);
        //fbSvc.removeDataPoint(path);

        //vm.indexer = 0;
        saveTab();
        //loadTabs(pSvc.user.uid);
        selectListAction(0);
        defer.resolve();
      },function(error){
        defer.reject();
      });
      return defer.promise();
    }
    function editItem(index, content,_done){
      vm.list[index].value = content;
      vm.list[index].done = _done;
      vm.displayList[index].value = content;
      vm.displayList[index].done = _done;
      if(vm.displayList[index].done){
        vm.displayList[index].line = 'line-through';
      } else {
        vm.displayList[index].line = '';
      }
      saveAction();
    }
    function editModeAction($index){
      if(vm.displayList[$index].editMode){
        //console.log(vm.list[$index].value);
        editItem($index,vm.displayList[$index].value,vm.displayList[$index].done);
        //console.log(vm.list[$index].value);
      }
      vm.displayList[$index].editMode = !vm.displayList[$index].editMode;
    }
    function exitEditMode($event,$index){
      if($event.code === 'Enter'){
        editModeAction($index);
      }
    }
    function removeItem(index){
      vm.list.splice(index,1);
      clearDisplay();
      loadList();
      saveAction();
    }
    function saveAction(){
      //console.log("ping;");
      //saveTab();
      //set up save list
      //to get rid of angular hash key and keys used only client side
      var list_ = []
      for(let i =0, l =vm.list.length; i < l; i++){
        list_.push({value:vm.list[i].value, done: vm.list[i].done});
      }
      //console.log(list_);
      saveList(list_);
    }
    function searchListsAction($event){
      if($event.code === 'Enter' && vm.search != ""){
        for(let i = 0, l = vm.tabs.length; i<l; i++){
          let tab = vm.tabs[i].invisible = true;
        }
        var filterdByName = filterByName();
        var filterdByTags = filterByTags();
        //console.log(filterdByName);
        console.log(filterdByTags);
        console.log(vm.tabs);
        for(let i =0, l = filterdByName.length; i<l; i++){
            vm.tabs[filterdByName[i]].invisible = false;
        }
        for(let i =0, l = filterdByTags.length; i<l; i++){
            vm.tabs[filterdByTags[i]].invisible = false;
        }
      } else if($event.code === 'Enter' && vm.search == ""){
        for(let i = 0, l = vm.tabs.length; i<l; i++){
          let tab = vm.tabs[i].invisible = false;
        }
      }
    }
    function selectListAction(_indexer){
      vm.listCreation = false;
      vm.indexer = _indexer;
      //console.log(vm.tabs[_indexer].name);
      loadListData(pSvc.user.uid);
    }
    function signInAction(){
      if(pSvc.profileMode == "signIn"){
        //console.log(pSvc.profileMode);
        //console.log(pSvc.userEmail);
        fbSvc.signInUser(pSvc.userEmail,pSvc.userPassword)
        .then(function(userData){
          //console.log("success!");
          //console.log(userData);
          if(!userData.emailVerified){
            //console.log("not verified");
            alert("user not verified");
            let resend = confirm("resend verification?")
            if(confirm != null ||confirm != "" ){
              //call fbSvc.emailConfirm
              //console.log("confirming email");
              fbSvc.emailConfirm(userData);
            }
            signOutAction();
          }else{
            userDataCheck(userData);//<!> replace to profile controler call
            //<!>move to load list data function
            loadTabs(userData.uid);
            //loadListData(userData.uid);
            pSvc.profileMode = "profile";
            vm.profileMode = "profile";
          }
        });
      }
    }
    function signOutAction(){
      fbSvc.signOutUser()
      .then(function(user){
        pSvc.profileMode = "signIn";
        vm.profileMode = "signIn";
        clearDisplay();
        pSvc.ClearUserData();
      });
    }
    function signUpAction(){
      if(pSvc.profileMode == "signIn"){
        fbSvc.signUpUser(pSvc.userEmail,pSvc.userPassword)
        .then(function(user){
          //console.log(userData);
          alert("please verify user via the recived email, and then try login in, thank you! :) /n no need to refresh either.")
          //pSvc.profileMode = "profile";
        });
      }
    }
    function userDataCheck(_user){
      pSvc.user = _user;
      if(pSvc.user.displayName == "" || pSvc.user.displayName == null){
        var displayName = pSvc.user.email.split('@')[0];
        displayName = prompt("Enter your desired display name",displayName);
        pSvc.user.updateProfile({
          displayName: displayName,
          photoURL: ""
        }).then(function() {
          // Profile updated successfully!
          // "Jane Q. User"
           displayName = pSvc.user.displayName;
           //photoURL = user.photoURL;
        }, function(error) {
          // An error happened.
          console.error("display name could not be updated please contact support");
        });
      }else{
        //console.log(pSvc.user.displayName);
      }
    }
    /*====================== Private Methods ================================ */
    function addItemToDisplayList(index, item){//clunky way of getting around my lack of html finise ;)
      //console.log(item);
      //console.log(item);
      var line_;
      if(item.done){
        line_ = 'line-through';
      } else {
        line_ = '';
      }
      vm.displayList[index] = {value:item.value, done: item.done, editMode: false, line:line_};
    }
    function clearDisplay(){
      vm.displayList = [];
      vm.displayList = createEmptyList(vm.pageSize);
      vm.inputData = "";
    }
    function createEmptyList(_size){
      //create empty list at variable size!
      var list_ = [];//out going list
      for(let i =0, l = _size; i<l; i++){
        list_.push({value:" ",empty:true, editMode: false});
      }
      return list_
    }
    function filterByName(){ //<!>currently only does full matchs
      var nums_ = [];
      for(let i =0, l= vm.tabs.length; i<l;i++){
        if(vm.tabs[i].name == vm.search){
          nums_.push(i);
        }
      }
      return nums_;
    }
    function filterByTags(){ //<!>currently only does full matchs
      var nums_ = [];
      for(let i =0, l= vm.tabs.length; i<l;i++){
        for(let n =0, c = vm.tabs[i].tags.length ;n<c; n++){
          if(vm.tabs[i].tags[n] == vm.search){
            nums_.push(i);
          }
        }
      }
      return nums_;
    }
    function init(){
      vm.indexer = 0;
      vm.displayList = createEmptyList(vm.pageSize);
      vm.list = [];
      fbSvc.initializeFireBase();
      fbSvc.checkUserSession().then(function(user){
        pSvc.user = user;
        userDataCheck(user);
        loadTabs(user.uid);
        //loadListData(user.uid);
        //.then(function(_test){
          //console.log(_test);
          //console.log(vm.tabs);
        //});
        pSvc.profileMode = "profile";
        vm.profileMode = "profile";
      },function(){

      });
      //console.log();
    }

    function loadListData(_uid){
      //console.log(vm.tabs);
      //console.log(vm.indexer);
      // if(oldTabName != "" || oldTabName == undefined || oldTabName == null)
      //   fbSvc.readDataOff('users/'+_uid+"/lists/"+oldTabName);
      var tab = vm.tabs[vm.indexer];
      //oldTabName = tab.name;
      //console.log(vm.tabs);
      //console.log(oldTabName);
      //console.log(tab);
      //console.log(tab.name);
      //clearDisplay();
      // fbSvc.readDataOn('users/'+_uid+"/lists/"+tab.name,
      //   function(_list){
      //     clearDisplay();
      //     vm.list = _list;
      //     loadList();
      // });
      fbSvc.readDataOnce('users/'+_uid+"/lists/"+tab.name)
      .then(function(_list){
        //console.log(vm.list);
        vm.list = _list;
        loadList();
      },function(error){
      });
    }
    function loadList(){
      if(vm.list == null) vm.list = [];
      clearDisplay();
      for(let i=0,l=vm.list.length;i<l;i++){
        addItemToDisplayList(i,vm.list[i]);
      }
      //console.log(vm.displayList);
      //console.log("loaded");
      sortTabList();
    }
    function loadTabs(_uid){
      //loadTabData(_uid)
      fbSvc.readDataOn("users/"+_uid+"/tabs/",loadTabData);
      // .then(function(_tabs){
      //   if(_tabs == null){
      //     vm.tabs = [];
      //     vm.list = [];
      //   } else {
      //     vm.tabs = _tabs;
      //     loadListData(_uid);
      //   }

        // let keys = Object.keys(_tabs);
        // for(let i = 0, l = keys.length; i<l; i++){
        //   let tab = {name:keys[i],colour:_tabs[keys[i]].colour,tags:_tabs[keys[i]].tags}
        //   //console.log(tab);
        //   vm.tabs.push(tab);
        // }
        //vm.indexer = 0;
        //sortTabList();
      //});
    }
    function loadTabData(_tabs){
      if(_tabs == null ){
        vm.tabs = [];
        vm.list = [];
      } else {
        vm.tabs = _tabs;
        loadListData(pSvc.user.uid);
      }

      //console.log("loading tabs");
      // var deferred = $q.defer();
      // let tabs;
      // //vm.tabs = [];
      // .then(function(data){
      //   //console.log(data);
      //   tabs = data;
      //   //console.log(tabs);
      //   //vm.tabs = tabs;
      //   deferred.resolve(tabs);
      // },function(error){
      //   console.error(error.code);
      //   console.error(error.meesage);
      //   deferred.reject();
      // });
      // return deferred.promise;
    }

    function saveList(_list){
    //  let promise = new Promise((resolve, reject) => {
      //  if (/* some async task is all good */) {
      //    resolve('Success!');
      //  } else {
      //    reject('Oops... something went wrong');
      //  }
      //});
      /* ^ default promise
       Q/promise notes
       as promiseVar.then(resolutionFunction(),RegectionFunction(error))
       both results are q/promises
       promises are native to JS since 2015, as well as angulars Q
      */
      //vm.tab.list = _list;
      // console.log(vm.displayList);
      // console.log(vm.list);
      // console.log(_list);
      var defer = $q.defer();
      fbSvc.writeData("users/"+pSvc.user.uid+"/lists/"+vm.tabs[vm.indexer].name,_list)
      .then(function(){
        //console.log("saved");
        defer.resolve();
      },function(rejected){
        console.log(rejected.message);
        defer.reject();
      });

      return defer.promise;
    }

    function saveTab(){
      //var tab_ = {colour:vm.tabs[vm.indexer].colour,tags:vm.tabs[vm.indexer].tags};
      //var tabName_ = vm.tabs[vm.indexer].name;
      var defer = $q.defer();
      var tabs_ = [];
      for(let i =0, l=vm.tabs.length; i<l; i++){
        let tab_ = {name:vm.tabs[i].name,colour:vm.tabs[i].colour,tags:vm.tabs[i].tags};
        tabs_.push(tab_);
      }
      //console.log(vm.tabs);
      fbSvc.writeData("users/"+pSvc.user.uid+"/tabs/",tabs_) //need to sit down and re normalize this
      .then(function(){
        defer.resolve();
      },function(rejected){
        console.log(rejected.message);
        defer.reject();
      });

      return defer.promise;
    }

    function sortTabList(){
      if(vm.tabs.length>=2){
        vm.tabs.sort(function(a,b){

          if(a.name < b.name)//if
            return -1;
          if(a.name > b.name)//else
            return 1;
          return 0//else
        });
      }

    }
    /*====================== Actions ======================================== */
    init();
  }
})();
<|endoftext|>


<commit_before>import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.config.productionTip = false;

// components
import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome'
import 'pc-bootstrap4-datetimepicker/build/css/bootstrap-datetimepicker.css';

// app
import Generate from './generate'

// messages
import Messages from '../../localization/generate'
import mergeMessages from '../../localization/shared/_all'

if (document.getElementById("generate") != null) {
    // register plugins
    Vue.use(VueI18n);

    // register components
    Vue.component('font-awesome-icon', FontAwesomeIcon);

    // initialize messages
    const i18n = new VueI18n({
        locale: document.documentElement.lang.substr(0, 2),
        messages: mergeMessages(Messages),
    });

    // boot app
    new Vue({
        i18n,
        el: '#generate',
        template: '<Generate/>',
        components: {Generate}
    });
}<commit_msg>removing old dependency<commit_after>import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.config.productionTip = false;

// components
import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome'

// app
import Generate from './generate'

// messages
import Messages from '../../localization/generate'
import mergeMessages from '../../localization/shared/_all'

if (document.getElementById("generate") != null) {
    // register plugins
    Vue.use(VueI18n);

    // register components
    Vue.component('font-awesome-icon', FontAwesomeIcon);

    // initialize messages
    const i18n = new VueI18n({
        locale: document.documentElement.lang.substr(0, 2),
        messages: mergeMessages(Messages),
    });

    // boot app
    new Vue({
        i18n,
        el: '#generate',
        template: '<Generate/>',
        components: {Generate}
    });
}<|endoftext|>


<commit_before>/* global app, __dirname, _ */

/**
 * Bootstrap.js
 *
 */

global.app = {};

global._ = require('underscore');
const path = require('path');

global.Promise = require('bluebird');

// Include all api config
const config = require('include-all')({
  dirname: path.normalize(path.join(__dirname, '../app/config')),
  filter: /(.+)\.js$/,
  optional: true
});

// Environment
app.PRODUCTION = process.env.NODE_ENV !== 'production' ? false : true;
const env = (app.PRODUCTION) ? 'production' : 'development';

let settings = Object.assign(config.settings, config.env ? config.env[env] || {} : {}, config.local || {});

delete config.env;
delete config.local;

// General Settings
app.config = Object.assign(config, {settings: settings});

// Include all components
const services = require('./services')();
const database = require('./database');
const controllers = require('./controllers');
const server = require('./server');

module.exports = function () {

  console.log('');
  console.log('');
  console.log('------------------------------');
  console.log('');
  console.log('VULCANO - MVC');
  console.log('');
  console.log('------------------------------');

  // Database
  (new database());

  // Routes
  app.routes = controllers;

  // Server Config
  app.server = _({}).extend(server, app.config.settings || {});

  // Server Routes
  app.server.routes = _({}).extend(app.config.routes || {});

  // Start Express
  app.server.start(function () {
    let mode = app.PRODUCTION ? 'production' : 'development';
    if (config.bootstrap && typeof config.bootstrap === 'function') {
      config.bootstrap();
    }
    console.log('Node app is running on port', app.server.get('port'), 'in:', mode, 'mode');
  });

};
<commit_msg>[Update] Override custom config with the local file<commit_after>/* global app, __dirname, _ */

/**
 * Bootstrap.js
 *
 */

global.app = {};

global._ = require('underscore');
const path = require('path');

global.Promise = require('bluebird');

// Include all api config
const config = require('include-all')({
  dirname: path.normalize(path.join(__dirname, '../app/config')),
  filter: /(.+)\.js$/,
  optional: true
});

// Environment
app.PRODUCTION = process.env.NODE_ENV !== 'production' ? false : true;
const env = (app.PRODUCTION) ? 'production' : 'development';

let settings = Object.assign(config.settings, config.env ? config.env[env] || {} : {}, config.local || {});

delete config.env;
delete config.local;

// General Settings
app.config = Object.assign(config, {settings: settings});

// Override custom config with the localfile
for (const key in settings) {
  if (app.config[key] !== undefined) {
    app.config[key] = Object.assign(config[key], settings[key]);
  }
}

// Include all components
const services = require('./services')();
const database = require('./database');
const controllers = require('./controllers');
const server = require('./server');

module.exports = function () {

  console.log('');
  console.log('');
  console.log('------------------------------');
  console.log('');
  console.log('VULCANO - MVC');
  console.log('');
  console.log('------------------------------');

  // Database
  (new database());

  // Routes
  app.routes = controllers;

  // Server Config
  app.server = _({}).extend(server, app.config.settings || {});

  // Server Routes
  app.server.routes = _({}).extend(app.config.routes || {});

  // Start Express
  app.server.start(function () {
    let mode = app.PRODUCTION ? 'production' : 'development';
    if (config.bootstrap && typeof config.bootstrap === 'function') {
      config.bootstrap();
    }
    console.log('Node app is running on port', app.server.get('port'), 'in:', mode, 'mode');
  });

};
<|endoftext|>