<commit_before>;(function($) {
  var content_width = 0;
  var scroll_width = 0;
  var content, slider, padding;

  var enabled = false;
  function recalc_enabled_columns() {
    if(!enabled) {
      location.hash = "#0";
      $(window).scrollLeft(0).scrollTop(0);
      enabled = true;
    }

    var column_gap_width = (parseInt(padding.css("padding-top")) * 2) + parseInt(content.css("-webkit-column-rule-width") || content.css("column-rule-width"));
    var inner_width = window.innerWidth - column_gap_width;
    var inner_height = window.innerHeight - column_gap_width;
    var column_width = Math.floor((inner_width - column_gap_width) / 2);
    scroll_width = (column_width + column_gap_width) * 2;

    padding.css({ "width": inner_width + "px", "height": inner_height + "px", "overflow": "hidden" });
    content.css({ "width": inner_width + "px", "height": inner_height + "px", "-webkit-column-width": column_width + "px",
     "-moz-column-width": column_width + "px", "column-width": column_width + "px", "-webkit-column-gap": column_gap_width + "px",
     "-moz-column-gap": column_gap_width + "px", "column-gap": column_gap_width + "px" });
    content_width = content[0].scrollWidth;
  }

  function recalc_disabled_columns() {
    padding.css({ "width": "", "height": "", "overflow": "" });
    content.css({ "width": "", "height": "", "-webkit-column-width": "", "-moz-column-width": "", "column-width": "",
     "-webkit-column-gap": "", "-moz-column-gap": "", "column-gap": "" });
    slider.css({ "margin-left": "" });
    scroll_width = 0;
    content_width = 0;

    if(enabled) {
      $(window).scrollLeft(0).scrollTop(0);
      location.hash = "#0";
      enabled = false;
    }
  }

  function get_index() {
    var index = parseInt(location.hash.substr(1));
    if(isNaN(index)) index = 0;
    return index;
  }

  function get_max_index() {
    return Math.ceil(content_width / (scroll_width + 0.0));
  }

  //Cargo-culting from colorbox
  var twoup = $.fn.twoup = $.twoup = function(column_rule) {
    if(content) {
      alert("You already have a twoup!");
      return;
    }

    twoup.content = content = $("

").css({ "-webkit-column-rule": column_rule, "-moz-column-rule": column_rule, "column-rule": column_rule });
    twoup.slider = slider = $("

");
    twoup.padding = padding = $(this).css({ "overflow": "hidden" });

    var children = padding.children().detach();
    padding.append(slider);
    slider.append(content);
    content.append(children);

    //at the moment, only WebKit and MSIE10 has proper support for css3 columns AND getting the right width for a column element with overflow
    if(!$.browser.webkit && (!$.browser.msie || $.browser.version < 10)) return;

    var firstrun = true;
    $(window).resize(function() {
      if(twoup.displaying_columns() && firstrun) {
        enabled = true;
        firstrun = false;
      }

      if(twoup.displaying_columns()) recalc_enabled_columns();
      else recalc_disabled_columns();
    }).resize();

    $(window).bind('hashchange', function() {
      slider.animate({ "margin-left": -(scroll_width * get_index()) + "px" }, 500, "swing");
    }).trigger('hashchange');

    $(window).keydown(function(event) {
      var index = get_index();

      if(event.keyCode == 32 || event.keyCode == 39) {
        event.preventDefault();
        index++;
        if(index >= get_max_index()) index = get_max_index() - 1;
      }
      else if(event.keyCode == 8 || event.keyCode == 37) {
        event.preventDefault();
        index--;
        if(index < 0) index = 0;
      }

      location.hash = "#" + index;
    });

    return this;
  };

  twoup.displaying_columns = function() {
    //if the window width is narrower than 1000px, then the content column width would be too narrow
    return $(window).width() >= 1000;
  };

  twoup.column_width = function() {
    return twoup.displaying_columns() ? parseInt(content.css("-webkit-column-width") || content.css("-moz-column-width") || content.css("column-width")) : content.width()
  };
})(jQuery);
<commit_msg>Update jquery.twoup<commit_after>;(function($) {
  var content_width = 0;
  var scroll_width = 0;
  var content, slider, padding;

  var enabled = false;
  function recalc_enabled_columns() {
    if(!enabled) {
      location.hash = "#0";
      $(window).scrollLeft(0).scrollTop(0);
      enabled = true;
    }

    var column_gap_width = (parseInt(padding.css("padding-top")) * 2) + parseInt(content.css("-webkit-column-rule-width") || content.css("column-rule-width"));
    var inner_width = window.innerWidth - column_gap_width;
    var inner_height = window.innerHeight - column_gap_width;
    var column_width = Math.floor((inner_width - column_gap_width) / 2);
    scroll_width = (column_width + column_gap_width);

    padding.css({ "width": inner_width + "px", "height": inner_height + "px", "overflow": "hidden" });
    content.css({ "width": inner_width + "px", "height": inner_height + "px", "-webkit-column-width": column_width + "px",
     "-moz-column-width": column_width + "px", "column-width": column_width + "px", "-webkit-column-gap": column_gap_width + "px",
     "-moz-column-gap": column_gap_width + "px", "column-gap": column_gap_width + "px" });
    content_width = content[0].scrollWidth;
  }

  function recalc_disabled_columns() {
    padding.css({ "width": "", "height": "", "overflow": "" });
    content.css({ "width": "", "height": "", "-webkit-column-width": "", "-moz-column-width": "", "column-width": "",
     "-webkit-column-gap": "", "-moz-column-gap": "", "column-gap": "" });
    slider.css({ "margin-left": "" });
    scroll_width = 0;
    content_width = 0;

    if(enabled) {
      $(window).scrollLeft(0).scrollTop(0);
      location.hash = "#0";
      enabled = false;
    }
  }

  function get_index() {
    var index = parseInt(location.hash.substr(1));
    if(isNaN(index)) index = 0;
    return index;
  }

  function get_max_index() {
    return Math.ceil(content_width / scroll_width);
  }

  //Cargo-culting from colorbox
  var twoup = $.fn.twoup = $.twoup = function(column_rule) {
    if(content) {
      alert("You already have a twoup!");
      return;
    }

    twoup.content = content = $("

").css({ "-webkit-column-rule": column_rule, "-moz-column-rule": column_rule, "column-rule": column_rule });
    twoup.slider = slider = $("

");
    twoup.padding = padding = $(this).css({ "overflow": "hidden" });

    var children = padding.children().detach();
    padding.append(slider);
    slider.append(content);
    content.append(children);

    //at the moment, only WebKit and MSIE10 has proper support for css3 columns AND getting the right width for a column element with overflow
    if(!$.browser.webkit && (!$.browser.msie || $.browser.version < 10)) return;

    var firstrun = true;
    $(window).resize(function() {
      if(twoup.displaying_columns() && firstrun) {
        enabled = true;
        firstrun = false;
      }

      if(twoup.displaying_columns()) recalc_enabled_columns();
      else recalc_disabled_columns();
    }).resize();

    $(window).bind('hashchange', function() {
      slider.animate({ "margin-left": -(scroll_width * Math.floor(get_index() / 2) * 2) + "px" }, 500, "swing");
    }).trigger('hashchange');

    $(window).keydown(function(event) {
      var index = get_index();

      if(event.keyCode == 32 || event.keyCode == 39) {
        event.preventDefault();
        index += 2;
        if(index >= get_max_index()) index = get_max_index() - 1;
      }
      else if(event.keyCode == 8 || event.keyCode == 37) {
        event.preventDefault();
        index -= 2;
        if(index < 0) index = 0;
      }

      location.hash = "#" + index;
    });

    return this;
  };

  twoup.displaying_columns = function() {
    //if the window width is narrower than 1000px, then the content column width would be too narrow
    return $(window).width() >= 1000;
  };

  twoup.column_width = function() {
    return twoup.displaying_columns() ? parseInt(content.css("-webkit-column-width") || content.css("-moz-column-width") || content.css("column-width")) : content.width()
  };
})(jQuery);
<|endoftext|>


<commit_before>var easymidi = require('easymidi');
var output = new easymidi.Output('IAC Driver Bus 1');
var colors = require('colors');
var eventType = require('./interpreter/constants').eventType;
var pad = require('pad');
var NanoTimer = require('nanotimer');
var timer = new NanoTimer();
var utils = require('./interpreter/utils');
var Interpreter = require('./interpreter/Interpreter');

var stopped = false;
var paused = false;
var space = '                                                            ';
var sPaused = '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - P A U S E D - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -'.magenta;
var sStart = '= = = = = = = = = = = = = = = = = = = = = = = = = = = = S T A R T = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ='.yellow;
var sEnd = '= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = E N D = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ='.red;
var sStopped = '= = = = = = = = = = = = = = = = = = = = = = = = = = = = = S T O P P E D = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ='.blue;

var logMode = 'info';// 'pianoroll';

function allNotesOff() {

  offAll();
  function off() {
    for (var i = 0; i < 10; i++) {
      for (var channelKey in noteState) {
        for (var noteKey in noteState[channelKey]) {
          if (noteState[channelKey][noteKey]) {
            output.send('noteoff', {
              note: noteKey,
              channel: channelKey
            });
            console.log('off: ' + channelKey + ', ' + noteKey)
          }
        }
      }
    }
  }

  function offAll() {
    for (var i = 0; i < 3; i++) {
      for (var c = 0; c < 16; c++) {
        for (var p = 0; p < 128; p++) {
          output.send('noteoff', {
            note: p,
            channel: c
          });
        }
      }

    }
  }

}

function onKeyPress(ch, key) {

  if (!stopped) {
    if (key && key.name === 'escape') {
      api.stop();
    }
    if (key && key.name === 'space') {
      api.togglePause();
    }
  }

  /*
    if (key && key.name === 'f1') {
      console.log('Log information'.green);
      logMode = 'info';
    }
    if (key && key.name === 'f2') {
      console.log('Log piano roll'.green);
      logMode = 'pianoroll';
    }
  */

}

var indexed = {};

var noteState;
function resetNoteState() {
  noteState = {};
  for (var i = 0; i < 16; i++) {
    noteState[i] = {};
    for (var n = 0; n < 128; n++) {
      noteState[i][n] = false;
    }
  }
}

var interval = 10000;
var tick = -1, endTick, maxTick, lastBeat, prLastBeat;
var timeout;
function onTick() {
  if (stopped || paused) return;

  tick++;

  if (tick === 0) {
    console.log('\n');
    console.log(sStart);
  }

  indexed[tick].forEach(function (event) {
    if (event.type === eventType.noteon) {
      noteState[event.channel][event.pitch.value] = event.keyswitch ? 'keyswitch' : true;
    }

    if (logMode === 'info') {
      logInfo(event);
    }

    switch (event.type) {
      case eventType.tempo:
        var newInterval = Math.round(1000000 / (event.value * 0.8));
        if (newInterval !== interval) {
          interval = newInterval;
          timer.clearInterval();
          timer.setInterval(onTick, '', interval + 'u');
        }
        break;
      case eventType.controller:
        if (!event.sent) {
          output.send(eventType.controller, {
            value: event.value,
            controller: event.controller,
            channel: event.channel
          });
          event.sent = true;
        }
        break;
      case eventType.pitchbend:
        if (!event.sent) {
          output.send(eventType.pitchbend, {
            value: event.value,
            channel: event.channel
          });
          event.sent = true;
        }
        break;
      case eventType.noteon:
        if (!event.sent) {
          output.send(eventType.noteon, {
            note: event.pitch.value,
            velocity: event.velocity || 80,
            channel: event.channel
          });
          event.sent = true;
        }
        break;
      case eventType.noteoff:
        if (!event.sent) {
          output.send(eventType.noteoff, {
            note: event.pitch.value,
            channel: event.channel
          });
          event.sent = true;
        }
        break;
      default:
        throw 'Unknown event type: ' + event.type
        break
    }

    if (event.type === eventType.noteoff) {
      noteState[event.channel][event.pitch.value] = false;
    }

  });

  if (logMode === 'pianoroll' && tick % 12 === 0) {
    logPianoRoll();
  }

  if (tick < maxTick && (!endTick || tick < endTick) && !stopped && !paused) {

  } else if (!paused) {
    if (endTick < maxTick) {
      api.stop();
    } else if (!stopped) {
      api.end();
    }
  }
}
function logInfo(event) {

  var name = event.type;
  var data = [];
  var color;
  var log = '';
  var beat = Math.floor(event.tick / 48);

  switch (event.type) {
    case eventType.noteon:
      data.push(event.pitch.string + ' (' + event.pitch.value + ')');
      if (event.keyswitch) {
        name = 'noteon ks';
        color = colors.red;
      } else {
        color = colors.yellow;
        data.push(`v${event.velocity}`);
      }
      data.push(event.offset);
      break;
    case eventType.noteoff:
      if (event.keyswitch) {
        name = 'noteoff ks';
      }
      color = colors.grey;
      data.push(event.pitch.string + ' (' + event.pitch.value + ')');
      data.push(`d${event.duration}`);
      data.push(event.offset);

      break;
    case eventType.pitchbend:
      color = colors.red;
      data.push(event.value);
      break;
    case eventType.controller:
      color = colors.red;
      name = `cc ${event.controller}`;
      data.push(`${event.value}`);
      break;
    case eventType.tempo:
      color = colors.blue;
      data.push(event.tempo);
      break;
  }

  if (event.annotation) {
    data.push(event.annotation);
  }
  if (event.articulation) {
    data.push(event.articulation);
  }

  log += colors.gray(pad(5, event.tick.toString())) + ' ';
  if (lastBeat !== beat) {
    log += colors.white(pad(5, beat.toString())) + '  ';
  } else {

    log += colors.gray(pad(5, beat.toString())) + '  ';
  }

  lastBeat = beat;
  if (event.channel !== undefined) {
    log += colors.blue(pad((event.channel + 1).toString(), 3));
  } else {
    log += '   ';
  }

  log += color(pad(name, 10)) + '  ';
  data.forEach(d => {
    if (d !== undefined) {
      log += color(pad(15, d));
    }

  })

  // if (event.info) log += colors.gray(event.info) + '  ';
  console.log(log);
}

function logPianoRoll() {

  var beat = Math.floor(tick / 48);
  var showBeat = beat > 0 && (!prLastBeat || beat !== prLastBeat);
  prLastBeat = beat;

  var pianoRoll = [];
  for (var channelKey in noteState) {
    for (var noteKey in noteState[channelKey]) {
      if (noteState[channelKey][noteKey]) {
        pianoRoll[noteKey] = channelKey;
      }
    }
  }

  var pianoRollLog = pad(showBeat ? beat.toString() : '', 3).white;
  for (var i = 0; i < 128; i++) {
    if (pianoRoll[i]) {
      var channel = parseInt(pianoRoll[i], 10) + 1;
      switch (channel) {
        case 0:
          pianoRollLog += channel.toString().black.bgWhite;
          break;
        case 1:
          pianoRollLog += channel.toString().black.bgYellow;
          break;
        case 2:
          pianoRollLog += channel.toString().black.bgCyan;
          break;
        case 3:
          pianoRollLog += channel.toString().black.bgGreen;
          break;
        case 4:
          pianoRollLog += channel.toString().black.bgBlue;
          break;
        case 5:
          pianoRollLog += channel.toString().black.bgRed;
          break;
        case 5:
          pianoRollLog += channel.toString().black.bgMagenta;
          break;
        default:
          pianoRollLog += channel.toString().black.bgWhite;
          break;
      }

    } else {

      pianoRollLog += '.'.grey;
    }
  }

  console.log(pianoRollLog);
}

var api = {
  stop: function () {
    timer.clearInterval();
    stopped = true;
    allNotesOff();
    console.log(sStopped);
    console.log('\n');
    process.stdin.removeListener('keypress', onKeyPress);
  },
  end: function () {
    timer.clearInterval();
    console.log(sEnd);
    console.log('\n');
    stopped = true;
  },
  togglePause: function () {
    paused = !paused;
    if (paused) {
      timer.clearInterval();
      allNotesOff();
      console.log(sPaused);
    } else {
      timer.setInterval(onTick, '', interval + 'u');
    }

  },
  setLogMode: function (mode) {
    if (mode === 'info' || mode === 'pianoroll') {
      logMode = mode;
    } else {
      console.log('Invalid log mode: ${mode} (can be either info or pianoroll)'.red);
    }

  },
  start: function (events, startBeat, endBeat) {

    var errors = events.filter(e => {
      return e.tick === undefined || isNaN(e.tick);
    });

    if (errors.length) {
      throw ('Missing tick', errors);
    }

    events = events.sort(function (a, b) {
      return a.tick > b.tick ? 1 : -1;
    });

    resetNoteState();
    clearInterval(timeout);
    process.stdin.removeListener('keypress', onKeyPress);
    process.stdin.on('keypress', onKeyPress);
    var startTick = -1;
    if (startBeat) {
      startTick = (parseInt(startBeat, 10) * 48) - 12;
    }
    if (endBeat) {
      endTick = (parseInt(endBeat, 10) * 48);
    }
    console.log('\n');

    stopped = false;
    paused = false;

    tick = startTick;
    maxTick = events[events.length - 1].tick;

    indexed = {};
    for (var i = 0; i <= maxTick; i++) {
      indexed[i] = events.filter(function (event) {
        return event.tick === i;
      });
    }

    timer.setInterval(onTick, '', interval + 'u');

  },
  load: function (players) {
    var allEvents = [];
    for (var key in players) {
      var player = players[key];
      delete player.annotations.name;
      var macros = utils.buildMacros(player.substitutions, player.annotations, player.articulations);
      var interpreter = new Interpreter(macros), events = [];
      if (typeof player.part === 'string') {
        events = utils.eventsFromStates(interpreter.interpret(player.part, player.master).states);
      } else { //array of part objects
        player.part.forEach(p => {
          events = events.concat(utils.eventsFromStates(interpreter.interpret(p, player.master).states));
        });
      }
      events.forEach(e => { e.channel = player.channel });
      allEvents = allEvents.concat(events);
    }

    api.start(allEvents);
  }
};
module.exports = api;
<commit_msg>removed old sequencer<commit_after><|endoftext|>


<commit_before>VISH.Flashcard = (function(V,$,undefined){

	var init = function(excursion){
		var fileref=document.createElement("link");
  		fileref.setAttribute("rel", "stylesheet");
  		fileref.setAttribute("type", "text/css");
  		fileref.setAttribute("href", "stylesheets/flashcard/flashcard.css");
  		document.getElementsByTagName("body")[0].appendChild(fileref);

  		var flashcard_div = $("#flashcard-background");
  		//first we set the flashcard background image
  		flashcard_div.css("background-image", excursion.background.src);

  		//and now we add the points of interest with their click events to show the slides
  		for(index in excursion.background.pois){
  			var poi = excursion.background.pois[index];
  			var div_to_add = "

";

  			flashcard_div.append(div_to_add);
  			$(document).on('click', "#" + poi.id,  { slide_id: poi.slide_id}, _onPoiClicked);
  		}

      $(document).on('click','.close_slide', _onCloseSlideClicked);

	};

	/**
	 * function called when a poi is clicked
	 */
	 var _onPoiClicked = function(event){
	 	V.Debugging.log("Show slide " + event.data.slide_id);
    V.Slides.showSlide(event.data.slide_id);
	 };

   var _onCloseSlideClicked = function(event){
    var close_slide = event.target.id.substring(5); //the id is close3
    V.Debugging.log("Close slide " + close_slide);
    V.Slides.closeSlide(close_slide);
   };

	return {
		init		: init

	};
}) (VISH, jQuery);<commit_msg>bug fix for flashcard<commit_after>VISH.Flashcard = (function(V,$,undefined){

	var init = function(excursion){
		var fileref=document.createElement("link");
  		fileref.setAttribute("rel", "stylesheet");
  		fileref.setAttribute("type", "text/css");
  		fileref.setAttribute("href", VISH.StylesheetsPath + "flashcard/flashcard.css");
  		document.getElementsByTagName("body")[0].appendChild(fileref);

  		var flashcard_div = $("#flashcard-background");
  		//first we set the flashcard background image
  		flashcard_div.css("background-image", excursion.background.src);

  		//and now we add the points of interest with their click events to show the slides
  		for(index in excursion.background.pois){
  			var poi = excursion.background.pois[index];
  			var div_to_add = "

";

  			flashcard_div.append(div_to_add);
  			$(document).on('click', "#" + poi.id,  { slide_id: poi.slide_id}, _onPoiClicked);
  		}

      $(document).on('click','.close_slide', _onCloseSlideClicked);

	};

	/**
	 * function called when a poi is clicked
	 */
	 var _onPoiClicked = function(event){
	 	V.Debugging.log("Show slide " + event.data.slide_id);
    V.Slides.showSlide(event.data.slide_id);
	 };

   var _onCloseSlideClicked = function(event){
    var close_slide = event.target.id.substring(5); //the id is close3
    V.Debugging.log("Close slide " + close_slide);
    V.Slides.closeSlide(close_slide);
   };

	return {
		init		: init

	};
}) (VISH, jQuery);<|endoftext|>


<commit_before>import React from 'react';
import cx from 'classnames';
import omit from 'lodash/object/omit';

/**
 * ### To be used with `ReactTransitionGroup` to show transitions for a component
 */
const propTypes = {
  /**
   * the component you want to animate (it must have a unique "key")
   */
  children: React.PropTypes.node.isRequired,
  /**
   * custom component to be used as wrapper for `children`
   */
  component: React.PropTypes.any,
  /**
   * object with inline-style for each transition event. It's also possible to use `css` classes (formatted in kebab-case)
   */
  transitionStyles: React.PropTypes.shape({
    enter: React.PropTypes.object,
    enterActive: React.PropTypes.object,
    default: React.PropTypes.object,
    leave: React.PropTypes.object,
    leaveActive: React.PropTypes.object
  }),
  /**
   * duration of enter transition in milliseconds
   */
  transitionEnterTimeout: React.PropTypes.number.isRequired,
  /**
   * duration of leave transition in milliseconds
   */
  transitionLeaveTimeout: React.PropTypes.number.isRequired,
  className: React.PropTypes.string,
  style: React.PropTypes.object
};

export default class TransitionWrapper extends React.Component {

  static propTypes = propTypes

  static defaultProps = {
    transitionStyles: {},
    style: {},
    component: 'div'
  }

  _replaceState = (state) => {
    this.state = state;
    this.forceUpdate();
  }

  startAnimation(anim, timeout, callback) {
    const { transitionStyles } = this.props;
    const animationStart = transitionStyles[anim];
    const animationEnd = transitionStyles[`${anim}Active`];

    const initState = { animationStart, transitionClassName: anim };
    const activeState = { animationEnd, transitionClassName: cx(anim, `${anim}-active`) };

    this._replaceState(initState);
    setTimeout(() => {
      this.setState(activeState);
      setTimeout(callback, timeout);
    }, 30); // if the render is too fast the animation fails... 30ms is an empiric value.
  }

  componentWillAppear = (callback) => this.componentWillEnter(callback)

  componentDidAppear = (callback) => this.componentDidEnter(callback)

  componentWillEnter = (callback) => (
    this.startAnimation('enter', this.props.transitionEnterTimeout, callback)
  )

  componentDidEnter = () => (
    this._replaceState({ defaultStyle: this.props.transitionStyles.default })
  )

  componentWillLeave = (callback) => (
    this.startAnimation('leave', this.props.transitionLeaveTimeout, callback)
  )

  getStyle = () => {
    const { style } = this.props;
    const { animationStart, animationEnd, defaultStyle } = this.state;
    const userTransform = (animationEnd || animationStart || defaultStyle || {}).transform;

    return {
      ...style,
      ...defaultStyle,
      ...animationStart,
      ...animationEnd,
      transform: cx(userTransform, style.transform)
    };
  }

  render() {
    if (!this.state) {
      return null;
    }
    const { children, className, component } = this.props;
    const { transitionClassName } = this.state;

    const props = {
      className: cx(className, transitionClassName),
      style: this.getStyle(),
      ...omit(this.props, Object.keys(propTypes))
    };

    return React.createElement(
      component,
      props,
      children
    );
  }

}
<commit_msg>udpate TransitionWrapper<commit_after>import React from 'react';
import cx from 'classnames';
import omit from 'lodash/object/omit';

/**
 * ### To be used with `ReactTransitionGroup` to show transitions for a component
 */
const PropTypes = {
  /**
   * the component you want to animate (it must have a unique "key")
   */
  children: t.ReactNode,
  /**
   * custom component to be used as wrapper for `children`.
   * Can be either an html tag name string (eg. 'div', 'span', etc), or a `ReactClass` (eg. `FlexView`)
   */
  component: React.PropTypes.any,
  /**
   * object with inline-style for each transition event. It's also possible to use `css` classes (formatted in kebab-case)
   */
  transitionStyles: t.maybe(t.struct({
    enter: t.maybe(t.Object),
    enterActive: t.maybe(t.Object),
    default: t.maybe(t.Object),
    leave: t.maybe(t.Object),
    leaveActive: t.maybe(t.Object)
  })),
  /**
   * duration of enter transition in milliseconds
   */
  transitionEnterTimeout: t.Number,
  /**
   * duration of leave transition in milliseconds
   */
  transitionLeaveTimeout: t.Number,
  className: t.maybe(t.String),
  style: t.maybe(t.Object)
};

@props(PropTypes, { strict: false })
export default class TransitionWrapper extends React.Component {

  static defaultProps = {
    transitionStyles: {},
    style: {},
    component: 'div'
  }

  _replaceState = (state) => {
    this.state = state;
    this.forceUpdate();
  }

  startAnimation(anim, timeout, callback) {
    const { transitionStyles } = this.props;
    const animationStart = transitionStyles[anim];
    const animationEnd = transitionStyles[`${anim}Active`];

    const initState = { animationStart, transitionClassName: anim };
    const activeState = { animationEnd, transitionClassName: cx(anim, `${anim}-active`) };

    this._replaceState(initState);
    setTimeout(() => {
      this.setState(activeState);
      setTimeout(callback, timeout);
    }, 30); // if the render is too fast the animation fails... 30ms is an empiric value.
  }

  componentWillAppear = (callback) => this.componentWillEnter(callback)

  componentDidAppear = (callback) => this.componentDidEnter(callback)

  componentWillEnter = (callback) => (
    this.startAnimation('enter', this.props.transitionEnterTimeout, callback)
  )

  componentDidEnter = () => (
    this._replaceState({ defaultStyle: this.props.transitionStyles.default })
  )

  componentWillLeave = (callback) => (
    this.startAnimation('leave', this.props.transitionLeaveTimeout, callback)
  )

  getStyle = () => {
    const { style } = this.props;
    const { animationStart, animationEnd, defaultStyle } = this.state;
    const userTransform = (animationEnd || animationStart || defaultStyle || {}).transform;

    return {
      ...style,
      ...defaultStyle,
      ...animationStart,
      ...animationEnd,
      transform: cx(userTransform, style.transform)
    };
  }

  render() {
    if (!this.state) {
      return null;
    }
    const { children, className, component } = this.props;
    const { transitionClassName } = this.state;

    const props = {
      className: cx(className, transitionClassName),
      style: this.getStyle(),
      ...omit(this.props, Object.keys(PropTypes))
    };

    return React.createElement(
      component,
      props,
      children
    );
  }

}
<|endoftext|>


<commit_before>javascript:
(function(){

lang = "zh-hant";

function getTranslatewikiLink(str) {
	match = str.match(/\(([^:)]+)/g);
	res = [];
	if (match !== undefined) {
		$(match).each(function(i, m){
			m = m.substr(1);
			res.push('('+m+')local');
		});
	}
	return res;
}
$(document).click(function(event) {
	el = $(event.target);
	if ($(el).attr("class") == "mw-notification-content") {
		return;
	}
	msg = "translatewiki links:";
	msg += "
text: ";
	hasmsg = false;
	if (el.text() !== undefined) {
		res = getTranslatewikiLink(el.text());
		$(res).each(function(i, a){
			msg += a+" ";
			hasmsg = true;
		});
	}
	msg += "
title: ";
	if (el.attr("title") !== undefined) {
		res = getTranslatewikiLink(el.attr("title"));
		$(res).each(function(i, a){
			msg += a+" ";
			hasmsg = true;
		});
	}
	if (hasmsg) {
		mw.notify([msg]);
	}
	return false;
});

})();
<commit_msg>change translatewiki.js to wikipeda gadget<commit_after>(function(){

var lang = "zh-hant";

function getTranslatewikiLink(str) {
	match = str.match(/\(([^:)]+)/g);
	res = [];
	if (match !== undefined) {
		$(match).each(function(i, m){
			m = m.substr(1);
			res.push('('+m+')local');
		});
	}
	return res;
}

function main() {
	$(document).click(function(event) {
		el = $(event.target);
		if ($(el).attr("class") == "mw-notification-content") {
			return;
		}
		msg = "translatewiki links:";
		hasmsg = false;
		if (el.text()) {
			res = getTranslatewikiLink(el.text());
			if (res.length > 0) {
				msg += "
text: ";
			}
			$(res).each(function(i, a){
				msg += a+" ";
				hasmsg = true;
			});
		}
		if (el.attr("value")) {
			res = getTranslatewikiLink(el.attr("value"));
			if (res.length > 0) {
				msg += "
value: ";
			}
			$(res).each(function(i, a){
				msg += a+" ";
				hasmsg = true;
			});
		}
		if (el.attr("title")) {
			res = getTranslatewikiLink(el.attr("title"));
			if (res.length > 0) {
				msg += "
title: ";
			}
			$(res).each(function(i, a){
				msg += a+" ";
				hasmsg = true;
			});
		}
		if (hasmsg) {
			mw.notify([msg]);
		}
		return false;
	});
}

mw.loader.using('mediawiki.util').done(function() {
	if (mw.util.getParamValue('uselang') === 'qqx') {
		var node = mw.util.addPortletLink('p-cactions', '#', '取得translatewiki連結');
		$(node).click(function(e) {
			e.preventDefault();
			$(node).hide();

			main();
		});
	}
});

})();
<|endoftext|>


<commit_before>(function(root, factory) {

  // Set up Backbone appropriately for the environment. Start with AMD.
  if (typeof define === 'function' && define.amd) {
    define(['underscore', 'jquery', 'modernizr'], factory);

  // Next for Node.js or CommonJS. jQuery may not be needed as a module.
  } else if (typeof exports !== 'undefined') {
    var _ = require('underscore');
    var $ = require('jquery');
    var Modernizr = require('Modernizr');

    factory(_, $, Modernizr);

  // Finally, as a browser global.
  } else {
    root.Trans = factory(root._, (root.$ || root.jQuery), root.Modernizr);
  }

}(this, function(_, $, Modernizr) {

    'use strict';

    var w = window;
    var doc = document;

    var hasCSSTransitions = Modernizr.csstransitions;

    var transitionProperty = Modernizr.prefixed('transition');

    var transitionEndEvent = {
        WebkitTransition: 'webkitTransitionEnd',
        MozTransition: 'transitionend',
        OTransition: 'otransitionend',
        transition: 'transitionend'
    }[transitionProperty];

    var splitCommasOutside = function(str) {
        return str.split(/(?:,+\s)(?=(?:[^\(\)]|[\(\)|\(\)][^\(\)]*[\(|\)])*$)/g);
    };

    var addStyleTag = function(css) {
        var tag = doc.createElement('style');
        tag.setAttribute('type', 'text/css');
        doc.getElementsByTagName('head')[0].appendChild(tag);
        if (tag.styleSheet) {
            tag.styleSheet.cssText = css;
        } else {
            tag.appendChild(doc.createTextNode(css));
        }
    };

    function Trans($el, opts) {
        var ins = $el.data('trans');
        var _this = ins || this;
        var optsIsFn = $.isFunction(opts);

        _this.$el = $el;
        _this.el = $el[0];
        _this.opts = {};

        !optsIsFn && (_this.opts = opts || {});
        optsIsFn && (_this.opts.endAll = opts);

        if (!ins) {
            _this.$el.data('trans', _this.init());
        } else {
            return ins;
        }
    }

    Trans.css = '.js-notransition {' +
                '  -webkit-transition: none !important;' +
                '  -moz-transition: none !important;' +
                '  -o-transition: none !important;' +
                '  -ms-transition: none !important;' +
                '  transition: none !important;' +
                '}';

    Trans.autoProps = {
        'height': true,
        'width': true,
        'opacity': true,
    };

    Trans.maps = {
        'dimension': {
            'from': {
                '0px': '*',
                '*': '*'
            },
            'to': {
                '0px': '',
                '*': ''
            }
        },
        'display': {
            'opacity': {
                'from': {
                    '0': 'block',
                    '1': 'block'
                },
                'to': {
                    '0': 'none',
                    '1': 'block'
                }
            },
            'dimension': {
                'from': {
                    '0px': 'block',
                    '*': 'block'
                },
                'to': {
                    '0px': '',
                    '*': 'block'
                }
            }
        }
    };

    Trans.methods = {
        'add': $.fn.addClass,
        'remove': $.fn.removeClass
    };

    _.extend(Trans.prototype, {
        init: function() {
            this.transClass = '';
            this.transProps = {};
            this.transPrefix = _.filter(Modernizr._cssomPrefixes, function(prfx) {
                return Modernizr.prefixed(prfx + 'Transition');
            })[0];
            return this;
        },

        repaint: function() {
            this.$el.width();
        },

        manageAutoProps: function(point, props) {
            props || (props = this.transProps);
            var css = {};

            if (!_.intersection(_.keys(Trans.autoProps), _.keys(props)).length) {
                return;
            }

            var _setProp = function(prop, subprop) {
                var fromVal, toVal, i, val, size, z;
                fromVal = props[(subprop || prop)]['from'];
                toVal = props[(subprop || prop)]['to'];
                i = props[(subprop || prop)][point];

                switch (prop) {
                    case "display":
                        if (fromVal !== '0px' && toVal !== '0px') { return; }
                        i === '0px' || (i = '*');
                        val = Trans.maps.display.dimension[point][i];
                        css['display'] = val;
                    break;

                    case "width":
                    case "height":
                        if ((fromVal == 'auto' || toVal == 'auto') ||
                            (fromVal == '0px' || toVal == '0px')) {
                            size = i !== '0px' ? fromVal : toVal;
                            z = i === '0px' ? '0px' : '*';
                            val = Trans.maps.dimension[point][z];
                            if (val === '*') { val = size; }
                            css[prop] = val;
                        }
                    break;
                }

            };

            if (props['opacity']) {
                var j = props['opacity'][point];
                // console.log(i, point, '---', Trans.maps.display.opacity[point][i]);
                css['display'] = Trans.maps.display.opacity[point][j];
            }

            _.each(['width', 'height'], function(prop) {
                if (props[prop]) {
                    _setProp('display', prop);
                    // _setProp(prop);
                }
            });

            if (_.size(css)) {
                this.$el.css(css);
                this.repaint();
            }
        },

        getTransitionValue: function() {
            var style = w.getComputedStyle(this.el, null);
            this.transitionValue = style.getPropertyValue(transitionProperty);

            if (!hasCSSTransitions) {
                this.transitionValue = splitCommasOutside(this.$el.css('transition'));
                return;
            }

            // firefox doesn't return data in shorthand CSS props
            if (!this.transitionValue || !this.transitionValue.length) {
                // TODO: move this to a test method fired after init
                var prefix = this.transPrefix;
                var properties = this.$el.css(prefix + 'TransitionProperty').split(', ');

                var transitions = [];
                for (var i = properties.length - 1; i >= 0; i--) {
                    transitions.push(properties[i]);
                }
                // whitespace after comma is required
                this.transitionValue = transitions.join(', ');
            }

            this.transitionValue = splitCommasOutside(this.transitionValue);
        },

        getTransProps: function(method) {
            var fProp, tProp;
            var res = {};

            this.getTransitionValue();

            this.$el.addClass('js-notransition');
            var fromProps = this.getFromProps(method);
            var toProps = this.getToProps(method === 'add' ? 'remove' : 'add');
            this.$el.removeClass('js-notransition');

            for (var propKey in fromProps) {
                fProp = fromProps[propKey];
                tProp = toProps[propKey];

                if (fProp.from !== tProp.to) {
                    fProp.to = tProp.to;
                    res[propKey] = fProp;
                }
            }
            return res;
        },

        getFromProps: function(method) {
            var props = this.getCurrentProps('from');
            Trans.methods[method].call(this.$el, this.transClass);
            this.repaint();
            return props;
        },

        getToProps: function(method) {
            var props = this.getCurrentProps('to');
            Trans.methods[method].call(this.$el, this.transClass);
            this.repaint();
            return props;
        },

        getCurrentProps: function(point) {
            var prop, propKey, transProps, resProp;
            var res = {};
            var style = w.getComputedStyle(this.el, null);
            var propKeys = 'property duration timing-function delay'.split(' ');
            var props = this.transitionValue;

            if (!props.length) { return false; }

            for (var i = props.length - 1; i >= 0; i--) {
                transProps = props[i].split(' ');
                propKey = transProps[0];
                resProp = {};
                resProp[point] = style.getPropertyValue(propKey);
                for (var j = propKeys.length - 1; j >= 0; j--) {
                    resProp[propKeys[j]] = transProps[j];
                }
                res[propKey] = resProp;
            }

            return res;
        },

        addTransClass: function(transClass) {
            this.transClass = transClass;
            this.transition('add');
        },

        removeTransClass: function(transClass) {
            this.transClass = transClass;
            this.transition('remove');
        },

        _transitionFallback: function() {
            $.each(this.transProps, function(propKey, val) {
                this._end(propKey);
            }.bind(this));

            this.endAll();
        },

        transition: function(method) {
            this.stop();

            this.transProps = this.getTransProps(method);

            if (hasCSSTransitions) {
                this.$el.on(transitionEndEvent + '.trans', {
                    endAll: _.after(_.size(this.transProps), _.bind(this.endAll, this))
                }, _.bind(this.end, this));

                this.manageAutoProps('from');
            }

            // transition start
            this.transitionActive = true;
            Trans.methods[method].call(this.$el, this.transClass);
            // fire end events when no csstransitions support
            !hasCSSTransitions && this._transitionFallback();
        },

        stop: function() {
            if (!this.transitionActive) { return; }

            this.$el.addClass('js-notransition');
            this.repaint();
            this.$el.removeClass('js-notransition');
            this.endAll();
        },

        _end: function(propKey) {
            var args = [propKey, this];
            this.$el.trigger('trans:end', args);
            this.$el.trigger('trans:end:' + propKey, args);
            this.opts.end && this.opts.end.apply(this.$el, args);
        },

        // e.originalEvent[type || propertyName || elapsedTime || eventPhase]
        end: function(e) {
            var propKey = e.originalEvent.propertyName;

            // ignore other transitionEnd events bubbling up
            if (e.handleObj.namespace !== 'trans' ||
                !this.transProps[propKey] ||
                e.target !== this.el
            ) {
                return;
            }

            this._end(propKey);
            this.transitionActive && e.data.endAll.call(this, e);
        },

        endAll: function(e) {
            var propKey = e && e.originalEvent.propertyName;
            this.transitionActive = false;

            /* Not called in end method because Firefox stops transition if
             * display property is changed during animation */
            hasCSSTransitions && this.manageAutoProps('to');

            this.$el.trigger('trans:endAll', [this]);
            this.opts.endAll && this.opts.endAll.call(this.$el, this);

            this.$el.off('.trans');
            delete this.transProps;
        },

        destroy: function() {
            this.stop();
            this.$el.removeData('trans');
        }
    });

    addStyleTag(Trans.css);

    // jquerify
    $.fn.addTransClass = function(transClass, opts) {
        var t = new Trans(this.eq(0), opts);
        t.addTransClass(transClass);
        return t.$el;
    };

    $.fn.removeTransClass = function(transClass, opts) {
        var t = new Trans(this.eq(0), opts);
        t.removeTransClass(transClass);
        return t.$el;
    };

    return Trans;

}));<commit_msg>feat(utils): basic `transEnd` jQuery event type and `transEnd` method<commit_after>(function(root, factory) {

  // Set up Backbone appropriately for the environment. Start with AMD.
  if (typeof define === 'function' && define.amd) {
    define(['underscore', 'jquery', 'modernizr'], factory);

  // Next for Node.js or CommonJS. jQuery may not be needed as a module.
  } else if (typeof exports !== 'undefined') {
    var _ = require('underscore');
    var $ = require('jquery');
    var Modernizr = require('Modernizr');

    factory(_, $, Modernizr);

  // Finally, as a browser global.
  } else {
    root.Trans = factory(root._, (root.$ || root.jQuery), root.Modernizr);
  }

}(this, function(_, $, Modernizr) {

    'use strict';

    var w = window;
    var doc = document;

    var hasCSSTransitions = Modernizr.csstransitions;

    var transitionProperty = Modernizr.prefixed('transition');

    var transitionEndEvent = {
        WebkitTransition: 'webkitTransitionEnd',
        MozTransition: 'transitionend',
        OTransition: 'otransitionend',
        transition: 'transitionend'
    }[transitionProperty];

    var splitCommasOutside = function(str) {
        return str.split(/(?:,+\s)(?=(?:[^\(\)]|[\(\)|\(\)][^\(\)]*[\(|\)])*$)/g);
    };

    var addStyleTag = function(css) {
        var tag = doc.createElement('style');
        tag.setAttribute('type', 'text/css');
        doc.getElementsByTagName('head')[0].appendChild(tag);
        if (tag.styleSheet) {
            tag.styleSheet.cssText = css;
        } else {
            tag.appendChild(doc.createTextNode(css));
        }
    };

    function Trans($el, opts) {
        var ins = $el.data('trans');
        var _this = ins || this;
        var optsIsFn = $.isFunction(opts);

        _this.$el = $el;
        _this.el = $el[0];
        _this.opts = {};

        !optsIsFn && (_this.opts = opts || {});
        optsIsFn && (_this.opts.endAll = opts);

        if (!ins) {
            _this.$el.data('trans', _this.init());
        } else {
            return ins;
        }
    }

    Trans.css = '.js-notransition {' +
                '  -webkit-transition: none !important;' +
                '  -moz-transition: none !important;' +
                '  -o-transition: none !important;' +
                '  -ms-transition: none !important;' +
                '  transition: none !important;' +
                '}';

    Trans.autoProps = {
        'height': true,
        'width': true,
        'opacity': true,
    };

    Trans.maps = {
        'dimension': {
            'from': {
                '0px': '*',
                '*': '*'
            },
            'to': {
                '0px': '',
                '*': ''
            }
        },
        'display': {
            'opacity': {
                'from': {
                    '0': 'block',
                    '1': 'block'
                },
                'to': {
                    '0': 'none',
                    '1': 'block'
                }
            },
            'dimension': {
                'from': {
                    '0px': 'block',
                    '*': 'block'
                },
                'to': {
                    '0px': '',
                    '*': 'block'
                }
            }
        }
    };

    Trans.methods = {
        'add': $.fn.addClass,
        'remove': $.fn.removeClass
    };

    _.extend(Trans.prototype, {
        init: function() {
            this.transClass = '';
            this.transProps = {};
            this.transPrefix = _.filter(Modernizr._cssomPrefixes, function(prfx) {
                return Modernizr.prefixed(prfx + 'Transition');
            })[0];
            return this;
        },

        repaint: function() {
            this.$el.width();
        },

        manageAutoProps: function(point, props) {
            props || (props = this.transProps);
            var css = {};

            if (!_.intersection(_.keys(Trans.autoProps), _.keys(props)).length) {
                return;
            }

            var _setProp = function(prop, subprop) {
                var fromVal, toVal, i, val, size, z;
                fromVal = props[(subprop || prop)]['from'];
                toVal = props[(subprop || prop)]['to'];
                i = props[(subprop || prop)][point];

                switch (prop) {
                    case "display":
                        if (fromVal !== '0px' && toVal !== '0px') { return; }
                        i === '0px' || (i = '*');
                        val = Trans.maps.display.dimension[point][i];
                        css['display'] = val;
                    break;

                    case "width":
                    case "height":
                        if ((fromVal == 'auto' || toVal == 'auto') ||
                            (fromVal == '0px' || toVal == '0px')) {
                            size = i !== '0px' ? fromVal : toVal;
                            z = i === '0px' ? '0px' : '*';
                            val = Trans.maps.dimension[point][z];
                            if (val === '*') { val = size; }
                            css[prop] = val;
                        }
                    break;
                }

            };

            if (props['opacity']) {
                var j = props['opacity'][point];
                // console.log(i, point, '---', Trans.maps.display.opacity[point][i]);
                css['display'] = Trans.maps.display.opacity[point][j];
            }

            _.each(['width', 'height'], function(prop) {
                if (props[prop]) {
                    _setProp('display', prop);
                    // _setProp(prop);
                }
            });

            if (_.size(css)) {
                this.$el.css(css);
                this.repaint();
            }
        },

        getTransitionValue: function() {
            var style = w.getComputedStyle(this.el, null);
            this.transitionValue = style.getPropertyValue(transitionProperty);

            if (!hasCSSTransitions) {
                this.transitionValue = splitCommasOutside(this.$el.css('transition'));
                return;
            }

            // firefox doesn't return data in shorthand CSS props
            if (!this.transitionValue || !this.transitionValue.length) {
                // TODO: move this to a test method fired after init
                var prefix = this.transPrefix;
                var properties = this.$el.css(prefix + 'TransitionProperty').split(', ');

                var transitions = [];
                for (var i = properties.length - 1; i >= 0; i--) {
                    transitions.push(properties[i]);
                }
                // whitespace after comma is required
                this.transitionValue = transitions.join(', ');
            }

            this.transitionValue = splitCommasOutside(this.transitionValue);
        },

        getTransProps: function(method) {
            var fProp, tProp;
            var res = {};

            this.getTransitionValue();

            this.$el.addClass('js-notransition');
            var fromProps = this.getFromProps(method);
            var toProps = this.getToProps(method === 'add' ? 'remove' : 'add');
            this.$el.removeClass('js-notransition');

            for (var propKey in fromProps) {
                fProp = fromProps[propKey];
                tProp = toProps[propKey];

                if (fProp.from !== tProp.to) {
                    fProp.to = tProp.to;
                    res[propKey] = fProp;
                }
            }
            return res;
        },

        getFromProps: function(method) {
            var props = this.getCurrentProps('from');
            Trans.methods[method].call(this.$el, this.transClass);
            this.repaint();
            return props;
        },

        getToProps: function(method) {
            var props = this.getCurrentProps('to');
            Trans.methods[method].call(this.$el, this.transClass);
            this.repaint();
            return props;
        },

        getCurrentProps: function(point) {
            var prop, propKey, transProps, resProp;
            var res = {};
            var style = w.getComputedStyle(this.el, null);
            var propKeys = 'property duration timing-function delay'.split(' ');
            var props = this.transitionValue;

            if (!props.length) { return false; }

            for (var i = props.length - 1; i >= 0; i--) {
                transProps = props[i].split(' ');
                propKey = transProps[0];
                resProp = {};
                resProp[point] = style.getPropertyValue(propKey);
                for (var j = propKeys.length - 1; j >= 0; j--) {
                    resProp[propKeys[j]] = transProps[j];
                }
                res[propKey] = resProp;
            }

            return res;
        },

        addTransClass: function(transClass) {
            this.transClass = transClass;
            this.transition('add');
        },

        removeTransClass: function(transClass) {
            this.transClass = transClass;
            this.transition('remove');
        },

        _transitionFallback: function() {
            $.each(this.transProps, function(propKey, val) {
                this._end(propKey);
            }.bind(this));

            this.endAll();
        },

        transition: function(method) {
            this.stop();

            this.transProps = this.getTransProps(method);

            if (hasCSSTransitions) {
                this.$el.on(transitionEndEvent + '.trans', {
                    endAll: _.after(_.size(this.transProps), _.bind(this.endAll, this))
                }, _.bind(this.end, this));

                this.manageAutoProps('from');
            }

            // transition start
            this.transitionActive = true;
            Trans.methods[method].call(this.$el, this.transClass);
            // fire end events when no csstransitions support
            !hasCSSTransitions && this._transitionFallback();
        },

        stop: function() {
            if (!this.transitionActive) { return; }

            this.$el.addClass('js-notransition');
            this.repaint();
            this.$el.removeClass('js-notransition');
            this.endAll();
        },

        _end: function(propKey) {
            var args = [propKey, this];
            this.$el.trigger('trans:end', args);
            this.$el.trigger('trans:end:' + propKey, args);
            this.opts.end && this.opts.end.apply(this.$el, args);
        },

        // e.originalEvent[type || propertyName || elapsedTime || eventPhase]
        end: function(e) {
            var propKey = e.originalEvent.propertyName;

            // ignore other transitionEnd events bubbling up
            if (e.handleObj.namespace !== 'trans' ||
                !this.transProps[propKey] ||
                e.target !== this.el
            ) {
                return;
            }

            this._end(propKey);
            this.transitionActive && e.data.endAll.call(this, e);
        },

        endAll: function(e) {
            var propKey = e && e.originalEvent.propertyName;
            this.transitionActive = false;

            /* Not called in end method because Firefox stops transition if
             * display property is changed during animation */
            hasCSSTransitions && this.manageAutoProps('to');

            this.$el.trigger('trans:endAll', [this]);
            this.opts.endAll && this.opts.endAll.call(this.$el, this);

            this.$el.off('.trans');
            delete this.transProps;
        },

        destroy: function() {
            this.stop();
            this.$el.removeData('trans');
        }
    });

    addStyleTag(Trans.css);

    // jquerify
    $.fn.addTransClass = function(transClass, opts) {
        var t = new Trans(this.eq(0), opts);
        t.addTransClass(transClass);
        return t.$el;
    };

    $.fn.removeTransClass = function(transClass, opts) {
        var t = new Trans(this.eq(0), opts);
        t.removeTransClass(transClass);
        return t.$el;
    };

    $.fn.transEnd = function(callback) {
        var cb = _.bind(callback, this);
        this.one(transitionEndEvent, function(e) {
            var propKey = e.originalEvent.propertyName;
            cb(propKey);
        });
        return this;
    };

    $.event.special.transEnd = {
        setup: function() {
            $(this).on(transitionEndEvent + '.transEt', function() {
                $(this).triggerHandler('transEnd');
            });
        },

        teardown: function() {
            $(this).off(transitionEndEvent + '.transEt');
        }
    };

    return Trans;

}));<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Link } from 'react-router';
import { connect } from 'react-redux';
import { searchRecipes } from '../utils/utils.js';
import actions from '../actions/index.js';
import { push } from 'react-router-redux';
import { EMPTY_RECIPE } from '../constants/EmptyRecipe.js';
import '../scss/_nav.scss';

class Nav extends Component {
  render() {
    const { user, avatar, search, recipeID, navToCreate, dispatch } = this.props;
    let { searchString } = this.props;
    let signInOut, linkToProfile;
    if (!user.id) {
      signInOut = Sign In;
    } else {
      signInOut = Sign out;
      linkToProfile = (
        <Link to={`/profile/${user.id}`}>

        </Link>);
    }
    return (

            <Link to="/">GitCooking</Link>
            <input
              className="search-bar"
              placeholder="Search for recipes"
              onChange={(e) => { searchString = e.target.value; }}
            ></input>
            <button
              onClick={(e) => {
                e.preventDefault();
                e.stopPropagation();
                search(searchString);
              }}
            > Search </button>
            <button
              onClick={(e) => {
                e.preventDefault();
                e.stopPropagation();
                navToCreate();
              }}> Create
            </button>
            Discover

              {signInOut}
              {linkToProfile}

          {/* <Link to={`/recipe/${recipeID}`}>Recipe</Link>*/}

    );
  }
}

const mapStateToProps = (state) => {
  return {
    user: state.user,
    avatar: state.user.photos[0].value,
    recipeID: state.recipe.id,
    // map a local variable to props
    searchString: '',
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    search: (query) => {
      searchRecipes(query, (recipeArray) => {
        dispatch(actions.setRecipeList(recipeArray));
        dispatch(push('/search'));
      });
    },
    navToCreate: () => {
      dispatch(actions.setRecipe(EMPTY_RECIPE));
      dispatch(push('/create'));
    },
    dispatch,
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(Nav);
<commit_msg>add Discover button<commit_after>import React, { Component } from 'react';
import { Link } from 'react-router';
import { connect } from 'react-redux';
import { searchRecipes } from '../utils/utils.js';
import actions from '../actions/index.js';
import { push } from 'react-router-redux';
import { EMPTY_RECIPE } from '../constants/EmptyRecipe.js';
import '../scss/_nav.scss';

class Nav extends Component {
  render() {
    const { user, avatar, search, recipeID, navToCreate, dispatch } = this.props;
    let { searchString } = this.props;
    let signInOut, linkToProfile;
    if (!user.id) {
      signInOut = Sign In;
    } else {
      signInOut = Sign out;
      linkToProfile = (
        <Link to={`/profile/${user.id}`}>

        </Link>);
    }
    return (

            <Link to="/">GitCooking</Link>
            <input
              className="search-bar"
              placeholder="Search for recipes"
              onChange={(e) => { searchString = e.target.value; }}
            ></input>
            <button
              onClick={(e) => {
                e.preventDefault();
                e.stopPropagation();
                search(searchString);
              }}
            > Search </button>
            <button
              onClick={(e) => {
                e.preventDefault();
                e.stopPropagation();
                navToCreate();
              }}> Create
            </button>
            <button>
              Discover
            </button>

              {signInOut}
              {linkToProfile}

          {/* <Link to={`/recipe/${recipeID}`}>Recipe</Link>*/}

    );
  }
}

const mapStateToProps = (state) => {
  return {
    user: state.user,
    avatar: state.user.photos[0].value,
    recipeID: state.recipe.id,
    // map a local variable to props
    searchString: '',
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    search: (query) => {
      searchRecipes(query, (recipeArray) => {
        dispatch(actions.setRecipeList(recipeArray));
        dispatch(push('/search'));
      });
    },
    navToCreate: () => {
      dispatch(actions.setRecipe(EMPTY_RECIPE));
      dispatch(push('/create'));
    },
    dispatch,
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(Nav);
<|endoftext|>


<commit_before>/*global window: false */
module.exports = function (ngModule) {
  'use strict';

  ngModule.service('Pouch', function ($rootScope, $q, $http, rooConfig, LocalStorageService) {

    var dbCache = {};

    function getDB(name) {
      if (!dbCache[name]) {
        dbCache[name] = new PouchDB(name, rooConfig.getDbOptions());
      }
      return dbCache[name];
    }

    /**
     * Function to update the records that are read-only
     * from the server with whatever changes have been
     * made on the client but have not yet been synced
     * to the server, for ui display purposes. This
     * is called currently from the MasterCtrl, so
     * basically on app load. change_id is dbname::id;
     * so, for example, looks something like this:
     *"gemini_cushion_fist::WO-20150226-2949689"
     */
    function shimRecords(downDbName, downDocs) {
      var deferred = $q.defer();
      var promises = [];
      var jorgeNames = rooConfig.getUpDbs();
      // Loop through all of the write databases
      _.each(jorgeNames, function (jorgeName) {
        // Get all the documents in the current write db
        getDB(jorgeName).allDocs({
          include_docs: true,
          attachments: true
        })
          .then(function (jorgeDocs) {
            if (jorgeDocs.total_rows > 0) {
              _.each(downDocs.rows, function (doc) {
                // If the current write db has any documents, loop through
                // them and see if any of the documents have a change_id that
                // matches the current read-only db
                _.each(jorgeDocs.rows, function (row) {
                  var d = $q.defer();
                  var change_id = row.doc.change_id;
                  var split = change_id.split('::');
                  var dbName = split[0];
                  var id = split[1];
                  if (dbName === downDbName) {
                    // Find if any document matches
                    if (doc.id === id) {
                      _.extend(doc.doc, JSON.parse(row.doc.change));

                      // Handle attachments
                      if (row.doc._attachments) {
                        if (doc._attachments) {
                          _.extend(doc._attachments, row.doc._attachments);
                        }
                        else {
                          doc._attachments = row.doc._attachments;
                        }
                      }
                    }
                  }
                  d.resolve(doc);
                  promises.push(d.promise);
                });
              });
            }
            $q.all(promises).then(function () {
              deferred.resolve(downDocs);
            });
          });
      });

      return deferred.promise;
    }

    /**
     * Function to update a given read-only record
     * from the server with whatever changes have been
     * made on the client but have not yet been synced
     * to the server, for ui display purposes. This
     * is called currently from the MasterCtrl, so
     * basically on app load. change_id is dbname::id;
     * so, for example, looks something like this:
     * "gemini_cushion_fist::WO-20150226-2949689"
     */
    function shimRecord(downDbName, downDoc) {
      var deferred = $q.defer();
      var jorgeNames = rooConfig.getUpDbs();
      // Loop through all of the write databases
      _.each(jorgeNames, function (jorgeName) {
        // Get all the documents in the current write db
        getDB(jorgeName).allDocs({
          include_docs: true,
          attachments: true
        }).then(function (jorgeDocs) {
          if (jorgeDocs.total_rows > 0) {
            // The the current write db has any documents, loop through
            // them and see if any of the documents have a change_id that
            // matches the current read-only db
            _.each(jorgeDocs.rows, function (row) {
              var change_id = row.doc.change_id;
              var split = change_id.split('::');
              var dbName = split[0];
              var id = split[1];
              if (dbName === downDbName) {
                // Find if any document matches
                if (downDoc._id === id) {
                  _.extend(downDoc, JSON.parse(row.doc.change));

                  // Handle attachments
                  if (row.doc._attachments) {
                    if (downDoc._attachments) {
                      _.extend(downDoc._attachments, row.doc._attachments);
                    }
                    else {
                      downDoc._attachments = row.doc._attachments;
                    }
                  }
                }
              }
            });
          }
          deferred.resolve(downDoc);
        });
      });
      return deferred.promise;
    }

    return function (db) {

      this.db = db;

      this.query = function (query, options) {
        var self = this;
        var deferred = $q.defer();

        var o = options || {};

        getDB(self.db).query(query, o)
          .then(function (doc) {
            return shimRecord(self.db, doc);
          }).then(function (doc) {
            deferred.resolve(doc);
          }).catch(function (err) {
            deferred.reject(err);
          });
        return deferred.promise;
      };

      this.getAll = function () {
        var self = this;
        var deferred = $q.defer();
        getDB(self.db).allDocs({
          include_docs: true,
          attachments: true
        }).then(function (docs) {
          return shimRecords(self.db, docs);
        }).then(function (docs) {
          deferred.resolve(_.pluck(docs.rows, 'doc'));
        }).catch(function (err) {
          deferred.reject(err);
        });
        return deferred.promise;
      };

      this.get = function (docId) {
        var self = this;
        var deferred = $q.defer();
        getDB(self.db).get(docId, {
          include_docs: true,
          attachments: true
        }).then(function (doc) {
          return shimRecord(self.db, doc);
        }).then(function (doc) {
          deferred.resolve(doc);
        }).catch(function (err) {
          deferred.reject(err);
        });
        return deferred.promise;
      };

      this.destroy = function() {
        var self = this;
        return getDB(self.db).query(function(doc, emit) {
          emit(doc);
        }, {limit: 0}).then(function () {
          // then destroy after the index is built
          console.log('Destroying ' + self.db);
          return getDB(self.db).destroy();
        });
      };

      /**
       * Retrieve attachment's local url
       * @param {string} docId - Document's id were the attachment exists.
       * @param {string} attrId - The id for the attachment itself.
       */
      this.getAttachment = function (docId, attrId) {
        var self = this;
        var deferred = $q.defer();
        var URL = window.URL;
        getDB(self.db).getAttachment(docId, attrId)
          .then(function (blob) {
            var url = URL.createObjectURL(blob);
            deferred.resolve(url);
          }).catch(function (err) {
            deferred.reject(err);
          });
        return deferred.promise;
      };

      this.putEntry = function (originTable, originId, changes, method, endpoint, data, headers, user, attachments, id) {
        if (endpoint.indexOf("://") === -1) { // check to make sure it's a fully qualified URL
          endpoint = window.location.protocol + "//" + window.location.host + endpoint;
        }

        var entry = {
            _id: new moment().toJSON(),
            change_id: '' + originTable + '::' + originId,
            change: JSON.stringify(changes),
            method: method,
            endpoint: endpoint,
            data: data,
            headers: headers,
            user: user,
            networkType: 'Not supported'
          },
          self = this,
          db = getDB(self.db);

        if (attachments && attachments.length > 0) {
          if (!(attachments instanceof Array)) {
            attachments = [attachments];
          }
          entry._attachments = {};
          var attachmentSize = 0;
          attachments.forEach(function (attachment) {
            attachmentSize += attachment.size;
            entry._attachments[attachment.name] = {
              'content_type': attachment.type,
              'data': attachment
            }
          });
          entry.attachmentSize = attachmentSize;
        }

        if (navigator.connection && navigator.connection.type) {
          entry.networkType = navigator.connection.type;
        }

        return navigator.getBattery()
          .then(function (battery) {
            return {
              charging: battery.charging,
              chargingTime: battery.chargingTime,
              dischargingTime: battery.dischargingTime,
              level: battery.level
            };
          })
          .then(function (batteryInfo) {
            entry.batteryInfo = batteryInfo;
            return getCoords();
          })
          .then(function (coords) {
            entry.location = {
              accuracy: coords.accuracy,
              altitude: coords.altitude,
              altitudeAccuracy: coords.altitudeAccuracy,
              heading: coords.heading,
              latitude: coords.latitude,
              longitude: coords.longitude,
              speed: coords.speed
            };
            return getUserAgent();
          })
          .then(function(userAgent) {
            entry.userAgent = userAgent;
            return db.put(entry);
          })
          .catch(function () {
            console.log('JORGe error!', arguments);
            return db.put(entry);
          });

      };

      this.getDocCount = function (query) {
        var self = this;
        var db = getDB(self.db);

        if (query) {
          return db.query(query, {include_docs: false}).then(function (docs) {
            return docs.rows.length;
          });
        }
        else {
          return db.allDocs().then(function (docs) {
            return docs.rows.length;
          });
        }
      };

      function getUserAgent() {
        var deferred = $q.defer();
        var returnVal = window.navigator.userAgent;
        deferred.resolve(returnVal);
        return deferred.promise;
      }

      function getCoords() {
        var timeoutVal = 10 * 1000 * 1000;
        var deferred = $q.defer();
        window.navigator.geolocation.getCurrentPosition(
          function (position) {
            deferred.resolve(position.coords);
          },
          function () {
            var errors = {
              1: 'Permission denied',
              2: 'Position unavailable',
              3: 'Request timeout'
            };
            deferred.reject("Error: " + errors[error.code]);
          },
          {enableHighAccuracy: true, timeout: timeoutVal, maximumAge: 0}
        );
        return deferred.promise;
      };

      this.deleteEntry = function (doc) {
        var self = this;

        if (typeof doc === 'string') {
          return getDB(self.db)
            .get(doc)
            .then(function (doc) {
              return getDB(self.db).remove(doc);
            })
        }
        else {
          return getDB(self.db).remove(doc);
        }
      }

      /**
       * Replicate db with predefined CouchDB
       * @param {object} user - Any User object to be passed into getParams.
       * @param {object} options - functions to determine params and filters.
       */
      this.replicateDB = function (user, opts) {
        var self = this;

        if (rooConfig.getOptions().destoryOnSync) {
          console.log('removing table', self.db);
          return getDB(self.db)
            .destroy()
            .then(function () {
              return self.performReplication(user, opts);
            });
        }
        else {
          return self.performReplication(user, opts);
        }
      };

      this.performReplication = function (user, opts) {
        var self = this;

        // Initialize the remote and local databases
        var token = 'Bearer ' + window.localStorage['auth-token'];
        var headers = {
          Authorization: token
        };
        var remote = new PouchDB(rooConfig.getCouchConfig().couchUrl + self.db, {
          headers: headers
        });
        var local = getDB(self.db);
        console.log('Replicating', self.db);
        var replicationOptions = _.extend({
          batch_size: 5
        }, opts);

        if (opts.getParams) {
          replicationOptions.query_params = opts.getParams(user);
        }

        // Perform replication
        var rep = local.replicate.from(remote, replicationOptions)
          .on('complete', function (result) {
						$rootScope.$emit('ng-roo-replicate-complete', result, self.db);
            try {
              // Make an entry in the logs
              LocalStorageService.addEntryToLog(user.employeeID, self.db, result);
            } catch (error) {
              console.log(error);
            }
          })
          .on('paused', function () {
						$rootScope.$emit('ng-roo-replicate-paused');
            rep.cancel();
          })
          .on('denied', function (err) {
						$rootScope.$emit('ng-roo-replicate-denied', err);
            rep.cancel();
          });
        rooConfig.getReplications[self.db] = rep;
      };

      this.performSync = function (user, opts) {
        var self = this;

        console.log('Syncing', self.db);
        var syncOptions = _.extend({
          batch_size: 5,
          live: true,
          retry: true
        }, opts);

        if (opts.getParams) {
          syncOptions.query_params = opts.getParams(user);
        }

        // Perform sync
        var token = 'Bearer ' + window.localStorage['auth-token'];
        var headers = {
          Authorization: token
        };
        var remote = new PouchDB(rooConfig.getCouchConfig().couchUrl + self.db, {
          ajax: {headers: headers, timeout: 60000}
        });
        var sync = PouchDB.sync(self.db, remote, syncOptions)
          .on('complete', function (result) {
						$rootScope.$emit('ng-roo-sync-complete', result, self.db);
            try {
              // Make an entry in the logs
              LocalStorageService.addEntryToLog(user.employeeID, self.db, result);
            } catch (error) {
              console.log(error);
            }
          })
          .on('change', function (info) {
						$rootScope.$emit('ng-roo-sync-change', info);
          })
          .on('error', function (err) {
						$rootScope.$emit('ng-roo-sync-error', err);
          })
          .on('active', function () {
						$rootScope.$emit('ng-roo-sync-active');
          })
          .on('paused', function () {
						$rootScope.$emit('ng-roo-sync-paused');
          })
          .on('denied', function (err) {
						$rootScope.$emit('ng-roo-sync-denied', err);
          });
        rooConfig.getReplications[self.db] = sync;
      };

      this.update = function (db, obj, id) {
        var deferred = $q.defer();
        var cushiondb = getDB(db);
        cushiondb.get(id).then(function success(doc) {
          var newDoc = _.extend(doc, obj);
          cushiondb.put(newDoc).then(function success(result) {
            deferred.resolve(result);
          }, function error(result) {
            deferred.reject(result);
          });
        }, function error(result) {
          deferred.reject(result);
        });
        return deferred.promise;
      };

      this.writeLogEntries = function (db, user) {
        console.log('Writing log entries for db ' + db + ' for user ' + user.displayName);
        var deferred = $q.defer();
        var promises = [];
        // Do some stuff here.
        getDB(db).allDocs({
          include_docs: true
        }).then(function (docs) {
          // Make an entry in the logs
          _.forEach(docs.rows, function (row) {
            promises.push(LocalStorageService.addEntryToLog(user.employeeID, db, row));
          });

          $q.all(promises).then(function (result) {
            deferred.resolve(result);
          }).catch(function (err) {
            deferred.reject(err);
          });
        });
        return deferred.promise;
      };
    };

  });
};
<commit_msg>Make destroy simpler<commit_after>/*global window: false */
module.exports = function (ngModule) {
  'use strict';

  ngModule.service('Pouch', function ($rootScope, $q, $http, rooConfig, LocalStorageService) {

    var dbCache = {};

    function getDB(name) {
      if (!dbCache[name]) {
        dbCache[name] = new PouchDB(name, rooConfig.getDbOptions());
      }
      return dbCache[name];
    }

    /**
     * Function to update the records that are read-only
     * from the server with whatever changes have been
     * made on the client but have not yet been synced
     * to the server, for ui display purposes. This
     * is called currently from the MasterCtrl, so
     * basically on app load. change_id is dbname::id;
     * so, for example, looks something like this:
     *"gemini_cushion_fist::WO-20150226-2949689"
     */
    function shimRecords(downDbName, downDocs) {
      var deferred = $q.defer();
      var promises = [];
      var jorgeNames = rooConfig.getUpDbs();
      // Loop through all of the write databases
      _.each(jorgeNames, function (jorgeName) {
        // Get all the documents in the current write db
        getDB(jorgeName).allDocs({
          include_docs: true,
          attachments: true
        })
          .then(function (jorgeDocs) {
            if (jorgeDocs.total_rows > 0) {
              _.each(downDocs.rows, function (doc) {
                // If the current write db has any documents, loop through
                // them and see if any of the documents have a change_id that
                // matches the current read-only db
                _.each(jorgeDocs.rows, function (row) {
                  var d = $q.defer();
                  var change_id = row.doc.change_id;
                  var split = change_id.split('::');
                  var dbName = split[0];
                  var id = split[1];
                  if (dbName === downDbName) {
                    // Find if any document matches
                    if (doc.id === id) {
                      _.extend(doc.doc, JSON.parse(row.doc.change));

                      // Handle attachments
                      if (row.doc._attachments) {
                        if (doc._attachments) {
                          _.extend(doc._attachments, row.doc._attachments);
                        }
                        else {
                          doc._attachments = row.doc._attachments;
                        }
                      }
                    }
                  }
                  d.resolve(doc);
                  promises.push(d.promise);
                });
              });
            }
            $q.all(promises).then(function () {
              deferred.resolve(downDocs);
            });
          });
      });

      return deferred.promise;
    }

    /**
     * Function to update a given read-only record
     * from the server with whatever changes have been
     * made on the client but have not yet been synced
     * to the server, for ui display purposes. This
     * is called currently from the MasterCtrl, so
     * basically on app load. change_id is dbname::id;
     * so, for example, looks something like this:
     * "gemini_cushion_fist::WO-20150226-2949689"
     */
    function shimRecord(downDbName, downDoc) {
      var deferred = $q.defer();
      var jorgeNames = rooConfig.getUpDbs();
      // Loop through all of the write databases
      _.each(jorgeNames, function (jorgeName) {
        // Get all the documents in the current write db
        getDB(jorgeName).allDocs({
          include_docs: true,
          attachments: true
        }).then(function (jorgeDocs) {
          if (jorgeDocs.total_rows > 0) {
            // The the current write db has any documents, loop through
            // them and see if any of the documents have a change_id that
            // matches the current read-only db
            _.each(jorgeDocs.rows, function (row) {
              var change_id = row.doc.change_id;
              var split = change_id.split('::');
              var dbName = split[0];
              var id = split[1];
              if (dbName === downDbName) {
                // Find if any document matches
                if (downDoc._id === id) {
                  _.extend(downDoc, JSON.parse(row.doc.change));

                  // Handle attachments
                  if (row.doc._attachments) {
                    if (downDoc._attachments) {
                      _.extend(downDoc._attachments, row.doc._attachments);
                    }
                    else {
                      downDoc._attachments = row.doc._attachments;
                    }
                  }
                }
              }
            });
          }
          deferred.resolve(downDoc);
        });
      });
      return deferred.promise;
    }

    return function (db) {

      this.db = db;

      this.query = function (query, options) {
        var self = this;
        var deferred = $q.defer();

        var o = options || {};

        getDB(self.db).query(query, o)
          .then(function (doc) {
            return shimRecord(self.db, doc);
          }).then(function (doc) {
            deferred.resolve(doc);
          }).catch(function (err) {
            deferred.reject(err);
          });
        return deferred.promise;
      };

      this.getAll = function () {
        var self = this;
        var deferred = $q.defer();
        getDB(self.db).allDocs({
          include_docs: true,
          attachments: true
        }).then(function (docs) {
          return shimRecords(self.db, docs);
        }).then(function (docs) {
          deferred.resolve(_.pluck(docs.rows, 'doc'));
        }).catch(function (err) {
          deferred.reject(err);
        });
        return deferred.promise;
      };

      this.get = function (docId) {
        var self = this;
        var deferred = $q.defer();
        getDB(self.db).get(docId, {
          include_docs: true,
          attachments: true
        }).then(function (doc) {
          return shimRecord(self.db, doc);
        }).then(function (doc) {
          deferred.resolve(doc);
        }).catch(function (err) {
          deferred.reject(err);
        });
        return deferred.promise;
      };

      this.destroy = function() {
        var self = this;
        return getDB(self.db).destroy();
      };

      /**
       * Retrieve attachment's local url
       * @param {string} docId - Document's id were the attachment exists.
       * @param {string} attrId - The id for the attachment itself.
       */
      this.getAttachment = function (docId, attrId) {
        var self = this;
        var deferred = $q.defer();
        var URL = window.URL;
        getDB(self.db).getAttachment(docId, attrId)
          .then(function (blob) {
            var url = URL.createObjectURL(blob);
            deferred.resolve(url);
          }).catch(function (err) {
            deferred.reject(err);
          });
        return deferred.promise;
      };

      this.putEntry = function (originTable, originId, changes, method, endpoint, data, headers, user, attachments, id) {
        if (endpoint.indexOf("://") === -1) { // check to make sure it's a fully qualified URL
          endpoint = window.location.protocol + "//" + window.location.host + endpoint;
        }

        var entry = {
            _id: new moment().toJSON(),
            change_id: '' + originTable + '::' + originId,
            change: JSON.stringify(changes),
            method: method,
            endpoint: endpoint,
            data: data,
            headers: headers,
            user: user,
            networkType: 'Not supported'
          },
          self = this,
          db = getDB(self.db);

        if (attachments && attachments.length > 0) {
          if (!(attachments instanceof Array)) {
            attachments = [attachments];
          }
          entry._attachments = {};
          var attachmentSize = 0;
          attachments.forEach(function (attachment) {
            attachmentSize += attachment.size;
            entry._attachments[attachment.name] = {
              'content_type': attachment.type,
              'data': attachment
            }
          });
          entry.attachmentSize = attachmentSize;
        }

        if (navigator.connection && navigator.connection.type) {
          entry.networkType = navigator.connection.type;
        }

        return navigator.getBattery()
          .then(function (battery) {
            return {
              charging: battery.charging,
              chargingTime: battery.chargingTime,
              dischargingTime: battery.dischargingTime,
              level: battery.level
            };
          })
          .then(function (batteryInfo) {
            entry.batteryInfo = batteryInfo;
            return getCoords();
          })
          .then(function (coords) {
            entry.location = {
              accuracy: coords.accuracy,
              altitude: coords.altitude,
              altitudeAccuracy: coords.altitudeAccuracy,
              heading: coords.heading,
              latitude: coords.latitude,
              longitude: coords.longitude,
              speed: coords.speed
            };
            return getUserAgent();
          })
          .then(function(userAgent) {
            entry.userAgent = userAgent;
            return db.put(entry);
          })
          .catch(function () {
            console.log('JORGe error!', arguments);
            return db.put(entry);
          });

      };

      this.getDocCount = function (query) {
        var self = this;
        var db = getDB(self.db);

        if (query) {
          return db.query(query, {include_docs: false}).then(function (docs) {
            return docs.rows.length;
          });
        }
        else {
          return db.allDocs().then(function (docs) {
            return docs.rows.length;
          });
        }
      };

      function getUserAgent() {
        var deferred = $q.defer();
        var returnVal = window.navigator.userAgent;
        deferred.resolve(returnVal);
        return deferred.promise;
      }

      function getCoords() {
        var timeoutVal = 10 * 1000 * 1000;
        var deferred = $q.defer();
        window.navigator.geolocation.getCurrentPosition(
          function (position) {
            deferred.resolve(position.coords);
          },
          function () {
            var errors = {
              1: 'Permission denied',
              2: 'Position unavailable',
              3: 'Request timeout'
            };
            deferred.reject("Error: " + errors[error.code]);
          },
          {enableHighAccuracy: true, timeout: timeoutVal, maximumAge: 0}
        );
        return deferred.promise;
      };

      this.deleteEntry = function (doc) {
        var self = this;

        if (typeof doc === 'string') {
          return getDB(self.db)
            .get(doc)
            .then(function (doc) {
              return getDB(self.db).remove(doc);
            })
        }
        else {
          return getDB(self.db).remove(doc);
        }
      }

      /**
       * Replicate db with predefined CouchDB
       * @param {object} user - Any User object to be passed into getParams.
       * @param {object} options - functions to determine params and filters.
       */
      this.replicateDB = function (user, opts) {
        var self = this;

        if (rooConfig.getOptions().destoryOnSync) {
          console.log('removing table', self.db);
          return getDB(self.db)
            .destroy()
            .then(function () {
              return self.performReplication(user, opts);
            });
        }
        else {
          return self.performReplication(user, opts);
        }
      };

      this.performReplication = function (user, opts) {
        var self = this;

        // Initialize the remote and local databases
        var token = 'Bearer ' + window.localStorage['auth-token'];
        var headers = {
          Authorization: token
        };
        var remote = new PouchDB(rooConfig.getCouchConfig().couchUrl + self.db, {
          headers: headers
        });
        var local = getDB(self.db);
        console.log('Replicating', self.db);
        var replicationOptions = _.extend({
          batch_size: 5
        }, opts);

        if (opts.getParams) {
          replicationOptions.query_params = opts.getParams(user);
        }

        // Perform replication
        var rep = local.replicate.from(remote, replicationOptions)
          .on('complete', function (result) {
						$rootScope.$emit('ng-roo-replicate-complete', result, self.db);
            try {
              // Make an entry in the logs
              LocalStorageService.addEntryToLog(user.employeeID, self.db, result);
            } catch (error) {
              console.log(error);
            }
          })
          .on('paused', function () {
						$rootScope.$emit('ng-roo-replicate-paused');
            rep.cancel();
          })
          .on('denied', function (err) {
						$rootScope.$emit('ng-roo-replicate-denied', err);
            rep.cancel();
          });
        rooConfig.getReplications[self.db] = rep;
      };

      this.performSync = function (user, opts) {
        var self = this;

        console.log('Syncing', self.db);
        var syncOptions = _.extend({
          batch_size: 5,
          live: true,
          retry: true
        }, opts);

        if (opts.getParams) {
          syncOptions.query_params = opts.getParams(user);
        }

        // Perform sync
        var token = 'Bearer ' + window.localStorage['auth-token'];
        var headers = {
          Authorization: token
        };
        var remote = new PouchDB(rooConfig.getCouchConfig().couchUrl + self.db, {
          ajax: {headers: headers, timeout: 60000}
        });
        var sync = PouchDB.sync(self.db, remote, syncOptions)
          .on('complete', function (result) {
						$rootScope.$emit('ng-roo-sync-complete', result, self.db);
            try {
              // Make an entry in the logs
              LocalStorageService.addEntryToLog(user.employeeID, self.db, result);
            } catch (error) {
              console.log(error);
            }
          })
          .on('change', function (info) {
						$rootScope.$emit('ng-roo-sync-change', info);
          })
          .on('error', function (err) {
						$rootScope.$emit('ng-roo-sync-error', err);
          })
          .on('active', function () {
						$rootScope.$emit('ng-roo-sync-active');
          })
          .on('paused', function () {
						$rootScope.$emit('ng-roo-sync-paused');
          })
          .on('denied', function (err) {
						$rootScope.$emit('ng-roo-sync-denied', err);
          });
        rooConfig.getReplications[self.db] = sync;
      };

      this.update = function (db, obj, id) {
        var deferred = $q.defer();
        var cushiondb = getDB(db);
        cushiondb.get(id).then(function success(doc) {
          var newDoc = _.extend(doc, obj);
          cushiondb.put(newDoc).then(function success(result) {
            deferred.resolve(result);
          }, function error(result) {
            deferred.reject(result);
          });
        }, function error(result) {
          deferred.reject(result);
        });
        return deferred.promise;
      };

      this.writeLogEntries = function (db, user) {
        console.log('Writing log entries for db ' + db + ' for user ' + user.displayName);
        var deferred = $q.defer();
        var promises = [];
        // Do some stuff here.
        getDB(db).allDocs({
          include_docs: true
        }).then(function (docs) {
          // Make an entry in the logs
          _.forEach(docs.rows, function (row) {
            promises.push(LocalStorageService.addEntryToLog(user.employeeID, db, row));
          });

          $q.all(promises).then(function (result) {
            deferred.resolve(result);
          }).catch(function (err) {
            deferred.reject(err);
          });
        });
        return deferred.promise;
      };
    };

  });
};
<|endoftext|>