<commit_before>
function SolveTime(time, scramble) { // solve time object
  this.time = time
  this.scramble = scramble
}

function Solve(name) { // session object (multiple times)
  this.name = name
  this.times = []
}

function DataManager() {
  this.solves = [] // array of Solve objects
  this.numberOfSolves = 0 // solves loaded into the app !! not the actual number (solves.length)
  this.currentSolve = 'Default'
  this.deleted = [] // list of deleted solves to undo
  this.lastScramble = ''
  this.file = null
  this.fr = null

  this.init = function() {
    if(typeof(Storage) == "undefined") {
      // Sorry! No Web Storage support..
      Error.print('Sorry! No Web Storage support..');
    }
    if (typeof JSON === "undefined") {
      Error.print('JSON not supported')
    }

    if (!window.File || !window.FileReader || !window.FileList || !window.Blob) {
      Error.print('Sorry, no html5 support in this browser')
    }

    document.getElementById('uploadjsoninput').addEventListener("change", evt = function() {
     Data.uploadjson(evt)
    });

    // load number of solves stored
    this.numberOfSolves = localStorage.getItem('numberOfSolves')
    if (this.numberOfSolves == null) this.numberOfSolves = 0
    // load solves from storage
    this.load()
    this.refresh()
    MainLayout.scrollDown()
  }

  this.resetSolves = function() {
    this.currentSolve = 'Default'
    this.solves = [new Solve('Default', [])]
    this.numberOfSolves = 1
  }

  this.load = function() {
    if (this.numberOfSolves == 0) {
      this.resetSolves()
    }
    else {
      // checks for old solves and converts them
      if (localStorage.getItem('solves') == null) {
        this.resetSolves()
        return
      }
      if (typeof(JSON.parse(localStorage.getItem('solves'))[0].times[0]) == "string") { // old solves
        var slvs = JSON.parse(localStorage.getItem('solves')) // all solves
        var nslvs = Object.keys(slvs).length
        for (var i=0; i<nslvs; i++) { // iterate solves
          var n = new Solve(slvs[i].name)
          for (var j=0; j<slvs[i].times.length; j++) {
            n.times.push(new SolveTime(slvs[i].times[j],'no scramble for this solve'))
          }
          this.solves.push(n)
        }
      } else { // new solves with scrambles
        this.solves = JSON.parse(localStorage.getItem('solves')) // JSON object in localstorage
      }
      this.currentSolve = localStorage['currentSolve']
      if (this.solves == null) {
        this.resetSolves()
      }
    }
  }

  this.save = function() {
    if (this.solves == null) { // no solves
      localStorage['numberOfSolves'] = 1
      localStorage['solves'] = JSON.stringify([new Solve('Default')])
      localStorage['currentSolve'] = 'Default'
    } else {
      localStorage['numberOfSolves'] = this.solves.length
      localStorage['solves'] = JSON.stringify(this.solves)
      localStorage['currentSolve'] = this.currentSolve
    }
  }

  this.updateSolveName = function() {
    var content = ''
    for (var i=0; i<this.solves.length; i++) {
      if (this.currentSolve == this.solves[i].name) content += '<option selected>'+this.solves[i].name+'</option>'
      else content += '<option>'+this.solves[i].name+'</option>'
    }
    document.getElementById('solveNames').innerHTML = content
    $('#solveNames').select2({
  			minimumResultsForSearch: Infinity,
				theme: "classic"
		});
  }

  this.changeSolve = function(index) {
    this.currentSolve = this.solves[index].name
    this.refresh()
    MainLayout.hideUndoDelete()
    $('#solveNames').select2("close");
  }

  this.delSolve = function() {
    if (confirm ("Are you sure to delete this Solve class?")) {
      var index = $("select[id='solveNames'] option:selected").index()
      this.solves.splice(parseInt(index), 1)
      if (this.solves.length == 0) {
        this.solves[0] = new Solve('Default')
        this.currentSolve = 'Default'
      } else {
        this.currentSolve = this.solves[0].name
      }
      this.refresh()
      MainLayout.hideUndoDelete()
    }
  }

  this.getIndex = function(name) {
    var exists = false
    for (var i=0; i<this.solves.length; i++) {
      if (this.solves[i].name == name) {
        exists = true; break
      }
    }
    if (exists) return i;
    else return -1;
  }

  this.getCurrentSolve = function() {
    return this.solves[this.getIndex(this.currentSolve)]
  }

  this.add = function() {
    var currentTime = document.getElementById("chronotime").innerHTML
    MainLayout.updateScramble()
    this.getCurrentSolve().times.push(new SolveTime(currentTime, this.lastScramble))
    MainLayout.scrollDown()
  }

  this.refresh = function() {
    if (this.solves.length == 0) return;
    var best = this.getBestTime();
    var table = '';
    var times = this.getCurrentSolve().times
    for (var i=0; i<times.length; i++) {
      if (i == best) {
          table += "
"+(parseInt(i)+1)+"	"+times[i].time+"
";
      } else {
          table += "
"+(parseInt(i)+1)+"	"+times[i].time+"
";
      }
    }
    document.getElementById('times-table').innerHTML = table
    this.save()
    this.updateSolveName()

    if (times.length == 0) {
      document.getElementById('best-solve').innerHTML = "Best: -"
      document.getElementById('average-all').innerHTML = "Average All: -"
      document.getElementById('average-5').innerHTML = "Average 5: -"
    }
    else {
      // display scores
      document.getElementById('best-solve').innerHTML = "Best: "+ times[best].time
      document.getElementById('average-all').innerHTML = "Average All: " + this.getAverageAll()
      if (times.length>4) document.getElementById('average-5').innerHTML = "Average 5: " + this.getAverage5();
      else document.getElementById('average-5').innerHTML = "Average 5: -"
    }
  }

  this.deleteTime = function(index) {
    this.deleted.push(this.getCurrentSolve().times[index])
    this.getCurrentSolve().times.splice(parseInt(index), 1)
    this.refresh();
    MainLayout.showUndoDelete();
  }

  this.undoLastDelete = function() {
    this.getCurrentSolve().times.push(this.deleted.pop())
    this.refresh()
    MainLayout.scrollDown()
    if (this.deleted.length < 1) {
        MainLayout.hideUndoDelete();
    }
  }

  this.saveBackground = function() {
    localStorage['bgIndex'] = (""+MainLayout.backgroundSelected)
  }

  this.restoreBackground = function() {
    return ( (localStorage.getItem('bgIndex') == 'undefined' || isNaN(localStorage.getItem('bgIndex'))) ? 0 : parseInt(localStorage.getItem('bgIndex')) )
  }

  // index of the best time in the array
  this.getBestTime = function() {
    var times = this.getCurrentSolve().times
    var best = 0; // index 0
    var i = 1;
    for (i=1; i<times.length; i++) {
      var old = this.getIntFromTimeString(times[best].time)
      var cur = this.getIntFromTimeString(times[i].time)

      if (cur < old) best = i;
    }

    return best;
  }

  this.getAverageAll = function() {
    var times = this.getCurrentSolve().times
    var i=0, average=0, min=0, sec=0, dec=0;

    for (i=0; i<times.length; i++) {
      min = parseInt(times[i].time.charAt(0)+times[i].time.charAt(1))
      sec = parseInt(times[i].time.charAt(3)+times[i].time.charAt(4))
      dec = parseInt(times[i].time.charAt(6)+times[i].time.charAt(7))
      // average in decimals
      average += ( (min*60*100) + (sec*100) + dec)
    }
    average /= times.length
    average = average.toFixed(0);

    return this.getAverageStringFromDec(average)
  }

  this.getAverage5 = function() {
    var times = this.getCurrentSolve().times
    var i=0, average=0, min=0, sec=0, dec=0;
    times = times.slice(times.length-5, times.length)
    times.sort(function(a,b){ return a.toString().localeCompare(b) }) // custom sort
    for (i=1; i<times.length-1; i++) {
      min = parseInt(times[i].time.charAt(0)+times[i].time.charAt(1))
      sec = parseInt(times[i].time.charAt(3)+times[i].time.charAt(4))
      dec = parseInt(times[i].time.charAt(6)+times[i].time.charAt(7))
      // average in decimals
      average += ( (min*60*100) + (sec*100) + dec)
    }
    average /= 3
    average = average.toFixed(0);

    return this.getAverageStringFromDec(average)
  }

  this.getAverageStringFromDec = function(dec) {

    var decString = ""+dec;
    var l = decString.length;
    var decimals = decString.charAt(l-2) + decString.charAt(l-1) // last two digits

    if (dec < 100) {
      return "00:00:"+dec
    } // else

    if (dec < 6000) {
      var seconds = (dec < 1000 ? "0" + decString.charAt(0) : decString.charAt(0)+decString.charAt(1))
      return "00:" + seconds + "." + decimals
    } // else

    var minutes = Math.floor(dec / 6000);
    var seconds = ((dec % 6000) / 100).toFixed(0);

    return minutes + ":" + (seconds < 10 ? '0' : '') + seconds + "." + decimals;
  }

  this.getIntFromTimeString = function(time) {

    var r1 = time.replace(/:/g, ''); // removes ':'
    var r2 =  r1.replace(/\./g, ''); // removes '.'

    return parseInt(r2);
  }

  this.downloadjson = function() {
    if (this.getCurrentSolve().times.length==0) {
      Error.print('No solves yet')
      return;
    }
    var data = JSON.stringify(this.solves);
    var url = 'data:text/json;charset=utf8,' + encodeURIComponent(data);
    window.open(url, '_blank');
    window.focus();
   }

  this.uploadjson = function(evt) {
    var input = document.getElementById('uploadjsoninput');
    if (!input.files[0]) {
      alert("Please select a file before clicking 'Load'");
    }
    else {
      file = input.files[0];
      fr = new FileReader();
      fr.onload = this.saveJsonSolves;
      fr.readAsText(file);
    }
  }

  this.saveJsonSolves = function() {
    var oldSolves = Object.assign({}, Data.solves); // save current solves for recovery
    var newSolves = null
    try {
        newSolves = JSON.parse(fr.result)
    } catch (e) {
        alert('That was not a JSON file, was it?')
        return;
    }
    if (newSolves[0].name == undefined || newSolves[0].times == undefined ) {
      alert('It was a JSON but there were not solves in it')
      return;
    }
    try {
      for (var i=0; i<newSolves.length; i++) {
        var s = newSolves[i]
        var index = Data.getIndex(s.name)
        Data.newSolve(s.name)
        console.log('solve '+s.name);
        for (var j=0; j<s.times.length; j++) {
          console.log('\ttime '+s.times[j].time);
          Data.solves[index].times.push(new SolveTime(s.times[j].time, s.times[j].scramble))
        }
      }
      Data.refresh()
    } catch(e) {
      Data.solves = oldSolves // recover
      alert('There was a problem uploading solves')
      console.log(e);
    }
  }

  this.newSolve = function(name) {
    if (this.getIndex(name) == -1) { // it does not exists yet
      this.currentSolve = name
      this.solves.push(new Solve(name))
      this.refresh()
    }
  }
}
<commit_msg>fixed index error uploading json<commit_after>
function SolveTime(time, scramble) { // solve time object
  this.time = time
  this.scramble = scramble
}

function Solve(name) { // session object (multiple times)
  this.name = name
  this.times = []
}

function DataManager() {
  this.solves = [] // array of Solve objects
  this.numberOfSolves = 0 // solves loaded into the app !! not the actual number (solves.length)
  this.currentSolve = 'Default'
  this.deleted = [] // list of deleted solves to undo
  this.lastScramble = ''
  this.file = null
  this.fr = null

  this.init = function() {
    if(typeof(Storage) == "undefined") {
      // Sorry! No Web Storage support..
      Error.print('Sorry! No Web Storage support..');
    }
    if (typeof JSON === "undefined") {
      Error.print('JSON not supported')
    }

    if (!window.File || !window.FileReader || !window.FileList || !window.Blob) {
      Error.print('Sorry, no html5 support in this browser')
    }

    document.getElementById('uploadjsoninput').addEventListener("change", evt = function() {
     Data.uploadjson(evt)
    });

    // load number of solves stored
    this.numberOfSolves = localStorage.getItem('numberOfSolves')
    if (this.numberOfSolves == null) this.numberOfSolves = 0
    // load solves from storage
    this.load()
    this.refresh()
    MainLayout.scrollDown()
  }

  this.resetSolves = function() {
    this.currentSolve = 'Default'
    this.solves = [new Solve('Default', [])]
    this.numberOfSolves = 1
  }

  this.load = function() {
    if (this.numberOfSolves == 0) {
      this.resetSolves()
    }
    else {
      // checks for old solves and converts them
      if (localStorage.getItem('solves') == null) {
        this.resetSolves()
        return
      }
      if (typeof(JSON.parse(localStorage.getItem('solves'))[0].times[0]) == "string") { // old solves
        var slvs = JSON.parse(localStorage.getItem('solves')) // all solves
        var nslvs = Object.keys(slvs).length
        for (var i=0; i<nslvs; i++) { // iterate solves
          var n = new Solve(slvs[i].name)
          for (var j=0; j<slvs[i].times.length; j++) {
            n.times.push(new SolveTime(slvs[i].times[j],'no scramble for this solve'))
          }
          this.solves.push(n)
        }
      } else { // new solves with scrambles
        this.solves = JSON.parse(localStorage.getItem('solves')) // JSON object in localstorage
      }
      this.currentSolve = localStorage['currentSolve']
      if (this.solves == null) {
        this.resetSolves()
      }
    }
  }

  this.save = function() {
    if (this.solves == null) { // no solves
      localStorage['numberOfSolves'] = 1
      localStorage['solves'] = JSON.stringify([new Solve('Default')])
      localStorage['currentSolve'] = 'Default'
    } else {
      localStorage['numberOfSolves'] = this.solves.length
      localStorage['solves'] = JSON.stringify(this.solves)
      localStorage['currentSolve'] = this.currentSolve
    }
  }

  this.updateSolveName = function() {
    var content = ''
    for (var i=0; i<this.solves.length; i++) {
      if (this.currentSolve == this.solves[i].name) content += '<option selected>'+this.solves[i].name+'</option>'
      else content += '<option>'+this.solves[i].name+'</option>'
    }
    document.getElementById('solveNames').innerHTML = content
    $('#solveNames').select2({
  			minimumResultsForSearch: Infinity,
				theme: "classic"
		});
  }

  this.changeSolve = function(index) {
    this.currentSolve = this.solves[index].name
    this.refresh()
    MainLayout.hideUndoDelete()
    $('#solveNames').select2("close");
  }

  this.delSolve = function() {
    if (confirm ("Are you sure to delete this Solve class?")) {
      var index = $("select[id='solveNames'] option:selected").index()
      this.solves.splice(parseInt(index), 1)
      if (this.solves.length == 0) {
        this.solves[0] = new Solve('Default')
        this.currentSolve = 'Default'
      } else {
        this.currentSolve = this.solves[0].name
      }
      this.refresh()
      MainLayout.hideUndoDelete()
    }
  }

  this.getIndex = function(name) {
    var exists = false
    for (var i=0; i<this.solves.length; i++) {
      if (this.solves[i].name == name) {
        exists = true; break
      }
    }
    if (exists) return i;
    else return -1;
  }

  this.getCurrentSolve = function() {
    return this.solves[this.getIndex(this.currentSolve)]
  }

  this.add = function() {
    var currentTime = document.getElementById("chronotime").innerHTML
    MainLayout.updateScramble()
    this.getCurrentSolve().times.push(new SolveTime(currentTime, this.lastScramble))
    MainLayout.scrollDown()
  }

  this.refresh = function() {
    if (this.solves.length == 0) return;
    var best = this.getBestTime();
    var table = '';
    var times = this.getCurrentSolve().times
    for (var i=0; i<times.length; i++) {
      if (i == best) {
          table += "
"+(parseInt(i)+1)+"	"+times[i].time+"
";
      } else {
          table += "
"+(parseInt(i)+1)+"	"+times[i].time+"
";
      }
    }
    document.getElementById('times-table').innerHTML = table
    this.save()
    this.updateSolveName()

    if (times.length == 0) {
      document.getElementById('best-solve').innerHTML = "Best: -"
      document.getElementById('average-all').innerHTML = "Average All: -"
      document.getElementById('average-5').innerHTML = "Average 5: -"
    }
    else {
      // display scores
      document.getElementById('best-solve').innerHTML = "Best: "+ times[best].time
      document.getElementById('average-all').innerHTML = "Average All: " + this.getAverageAll()
      if (times.length>4) document.getElementById('average-5').innerHTML = "Average 5: " + this.getAverage5();
      else document.getElementById('average-5').innerHTML = "Average 5: -"
    }
  }

  this.deleteTime = function(index) {
    this.deleted.push(this.getCurrentSolve().times[index])
    this.getCurrentSolve().times.splice(parseInt(index), 1)
    this.refresh();
    MainLayout.showUndoDelete();
  }

  this.undoLastDelete = function() {
    this.getCurrentSolve().times.push(this.deleted.pop())
    this.refresh()
    MainLayout.scrollDown()
    if (this.deleted.length < 1) {
        MainLayout.hideUndoDelete();
    }
  }

  this.saveBackground = function() {
    localStorage['bgIndex'] = (""+MainLayout.backgroundSelected)
  }

  this.restoreBackground = function() {
    return ( (localStorage.getItem('bgIndex') == 'undefined' || isNaN(localStorage.getItem('bgIndex'))) ? 0 : parseInt(localStorage.getItem('bgIndex')) )
  }

  // index of the best time in the array
  this.getBestTime = function() {
    var times = this.getCurrentSolve().times
    var best = 0; // index 0
    var i = 1;
    for (i=1; i<times.length; i++) {
      var old = this.getIntFromTimeString(times[best].time)
      var cur = this.getIntFromTimeString(times[i].time)

      if (cur < old) best = i;
    }

    return best;
  }

  this.getAverageAll = function() {
    var times = this.getCurrentSolve().times
    var i=0, average=0, min=0, sec=0, dec=0;

    for (i=0; i<times.length; i++) {
      min = parseInt(times[i].time.charAt(0)+times[i].time.charAt(1))
      sec = parseInt(times[i].time.charAt(3)+times[i].time.charAt(4))
      dec = parseInt(times[i].time.charAt(6)+times[i].time.charAt(7))
      // average in decimals
      average += ( (min*60*100) + (sec*100) + dec)
    }
    average /= times.length
    average = average.toFixed(0);

    return this.getAverageStringFromDec(average)
  }

  this.getAverage5 = function() {
    var times = this.getCurrentSolve().times
    var i=0, average=0, min=0, sec=0, dec=0;
    times = times.slice(times.length-5, times.length)
    times.sort(function(a,b){ return a.toString().localeCompare(b) }) // custom sort
    for (i=1; i<times.length-1; i++) {
      min = parseInt(times[i].time.charAt(0)+times[i].time.charAt(1))
      sec = parseInt(times[i].time.charAt(3)+times[i].time.charAt(4))
      dec = parseInt(times[i].time.charAt(6)+times[i].time.charAt(7))
      // average in decimals
      average += ( (min*60*100) + (sec*100) + dec)
    }
    average /= 3
    average = average.toFixed(0);

    return this.getAverageStringFromDec(average)
  }

  this.getAverageStringFromDec = function(dec) {

    var decString = ""+dec;
    var l = decString.length;
    var decimals = decString.charAt(l-2) + decString.charAt(l-1) // last two digits

    if (dec < 100) {
      return "00:00:"+dec
    } // else

    if (dec < 6000) {
      var seconds = (dec < 1000 ? "0" + decString.charAt(0) : decString.charAt(0)+decString.charAt(1))
      return "00:" + seconds + "." + decimals
    } // else

    var minutes = Math.floor(dec / 6000);
    var seconds = ((dec % 6000) / 100).toFixed(0);

    return minutes + ":" + (seconds < 10 ? '0' : '') + seconds + "." + decimals;
  }

  this.getIntFromTimeString = function(time) {

    var r1 = time.replace(/:/g, ''); // removes ':'
    var r2 =  r1.replace(/\./g, ''); // removes '.'

    return parseInt(r2);
  }

  this.downloadjson = function() {
    if (this.getCurrentSolve().times.length==0) {
      Error.print('No solves yet')
      return;
    }
    var data = JSON.stringify(this.solves);
    var url = 'data:text/json;charset=utf8,' + encodeURIComponent(data);
    window.open(url, '_blank');
    window.focus();
   }

  this.uploadjson = function(evt) {
    var input = document.getElementById('uploadjsoninput');
    if (!input.files[0]) {
      alert("Please select a file before clicking 'Load'");
    }
    else {
      file = input.files[0];
      fr = new FileReader();
      fr.onload = this.saveJsonSolves;
      fr.readAsText(file);
    }
  }

  this.saveJsonSolves = function() {
    var oldSolves = Object.assign({}, Data.solves); // save current solves for recovery
    var newSolves = null
    try {
        newSolves = JSON.parse(fr.result)
    } catch (e) {
        alert('That was not a JSON file, was it?')
        return;
    }
    if (newSolves[0].name == undefined || newSolves[0].times == undefined ) {
      alert('It was a JSON but there were not solves in it')
      return;
    }
    try {
      for (var i=0; i<newSolves.length; i++) {
        var s = newSolves[i]
        Data.newSolve(s.name) // could exist, in that case times are pushed to existing solve
        var index = Data.getIndex(s.name)
        for (var j=0; j<s.times.length; j++) {
          Data.solves[index].times.push(new SolveTime(s.times[j].time, s.times[j].scramble))
        }
      }
      Data.refresh()
    } catch(e) {
      Data.solves = oldSolves // recover
      alert('There was a problem uploading solves')
      console.log(e);
    }
  }

  this.newSolve = function(name) {
    if (this.getIndex(name) == -1) { // it does not exists yet
      this.currentSolve = name
      this.solves.push(new Solve(name))
      this.refresh()
    }
  }
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Link, withRouter, graphql, gql, sortBy } from 'olymp';
import { createComponent, Grid } from 'olymp-fela';
import { H2 } from '../components';

const Item = createComponent(
  ({ theme, farbe, hovered }) => ({
    position: 'relative',
    paddingX: theme.space1,
    fontSize: '94%',
    onBefore: {
      color: `${farbe || theme.color} !important`,
    },
    '> a': {
      clearfix: true,
      color: hovered ? farbe || theme.color : theme.dark2,
      onHover: {
        color: farbe || theme.color,
      },
      '> span': {
        float: 'left',
        whiteSpace: 'nowrap',
        overflowX: 'hidden',
        textOverflow: 'ellipsis',
        maxWidth: '50%',
      },
      '> span:last-child': {
        opacity: 0.85,
        fontSize: '90%',
        float: 'right',
        marginRight: theme.space4,
        whiteSpace: 'nowrap',
        overflowX: 'hidden',
        textOverflow: 'ellipsis',
        maxWidth: '38%',
      },
    },
  }),
  ({
    className,
    slug,
    name,
    kurz,
    einrichtung,
    telefon,
    onMouseEnter,
    onMouseLeave,
  }) =>
    (

      <Link
        to={slug || '/'}
        onMouseEnter={onMouseEnter}
        onMouseLeave={onMouseLeave}
      >

          {kurz || name}

          {einrichtung || telefon}

      </Link>

),
  p => Object.keys(p)
);

@withRouter
@graphql(
  gql`
    query einrichtungList {
      items: einrichtungList(query: { state: { eq: PUBLISHED } }) {
        id
        slug
        image {
          url
        }
        telefon
        farbe
        name
        title
        fachrichtungen
        personen {
          id
          name
        }
      }
    }
  `,
  {
    options: () => ({}),
  }
)
class VerzeichnisBlock extends Component {
  state = { hover: undefined };

  onMouseLeave = () => {
    this.setState({ hover: null });
  };

  onMouseOver = item => () => {
    this.setState({ hover: item.einrichtungId || item.id });
  };

  renderSection = (title, items = []) =>
    (<Grid.Item medium={1}>

        {title}

        {items.map(item =>
          (<Item
            {...item}
            onMouseEnter={this.onMouseOver(item)}
            onMouseLeave={this.onMouseLeave}
            hovered={this.state.hover === (item.einrichtungId || item.id)}
          />)
        )}

    </Grid.Item>);

  render() {
    const { attributes, children, data } = this.props;
    const personen = [];
    const spezial = [];

    if (!data.items || !data.items.length) {
      return
;
    }

    data.items.forEach((item) => {
      if (item.personen) {
        item.personen.forEach(person =>
          personen.push({
            ...person,
            einrichtungId: item.id,
            farbe: item.farbe,
            einrichtung: item.kurz || item.name,
            slug: item.slug,
          })
        );
      }
      if (item.fachrichtungen) {
        item.fachrichtungen.forEach(leistung =>
          spezial.push({
            id: leistung,
            name: leistung,
            einrichtungId: item.id,
            farbe: item.farbe,
            einrichtung: item.kurz || item.name,
            slug: item.slug,
          })
        );
      }
    });

    return (
      <Grid size={3} {...attributes}>
        {this.renderSection(
          'Einrichtungen',
          sortBy(data.items, x => x.name || x.title)
        )}
        {this.renderSection('Spezialitäten', sortBy(spezial, 'name'))}
        {this.renderSection('Ärzte & Dienstleister', sortBy(personen, 'name'))}
        {children}
      </Grid>
    );
  }
}

export default {
  key: 'GZK.Collections.VerzeichnisBlock',
  label: 'Verzeichnis',
  category: 'Collections',
  editable: false,
  component: VerzeichnisBlock,
};
<commit_msg>fix id<commit_after>import React, { Component } from 'react';
import { Link, withRouter, graphql, gql, sortBy } from 'olymp';
import { createComponent, Grid } from 'olymp-fela';
import { H2 } from '../components';

const Item = createComponent(
  ({ theme, farbe, hovered }) => ({
    position: 'relative',
    paddingX: theme.space1,
    fontSize: '94%',
    onBefore: {
      color: `${farbe || theme.color} !important`,
    },
    '> a': {
      clearfix: true,
      color: hovered ? farbe || theme.color : theme.dark2,
      onHover: {
        color: farbe || theme.color,
      },
      '> span': {
        float: 'left',
        whiteSpace: 'nowrap',
        overflowX: 'hidden',
        textOverflow: 'ellipsis',
        maxWidth: '50%',
      },
      '> span:last-child': {
        opacity: 0.85,
        fontSize: '90%',
        float: 'right',
        marginRight: theme.space4,
        whiteSpace: 'nowrap',
        overflowX: 'hidden',
        textOverflow: 'ellipsis',
        maxWidth: '38%',
      },
    },
  }),
  ({
    className,
    slug,
    name,
    kurz,
    einrichtung,
    telefon,
    onMouseEnter,
    onMouseLeave,
  }) =>
    (

      <Link
        to={slug || '/'}
        onMouseEnter={onMouseEnter}
        onMouseLeave={onMouseLeave}
      >

          {kurz || name}

          {einrichtung || telefon}

      </Link>

),
  p => Object.keys(p)
);

@withRouter
@graphql(
  gql`
    query einrichtungList {
      items: einrichtungList(query: { state: { eq: PUBLISHED } }) {
        id
        slug
        image {
          id
          url
        }
        telefon
        farbe
        name
        title
        fachrichtungen
        personen {
          id
          name
        }
      }
    }
  `,
  {
    options: () => ({}),
  }
)
class VerzeichnisBlock extends Component {
  state = { hover: undefined };

  onMouseLeave = () => {
    this.setState({ hover: null });
  };

  onMouseOver = item => () => {
    this.setState({ hover: item.einrichtungId || item.id });
  };

  renderSection = (title, items = []) =>
    (<Grid.Item medium={1}>

        {title}

        {items.map(item =>
          (<Item
            {...item}
            onMouseEnter={this.onMouseOver(item)}
            onMouseLeave={this.onMouseLeave}
            hovered={this.state.hover === (item.einrichtungId || item.id)}
          />)
        )}

    </Grid.Item>);

  render() {
    const { attributes, children, data } = this.props;
    const personen = [];
    const spezial = [];

    if (!data.items || !data.items.length) {
      return
;
    }

    data.items.forEach((item) => {
      if (item.personen) {
        item.personen.forEach(person =>
          personen.push({
            ...person,
            einrichtungId: item.id,
            farbe: item.farbe,
            einrichtung: item.kurz || item.name,
            slug: item.slug,
          })
        );
      }
      if (item.fachrichtungen) {
        item.fachrichtungen.forEach(leistung =>
          spezial.push({
            id: leistung,
            name: leistung,
            einrichtungId: item.id,
            farbe: item.farbe,
            einrichtung: item.kurz || item.name,
            slug: item.slug,
          })
        );
      }
    });

    return (
      <Grid size={3} {...attributes}>
        {this.renderSection(
          'Einrichtungen',
          sortBy(data.items, x => x.name || x.title)
        )}
        {this.renderSection('Spezialitäten', sortBy(spezial, 'name'))}
        {this.renderSection('Ärzte & Dienstleister', sortBy(personen, 'name'))}
        {children}
      </Grid>
    );
  }
}

export default {
  key: 'GZK.Collections.VerzeichnisBlock',
  label: 'Verzeichnis',
  category: 'Collections',
  editable: false,
  component: VerzeichnisBlock,
};
<|endoftext|>


<commit_before>(function( Factlink ) {
Factlink.conf = {
    api: {
        loc: "http://development.factlink.com"
        // loc: "http://localhost:3000"
    },
    lib: {
        loc: "http://static.factlink.com/lib"
    }
};

Factlink.conf.css = {
    loc: Factlink.conf.lib.loc + "/src/css/basic.css?" + (new Date()).getTime()
};
})( window.Factlink );<commit_msg>Demo server<commit_after>(function( Factlink ) {
Factlink.conf = {
    api: {
        loc: "http://demo.factlink.org"
        // loc: "http://localhost:3000"
    },
    lib: {
        loc: "http://static.demo.factlink.org/lib"
    }
};

Factlink.conf.css = {
    loc: Factlink.conf.lib.loc + "/src/css/basic.css?" + (new Date()).getTime()
};
})( window.Factlink );<|endoftext|>


<commit_before>describe('Knight', function() {
  var Knight = require('../../lib/models/knight.js');
  var Enemy = require('../../lib/models/knight.js');

  beforeEach(function() {
    knight = Knight();
    enemy = Enemy();
  });

  it("should be able to attack and cause damage to enemies", function() {
    knight.attack(enemy);

    expect(enemy.health()).toEqual(950);
  });

  it("should be able to take damage from enemies when attacked", function() {
    enemy.attack(knight);

    expect(knight.health()).toEqual(950);
  })

  describe("when defending", function() {
    beforeEach(function() {
      knight.defend();
    });

    it("should take no damage from attacks", function() {
      enemy.attack(knight);

      expect(knight.health()).toEqual(1000);
    });

    it("should take damage on subsequent attacks, after successfully blocking an attack", function() {
      enemy.attack(knight);
      enemy.attack(knight);

      expect(knight.health()).toEqual(950);
    });
  });

  describe("when running", function() {
    beforeEach(function() {
      knight.run();
    });

    it("should take 50% more damage", function() {
      enemy.attack(knight);

      expect(knight.health()).toEqual(925);
    });

    it("should stop running and take normal damage when they attack", function() {
      knight.attack(enemy);
      enemy.attack(knight);

      expect(knight.health()).toEqual(950);
    });

    it("should stop running and take no damage when they defend", function() {
      knight.defend();
      enemy.attack(knight);

      expect(knight.health()).toEqual(1000);
    });
  });
});
<commit_msg>Makes small correction to Knight spec<commit_after>describe('Knight', function() {
  var Knight = require('../../lib/models/knight.js');
  var Enemy = require('../../lib/models/knight.js');
  var knight;
  var enemy;

  beforeEach(function() {
    knight = Knight();
    enemy = Enemy();
  });

  it("should be able to attack and cause damage to enemies", function() {
    knight.attack(enemy);

    expect(enemy.health()).toEqual(950);
  });

  it("should be able to take damage from enemies when attacked", function() {
    enemy.attack(knight);

    expect(knight.health()).toEqual(950);
  })

  describe("when defending", function() {
    beforeEach(function() {
      knight.defend();
    });

    it("should take no damage from attacks", function() {
      enemy.attack(knight);

      expect(knight.health()).toEqual(1000);
    });

    it("should take damage on subsequent attacks, after successfully blocking an attack", function() {
      enemy.attack(knight);
      enemy.attack(knight);

      expect(knight.health()).toEqual(950);
    });
  });

  describe("when running", function() {
    beforeEach(function() {
      knight.run();
    });

    it("should take 50% more damage", function() {
      enemy.attack(knight);

      expect(knight.health()).toEqual(925);
    });

    it("should stop running and take normal damage when they attack", function() {
      knight.attack(enemy);
      enemy.attack(knight);

      expect(knight.health()).toEqual(950);
    });

    it("should stop running and take no damage when they defend", function() {
      knight.defend();
      enemy.attack(knight);

      expect(knight.health()).toEqual(1000);
    });
  });
});
<|endoftext|>


<commit_before>$(document).ready(function() {

	var tpl = {

	    firstPage : '
'+
	                    '
'+
	                        '
'+
	                           ''+
	                        '
'+
	                        '
100
'+
	                        '
王东杰
'+
	                        '
北京子木投资顾问有限公司
'+
	                        '
前端开发
'+
	                    '
'+
	                '
',
		otherPage : '
'+
		                '
'+
		                    '
'+
		                        '
'+
		                            ''+
		                        '
'+
		                        '
100
'+
		                        '
王东杰
'+
		                        '
北京子木投资顾问有限公司
'+
		                        '
前端开发
'+
		                    '
'+
		                '
'+
		            '
'
	};

	// 投资者事件
	var tou = {

		init : function() {
			this.$swiperWrapper = $('.swiper-wrapper');
			this.$rule = $('.look-rule');
			this.$back = $('.back');
			this.bind();
		},

		getList : function() {
			var _this = this;
			// $.ajax({
		 //        url : '/home/banner',
		 //        type : 'get',
		 //        dataType : 'json',
		 //        success : function(msg) {
		 //            if (msg.code != '0000') {
		 //                return;
		 //            }
		 //            var first = template.compile(tpl.firstPage),
   //              	html = render({data : msg.data[0]});

   //              	var other = template.compile(tpl.otherPage),
   //              	html = render({data : msg.data[0]});
		 //            $('.head-time').append(html);

		 //            _this.bind();
		 //        }
		 //    });

			var data = {
						    "code": "0000",
						    "msg": "处理成功",
						    "data": [
						        {
						            "id": 16,
						            "mainTitle": "",
						            "subTitle": "",
						            "simgUrl": "http://spimg.qunarzz.com/gongyu/20150806/qunarbanner_150X60.jpg",
						            "imgUrl": "",
						            "bimgUrl": "http://spimg.qunarzz.com/gongyu/20150806/qunarbanner_2000x250.jpg",
						            "clickUrl": "http://tuan.qunar.com/static/topics/hotel/qixi/index.html",
						            "enable": true,
						            "sort": 1,
						            "updateTime": 1443496880000
						        },
						        {
						            "id": 14,
						            "mainTitle": "",
						            "subTitle": "",
						            "simgUrl": "http://spimg.qunarzz.com/gongyu/20150721/clzs2.jpg",
						            "imgUrl": "",
						            "bimgUrl": "http://spimg.qunarzz.com/gongyu/20150721/clzsg.jpg",
						            "clickUrl": "http://tuan.qunar.com/static/topics/hotel/chailvzhusu/index.html?from=gysy",
						            "enable": true,
						            "sort": 2,
						            "updateTime": 1442471883000
						        }
						    ]
						} ;
			var first = template.compile(tpl.otherPage),
                html = render({data : data[0]});
            $('.step-1').append(html);

		},

		bind : function() {
			var _this = this;
		    // 初始化swiper
		    var swiper = new Swiper('.swiper-container', {
		      	direction: 'vertical',
		      	loop: false,
		      	onSlideChangeStart: function(swiper){
			    	_this.getList();
			    }
		    });

		    // 点击进入详情
		    this.$swiperWrapper.on('click', 'li', function() {
		    	var $self = $(this);
		    	var uid = $self.data('uid');
		    	window.location.href="detail.html?uid="+uid;
		    });

		    this.$rule.on('click', function() {
		    	$('.rule').show();
		    	$('.step-1').siblings().hide();
		    	$('.list-1').hide();
		    	$('.head-time').hide();
		    });

		    this.$back.on('click',function() {
		    	$('.rule').hide();
		    	$('.step-1').siblings().show();
		    	$('.list-1').show();
		    	$('.head-time').show();
		    })

		}
	};
	tou.init();
});<commit_msg>chufa<commit_after>$(document).ready(function() {

	var tpl = {

	    firstPage : '
'+
	                    '
'+
	                        '
'+
	                           ''+
	                        '
'+
	                        '
100
'+
	                        '

'+
	                        '
北京子木投资顾问有限公司
'+
	                        '
前端开发
'+
	                    '
'+
	                '
',
		otherPage : '
'+
		                '
'+
		                    '
'+
		                        '
'+
		                            ''+
		                        '
'+
		                        '
100
'+
		                        '
{{data.name}}
'+
		                        '
{{data.company}}
'+
		                        '
{{data.position}}
'+
		                    '
'+
		                '
'+
		            '
'
	};

	// 投资者事件
	var tou = {

		init : function() {
			this.$swiperWrapper = $('.swiper-wrapper');
			this.$rule = $('.look-rule');
			this.$back = $('.back');
			this.bind();
		},

		getList : function() {
			var _this = this;
			// $.ajax({
		 //        url : '/home/banner',
		 //        type : 'get',
		 //        dataType : 'json',
		 //        success : function(msg) {
		 //            if (msg.code != '0000') {
		 //                return;
		 //            }
		 //            var first = template.compile(tpl.firstPage),
   //              	html = render({data : msg.data[0]});

   //              	var other = template.compile(tpl.otherPage),
   //              	html = render({data : msg.data[0]});
		 //            $('.head-time').append(html);

		 //            _this.bind();
		 //        }
		 //    });

			var data = {
						    "code": "0000",
						    "msg": "处理成功",
						    "data": [
						        {
						            "id": 16,
						            "mainTitle": "",
						            "subTitle": "",
						            "simgUrl": "http://spimg.qunarzz.com/gongyu/20150806/qunarbanner_150X60.jpg",
						            "name" : "王东杰",
						            "company":"北京子木投资顾问有限公司",
						            "position":"前端开发"
						        },
						        {
						            "id": 16,
						            "mainTitle": "",
						            "subTitle": "",
						            "simgUrl": "http://spimg.qunarzz.com/gongyu/20150806/qunarbanner_150X60.jpg",
						            "name" : "王东杰",
						            "company":"北京子木投资顾问有限公司",
						            "position":"前端开发"
						        }
						    ]
						} ;
			var first = template.compile(tpl.otherPage),
                html = render({data : data.data[0]});
            $('.step-1').append(html);
            _this.bind();
		},

		bind : function() {
			var _this = this;
		    // 初始化swiper
		    var swiper = new Swiper('.swiper-container', {
		      	direction: 'vertical',
		      	loop: false,
		      	onSlideChangeStart: function(swiper){
			    	_this.getList();
			    }
		    });

		    // 点击进入详情
		    this.$swiperWrapper.on('click', 'li', function() {
		    	var $self = $(this);
		    	var uid = $self.data('uid');
		    	window.location.href="detail.html?uid="+uid;
		    });

		    this.$rule.on('click', function() {
		    	$('.rule').show();
		    	$('.step-1').siblings().hide();
		    	$('.list-1').hide();
		    	$('.head-time').hide();
		    });

		    this.$back.on('click',function() {
		    	$('.rule').hide();
		    	$('.step-1').siblings().show();
		    	$('.list-1').show();
		    	$('.head-time').show();
		    })

		}
	};
	tou.init();
});<|endoftext|>


<commit_before>import Vue           from 'vue';
import types         from '@/utils/types';
import clientStorage from '@/utils/ClientStorage';

/**
 * Commonly used Vue instance helper methods.
 */
export default {
    install(Vue, options) {
        /**
         * Generic api client error response handler.
         *
         * @param {Error} err
         */
        Vue.prototype.$baseApiErrorHandler = function(err) {
            if (!err) {
                return;
            }

            const responseStatus = (err.response && err.response.status) ? err.response.status : 200;
            const errMessage     = (err.response && err.response.data && err.response.data.message) ? err.response.data.message : err.message;

            if (responseStatus == 401 || responseStatus == 403) {
                this.$logout();
            }

            if (errMessage) {
                this.$notify(errMessage);
            }
        };

        /**
         * Logouts the current user by taking care of cleaning stored user data.
         */
        Vue.prototype.$logout = function() {
            clientStorage.removeItem('token');

            if (this.$route.name !== 'auth') {
                this.$router.replace({ name: 'auth' });
            }
        };

        /**
         * Registers a new global notification/alert.
         *
         * @param {String} message   Notification message
         * @param {Number} [timeout] Auto close timeout in ms (defaults to 4000 ms)
         */
        Vue.prototype.$notify = function(message, timeout = 4000) {
            parent.postMessage({
                pluginMessage: {
                    type: types.MESSAGE_NOTIFY,
                    data: {
                        message: message,
                        timeout: timeout,
                    },
                },
            }, '*');
        };

        /**
         * Closes the active `figma.ui` modal dialog.
         */
        Vue.prototype.$closePluginDialog = function() {
            parent.postMessage({
                pluginMessage: { type: types.MESSAGE_CLOSE },
            }, '*');
        };

        /**
         * Resizes the active `figma.ui` modal dialog.
         *
         * @param {Number} [width]  New width of the dialog (if not set the default one will be used).
         * @param {Number} [height] New height of the dialog (if not set the default one will be used).
         */
        Vue.prototype.$resizePluginDialog = function(width, height) {
            parent.postMessage({
                pluginMessage: {
                    type: types.MESSAGE_RESIZE_UI,
                    data: {
                        width:  width,
                        height: height,
                    },
                },
            }, '*');
        };

        /**
         * Returns design frame nodes.
         *
         * @param  {Boolean} [onlySelected] Whether to return only the selected frames (`false` by default).
         * @return {Promise}
         */
        Vue.prototype.$getFrames = function(onlySelected = false) {
            const state = ('get_frames_' + Date.now());

            return new Promise(function(resolve, reject) {
                let forceTimeoutId = null;

                let handler = function (event) {
                    let message = event.data.pluginMessage || {};

                    if (
                        message.state == state && // is the correct response
                        message.type === types.MESSAGE_GET_FRAMES_RESPONSE
                    ) {
                        clearTimeout(forceTimeoutId);

                        window.removeEventListener('message', handler);

                        resolve(message.data || []);
                    }
                };

                window.addEventListener('message', handler);

                // force resolve after 10 seconds
                forceTimeoutId = setTimeout(() => {
                    window.removeEventListener('message', handler);

                    Promise.resolve([]);
                }, 10000);

                // request frames
                parent.postMessage({
                    pluginMessage: {
                        state: state,
                        type: types.MESSAGE_GET_FRAMES,
                        data: {
                            onlySelected: onlySelected,
                        },
                    },
                }, '*');
            });
        };

        /**
         * Exports a single frame image data.
         *
         * @param  {String} frameId    ID of the frame to export.
         * @param  {Object} [settings] Additional settings to be passed to the export command.
         * @return {Promise}
         */
        Vue.prototype.$exportFrame = function(frameId, settings) {
            const state = ('export_frame_' + frameId + Date.now());

            return new Promise(function(resolve, reject) {
                let forceTimeoutId = null;

                let handler = function (event) {
                    let message = event.data.pluginMessage || {};

                    if (
                        message.state == state && // is the correct response
                        message.type === types.MESSAGE_EXPORT_FRAME_RESPONSE
                    ) {
                        clearTimeout(forceTimeoutId);

                        window.removeEventListener('message', handler);

                        resolve(message.data || []);
                    }
                };

                window.addEventListener('message', handler);

                // force resolve after 10 seconds
                forceTimeoutId = setTimeout(() => {
                    window.removeEventListener('message', handler);
                    Promise.resolve([]);
                }, 10000);

                // request frames
                parent.postMessage({
                    pluginMessage: {
                        state: state,
                        type: types.MESSAGE_EXPORT_FRAME,
                        data: {
                            id: frameId,
                            settings: settings,
                        },
                    },
                }, '*');
            });
        };
    }
}
<commit_msg>updated default notifications timeout<commit_after>import Vue from 'vue';
import types from '@/utils/types';
import clientStorage from '@/utils/ClientStorage';

/**
 * Commonly used Vue instance helper methods.
 */
export default {
    install(Vue, options) {
        /**
         * Generic api client error response handler.
         *
         * @param {Error} err
         */
        Vue.prototype.$baseApiErrorHandler = function(err) {
            if (!err) {
                return;
            }

            const responseStatus = (err.response && err.response.status) ? err.response.status : 200;
            const errMessage = (err.response && err.response.data && err.response.data.message) ? err.response.data.message : err.message;

            if (responseStatus == 401 || responseStatus == 403) {
                this.$logout();
            }

            if (errMessage) {
                this.$notify(errMessage);
            }
        };

        /**
         * Logouts the current user by taking care of cleaning stored user data.
         */
        Vue.prototype.$logout = function() {
            clientStorage.removeItem('token');

            if (this.$route.name !== 'auth') {
                this.$router.replace({ name: 'auth' });
            }
        };

        /**
         * Registers a new global notification/alert.
         *
         * @param {String} message   Notification message
         * @param {Number} [timeout] Auto close timeout in ms (defaults to 3500 ms)
         */
        Vue.prototype.$notify = function(message, timeout = 3500) {
            parent.postMessage({
                pluginMessage: {
                    type: types.MESSAGE_NOTIFY,
                    data: {
                        message: message,
                        timeout: timeout,
                    },
                },
            }, '*');
        };

        /**
         * Closes the active `figma.ui` modal dialog.
         */
        Vue.prototype.$closePluginDialog = function() {
            parent.postMessage({
                pluginMessage: { type: types.MESSAGE_CLOSE },
            }, '*');
        };

        /**
         * Resizes the active `figma.ui` modal dialog.
         *
         * @param {Number} [width]  New width of the dialog (if not set the default one will be used).
         * @param {Number} [height] New height of the dialog (if not set the default one will be used).
         */
        Vue.prototype.$resizePluginDialog = function(width, height) {
            parent.postMessage({
                pluginMessage: {
                    type: types.MESSAGE_RESIZE_UI,
                    data: {
                        width: width,
                        height: height,
                    },
                },
            }, '*');
        };

        /**
         * Returns design frame nodes.
         *
         * @param  {Boolean} [onlySelected] Whether to return only the selected frames (`false` by default).
         * @return {Promise}
         */
        Vue.prototype.$getFrames = function(onlySelected = false) {
            const state = ('get_frames_' + Date.now());

            return new Promise(function(resolve, reject) {
                let forceTimeoutId = null;

                let handler = function(event) {
                    let message = event.data.pluginMessage || {};

                    if (
                        message.state == state && // is the correct response
                        message.type === types.MESSAGE_GET_FRAMES_RESPONSE
                    ) {
                        clearTimeout(forceTimeoutId);

                        window.removeEventListener('message', handler);

                        resolve(message.data || []);
                    }
                };

                window.addEventListener('message', handler);

                // force resolve after 10 seconds
                forceTimeoutId = setTimeout(() => {
                    window.removeEventListener('message', handler);

                    Promise.resolve([]);
                }, 10000);

                // request frames
                parent.postMessage({
                    pluginMessage: {
                        state: state,
                        type: types.MESSAGE_GET_FRAMES,
                        data: {
                            onlySelected: onlySelected,
                        },
                    },
                }, '*');
            });
        };

        /**
         * Exports a single frame image data.
         *
         * @param  {String} frameId    ID of the frame to export.
         * @param  {Object} [settings] Additional settings to be passed to the export command.
         * @return {Promise}
         */
        Vue.prototype.$exportFrame = function(frameId, settings) {
            const state = ('export_frame_' + frameId + Date.now());

            return new Promise(function(resolve, reject) {
                let forceTimeoutId = null;

                let handler = function(event) {
                    let message = event.data.pluginMessage || {};

                    if (
                        message.state == state && // is the correct response
                        message.type === types.MESSAGE_EXPORT_FRAME_RESPONSE
                    ) {
                        clearTimeout(forceTimeoutId);

                        window.removeEventListener('message', handler);

                        resolve(message.data || []);
                    }
                };

                window.addEventListener('message', handler);

                // force resolve after 10 seconds
                forceTimeoutId = setTimeout(() => {
                    window.removeEventListener('message', handler);
                    Promise.resolve([]);
                }, 10000);

                // request frames
                parent.postMessage({
                    pluginMessage: {
                        state: state,
                        type: types.MESSAGE_EXPORT_FRAME,
                        data: {
                            id: frameId,
                            settings: settings,
                        },
                    },
                }, '*');
            });
        };
    }
}
<|endoftext|>


<commit_before>$(document).ready(function ready() {

  var $photoThumb = $('.photos__thumb')
  var $modalImg = $('#photoModal img')

  var $navbarLink = $('.navbar__link')
  var $document = $(document)
  var $navbar = $('.navbar')

  function init() {

    var hash = window.location.hash
    hash && $('a.navbar__link[href="' + hash + '"]').tab('show')

    $navbarLink.click(function(e) {
      $(this).tab('show')
      window.location.hash = this.hash;
    })

    // tells the modal which photo to open
    $photoThumb.on('click', function(e) {
      var dataUrl = $(this).attr('src')
      $modalImg.attr('src', dataUrl)
    })

    $document.on('scroll', function() {
      if ($document.scrollTop() > 0) {
        $navbar.addClass('shadow')
      } else {
        $navbar.removeClass('shadow')
      }
    })
  }

  init()
})
<commit_msg>feat(Navbar): close mobile nav on click<commit_after>$(document).ready(function ready() {

  const $photoThumb = $('.photos__thumb')
  const $modalImg = $('#photoModal img')

  const $navbarLink = $('.navbar__link')
  const $navbarCollapse = $('.navbar-collapse')
  const $document = $(document)
  const $navbar = $('.navbar')

  function init() {

    const hash = window.location.hash
    hash && $('a.navbar__link[href="' + hash + '"]').tab('show')

    $navbarLink.click(function(e) {
      $(this).tab('show')
      $navbarCollapse.toggleClass('in')
      window.location.hash = this.hash;
    })

    // tells the modal which photo to open
    $photoThumb.on('click', function(e) {
      const dataUrl = $(this).attr('src')
      $modalImg.attr('src', dataUrl)
    })

    $document.on('scroll', function() {
      if ($document.scrollTop() > 0) {
        $navbar.addClass('shadow')
      } else {
        $navbar.removeClass('shadow')
      }
    })
  }

  init()
})
<|endoftext|>


<commit_before>;(function(){ //IIFE for angular

  angular.module('brewKeeper', ['ngRoute', 'timer', 'ngCookies', 'validation.match'], function($httpProvider, $routeProvider){
      $routeProvider
        .when('/',{
          templateUrl: 'partials/recipe-list.html',
          controller: 'WhoAmIController'
        })
        .when('/users/:username/recipes/new', {
          templateUrl: 'partials/recipe-create.html',
          controller: 'createNewRecipe'
        })
        .when('/users/:username/recipes/:id', {
          templateUrl: 'partials/recipe-detail.html',
          controller: 'recipeDetail'
        })
        .when('/users/:username', {
          templateUrl: 'partials/recipe-list.html',
          controller: 'recipeList'
        })
        .when('/users/:username/recipes/:id/brewit', {
          templateUrl: 'partials/brew-it.html',
          controller: 'brewIt'
        })
        .when('/info', {
          templateUrl: 'partials/more-info.html'
        })
        .when('/login', {
          templateUrl: 'partials/login.html'
        })
        // .otherwise({
        //   redirectTo: '/404.html',
        //   templateUrl: 'partials/404.html'
        // })
    })

    .controller('MainController', function($http, $scope, $route, $routeParams, $location, $cookies){
      var cookie = $cookies.get("Authorization")
      $http.defaults.headers.common = {"Authorization": cookie}
      $scope.$route = $route;
      $scope.$location = $location;
      $scope.$routeParams = $routeParams;

      $http.get('https://brew-keeper-api.herokuapp.com/api/whoami/')
        .then(function(response){
          $scope.username = response.data.username;
        })//This is for populating url with username

    $scope.logout= function(){
      var logoutHeader = {"Authorization":$cookies.get("Authorization")}
      $http.post('https://brew-keeper-api.herokuapp.com/api/logout/', logoutHeader)
        .then(function(){
          $('.login').removeClass('hidden');//when logged out
          $('.logout').addClass('hidden');
        })
        $cookies.remove("Authorization")
        $http.defaults.headers.common = {}
      }
    })//END MainController

    .controller('WhoAmIController', function($location, $http, $scope) {
      $http.get('https://brew-keeper-api.herokuapp.com/api/whoami/')
        .then(function(response){
          var username = response.data.username;
          $scope.username = username
          //pseudo-code Show "logout" in nav
          //pseudo-code Show "Create New Recipe" in nav
          $('.logout').removeClass('hidden')
          //pseudo-code Hide "login/signup" in nav in index.html
          //pseudo-code Hide "form.login" in login.html
          $('.login').addClass('hidden')
          $location.path('/users/' + username)
        })//.success
        .catch(function(){
          //pseudo-code Show "login/signup" in nav in index.html
          //pseudo-code Show "form.login" in login.html
          $('.login').removeClass('hidden')
          //pseudo-code Hide "logout" in nav
          $('.logout').addClass('hidden')
          $location.path('/login')
        })//.error
    })//END WhoAmIController

})(); //end IIFE
<commit_msg>set route for clone partial<commit_after>;(function(){ //IIFE for angular

  angular.module('brewKeeper', ['ngRoute', 'timer', 'ngCookies', 'validation.match'], function($httpProvider, $routeProvider){
      $routeProvider
        .when('/',{
          templateUrl: 'partials/recipe-list.html',
          controller: 'WhoAmIController'
        })
        .when('/users/:username/recipes/new', {
          templateUrl: 'partials/recipe-create.html',
          controller: 'createNewRecipe'
        })
        .when('/users/:username/clone/:id', {
          templateUrl: 'partials/clone.html',
          // controller:  'cloneController'
        })
        .when('/users/:username/recipes/:id', {
          templateUrl: 'partials/recipe-detail.html',
          controller: 'recipeDetail'
        })
        .when('/users/:username', {
          templateUrl: 'partials/recipe-list.html',
          controller: 'recipeList'
        })
        .when('/users/:username/recipes/:id/brewit', {
          templateUrl: 'partials/brew-it.html',
          controller: 'brewIt'
        })
        .when('/info', {
          templateUrl: 'partials/more-info.html'
        })
        .when('/login', {
          templateUrl: 'partials/login.html'
        })
        // .otherwise({
        //   redirectTo: '/404.html',
        //   templateUrl: 'partials/404.html'
        // })
    })

    .controller('MainController', function($http, $scope, $route, $routeParams, $location, $cookies){
      var cookie = $cookies.get("Authorization")
      $http.defaults.headers.common = {"Authorization": cookie}
      $scope.$route = $route;
      $scope.$location = $location;
      $scope.$routeParams = $routeParams;

      $http.get('https://brew-keeper-api.herokuapp.com/api/whoami/')
        .then(function(response){
          $scope.username = response.data.username;
        })//This is for populating url with username

    $scope.logout= function(){
      var logoutHeader = {"Authorization":$cookies.get("Authorization")}
      $http.post('https://brew-keeper-api.herokuapp.com/api/logout/', logoutHeader)
        .then(function(){
          $('.login').removeClass('hidden');//when logged out
          $('.logout').addClass('hidden');
        })
        $cookies.remove("Authorization")
        $http.defaults.headers.common = {}
      }
    })//END MainController

    .controller('WhoAmIController', function($location, $http, $scope) {
      $http.get('https://brew-keeper-api.herokuapp.com/api/whoami/')
        .then(function(response){
          var username = response.data.username;
          $scope.username = username
          //pseudo-code Show "logout" in nav
          //pseudo-code Show "Create New Recipe" in nav
          $('.logout').removeClass('hidden')
          //pseudo-code Hide "login/signup" in nav in index.html
          //pseudo-code Hide "form.login" in login.html
          $('.login').addClass('hidden')
          $location.path('/users/' + username)
        })//.success
        .catch(function(){
          //pseudo-code Show "login/signup" in nav in index.html
          //pseudo-code Show "form.login" in login.html
          $('.login').removeClass('hidden')
          //pseudo-code Hide "logout" in nav
          $('.logout').addClass('hidden')
          $location.path('/login')
        })//.error
    })//END WhoAmIController

})(); //end IIFE
<|endoftext|>


<commit_before>require('angular');
require('./lion/lion.module.js');

angular.element(document).ready(function () {
	var t = angular.module('lion');
	angular.bootstrap(document, ['lion']);
});

module.exports = angular.module('lion');<commit_msg>cleanup<commit_after>require('angular');
require('./lion/lion.module.js');

angular.element(document).ready(function () {
	angular.bootstrap(document, ['lion']);
});<|endoftext|>


<commit_before>/**
 * @fileoverview Creates a YouTube player in a modal.
 */

var classes = require('../utils/classes');
var dom = require('../utils/dom');
var events = require('../utils/events');
var objects = require('../utils/objects');
var useragent = require('../utils/useragent');

var initted = false;
var player = null;
var defaultConfig = {
  useHandlerOnMobile: true,
  history: false,
  historyNamePrefix: 'video:',
  transitionDuration: 300,
  className: 'ak-youtubemodal',
  playerVars: {
    'autohide': 1,
    'autoplay': 1,
    'fs': 1,
    'modestbranding': 1,
    'rel': 0,
    'showinfo': 0,
    'iv_load_policy': 3
  }
};

/**
 * Plays a YouTube video in a modal dialog.
 * @constructor
 */
function YouTubeModal(config) {
  this.config = config;
  this.initDom_();

  var func = function(targetEl) {
    var data = 'data-' + this.config.className + '-video-id';
    var videoId = targetEl.getAttribute(data);
    if (videoId) {
      this.play(videoId);
    }
  }.bind(this);

  // Loads YouTube iframe API.
  events.addDelegatedListener(document, 'click', func);
  var tag = document.createElement('script');
  tag.setAttribute('src', 'https://www.youtube.com/iframe_api');
  document.body.appendChild(tag);
}

/**
 * Creates the DOM for the YouTube modal.
 * @private
 */
YouTubeModal.prototype.initDom_ = function() {
  var createDom = dom.createDom;
  var el = createDom('div', this.config.className);
  var closeEl = createDom('div', this.config.className + '-x');
  el.appendChild(closeEl);
  el.appendChild(createDom('div', this.config.className + '-player'));
  el.appendChild(createDom('div', this.config.className + '-mask'));
  document.body.appendChild(el);
  closeEl.addEventListener('click', function() {
    this.setActive_(false);
  }.bind(this));

  if (this.config.history) {
    window.addEventListener('popstate', this.onHistoryChange_.bind(this));
  }
};

/**
 * Sets the modal's visibility.
 * @param {Boolean} enabled Whether the modal should be visible.
 */
YouTubeModal.prototype.setVisible = function(enabled) {
  // Plays or pauses depending on visibility.
  if (player) {
    // Delay call to give player time to load.
    window.setTimeout(function() {
      if (enabled) {
        player.playVideo();
      } else {
        player.pauseVideo();
      }
    }, 100);
  }

  var _keyToggle = function(e) {
    if (e.keyCode == 27) {
      this.setActive_(false);
      document.body.removeEventListener('keydown', _keyToggle);
    }
  }.bind(this);

  if (enabled) {
    document.body.addEventListener('keydown', _keyToggle);
  } else {
    document.body.removeEventListener('keydown', _keyToggle);
  }

  var lightboxEl = document.querySelector('.' + this.config.className);
  window.setTimeout(function() {
    classes.enable(lightboxEl, this.config.className + '--enabled', enabled);
  }.bind(this), enabled ? 0 : this.config.transitionDuration);
  window.setTimeout(function() {
    classes.enable(lightboxEl, this.config.className + '--visible', enabled);
  }.bind(this), enabled ? this.config.transitionDuration : 0);
};

/**
 * Sets whether the modal is active (and thus visible and playing). Handles history state if applicable.
 * @param {Boolean} active Whether the modal is active.
 * @param {=string} opt_videoId Video ID to use in the history hash.
 * @param {=Boolean} opt_updateState Whether to update the history state.
 * @private
 */
YouTubeModal.prototype.setActive_ = function(active, opt_videoId, opt_updateState) {
  if (!this.config.history) {
    this.setVisible(active);
    return;
  }

  this.setVisible(active);
  if (opt_updateState === false) {
    return;
  }
  var videoId = opt_videoId || this.activeVideoId_;
  if (active) {
    window.history.pushState(
        {'videoId': videoId}, '',
        '#' + this.config.historyNamePrefix + videoId);
  } else {
    window.history.pushState(
        {'videoId': null}, '', window.location.pathname);
  }
};

/**
 * Callback for changes to the history state.
 * @param {Event} e Pop state event.
 * @private
 */
YouTubeModal.prototype.onHistoryChange_ = function(e) {
  if (e.state && e.state['videoId']) {
    this.play(e.state['videoId'], false);
  } else {
    this.setVisible(false);
  }
};

/**
 * Plays a YouTube video.
 * @param {string} videoId Video ID to play.
 * @param {=Boolean} opt_updateState Whether to update the history state.
 */
YouTubeModal.prototype.play = function(videoId, opt_updateState) {
  var useHandler = (
      this.config.useHandlerOnMobile
      && (useragent.isIOS() || useragent.isAndroid()));

  if (useHandler) {
    window.location.href = 'https://m.youtube.com/watch?v=' + videoId;
    return;
  }

  this.setActive_(true, videoId, opt_updateState);
  if (player && videoId == this.activeVideoId_) {
    return;
  } else if (player && videoId != this.activeVideoId_) {
    player.loadVideoById(videoId, 0, 'large');
    this.activeVideoId_ = videoId;
    return;
  }
  var playerEl = document.querySelector('.' + this.config.className + '-player');
  var options = {
    'videoId': videoId,
    'playerVars': objects.clone(this.config.playerVars)
  };
  player = new YT.Player(playerEl, options);
  this.activeVideoId_ = videoId;
}

/**
 * Initializes a YouTube modal dialog singleton.
 * @param {Object=} opt_config Config options.
 */
function init(opt_config) {
  if (initted) {
    return;
  }
  var config = objects.clone(defaultConfig);
  if (opt_config) {
    objects.merge(config, opt_config);
  }

  new YouTubeModal(config);
  initted = true;
}

module.exports = {
  init: init
};
<commit_msg>Bugfix for two equal history state items.<commit_after>/**
 * @fileoverview Creates a YouTube player in a modal.
 */

var classes = require('../utils/classes');
var dom = require('../utils/dom');
var events = require('../utils/events');
var objects = require('../utils/objects');
var useragent = require('../utils/useragent');

var initted = false;
var player = null;
var defaultConfig = {
  useHandlerOnMobile: true,
  history: false,
  historyNamePrefix: 'video:',
  transitionDuration: 300,
  className: 'ak-youtubemodal',
  playerVars: {
    'autohide': 1,
    'autoplay': 1,
    'fs': 1,
    'modestbranding': 1,
    'rel': 0,
    'showinfo': 0,
    'iv_load_policy': 3
  }
};

/**
 * Plays a YouTube video in a modal dialog.
 * @constructor
 */
function YouTubeModal(config) {
  this.config = config;
  this.initDom_();

  var func = function(targetEl) {
    var data = 'data-' + this.config.className + '-video-id';
    var videoId = targetEl.getAttribute(data);
    if (videoId) {
      this.play(videoId);
    }
  }.bind(this);

  // Loads YouTube iframe API.
  events.addDelegatedListener(document, 'click', func);
  var tag = document.createElement('script');
  tag.setAttribute('src', 'https://www.youtube.com/iframe_api');
  document.body.appendChild(tag);
}

/**
 * Creates the DOM for the YouTube modal.
 * @private
 */
YouTubeModal.prototype.initDom_ = function() {
  var createDom = dom.createDom;
  var el = createDom('div', this.config.className);
  var closeEl = createDom('div', this.config.className + '-x');
  el.appendChild(closeEl);
  el.appendChild(createDom('div', this.config.className + '-player'));
  el.appendChild(createDom('div', this.config.className + '-mask'));
  document.body.appendChild(el);
  closeEl.addEventListener('click', function() {
    this.setActive_(false);
  }.bind(this));

  if (this.config.history) {
    window.addEventListener('popstate', this.onHistoryChange_.bind(this));
  }
};

/**
 * Sets the modal's visibility.
 * @param {Boolean} enabled Whether the modal should be visible.
 */
YouTubeModal.prototype.setVisible = function(enabled) {
  // Plays or pauses depending on visibility.
  if (player) {
    // Delay call to give player time to load.
    window.setTimeout(function() {
      if (enabled) {
        player.playVideo();
      } else {
        player.pauseVideo();
      }
    }, 100);
  }

  var _keyToggle = function(e) {
    if (e.keyCode == 27) {
      this.setActive_(false);
      document.body.removeEventListener('keydown', _keyToggle);
    }
  }.bind(this);

  if (enabled) {
    document.body.addEventListener('keydown', _keyToggle);
  } else {
    document.body.removeEventListener('keydown', _keyToggle);
  }

  var lightboxEl = document.querySelector('.' + this.config.className);
  window.setTimeout(function() {
    classes.enable(lightboxEl, this.config.className + '--enabled', enabled);
  }.bind(this), enabled ? 0 : this.config.transitionDuration);
  window.setTimeout(function() {
    classes.enable(lightboxEl, this.config.className + '--visible', enabled);
  }.bind(this), enabled ? this.config.transitionDuration : 0);
};

/**
 * Sets whether the modal is active (and thus visible and playing). Handles history state if applicable.
 * @param {Boolean} active Whether the modal is active.
 * @param {=string} opt_videoId Video ID to use in the history hash.
 * @param {=Boolean} opt_updateState Whether to update the history state.
 * @private
 */
YouTubeModal.prototype.setActive_ = function(active, opt_videoId, opt_updateState) {
  if (!this.config.history) {
    this.setVisible(active);
    return;
  }

  this.setVisible(active);
  if (opt_updateState === false) {
    return;
  }
  var videoId = opt_videoId || this.activeVideoId_;
  if (active) {
    // Avoid pushing two equal items onto the state.
    var stateId = window.history.state && window.history.state['videoId'];
    if (stateId == videoId) {
      return;
    }
    window.history.pushState(
        {'videoId': videoId}, '',
        '#' + this.config.historyNamePrefix + videoId);
  } else {
    window.history.pushState(
        {'videoId': null}, '', window.location.pathname);
  }
};

/**
 * Callback for changes to the history state.
 * @param {Event} e Pop state event.
 * @private
 */
YouTubeModal.prototype.onHistoryChange_ = function(e) {
  if (e.state && e.state['videoId']) {
    this.play(e.state['videoId'], false);
  } else {
    this.setVisible(false);
  }
};

/**
 * Plays a YouTube video.
 * @param {string} videoId Video ID to play.
 * @param {=Boolean} opt_updateState Whether to update the history state.
 */
YouTubeModal.prototype.play = function(videoId, opt_updateState) {
  var useHandler = (
      this.config.useHandlerOnMobile
      && (useragent.isIOS() || useragent.isAndroid()));

  if (useHandler) {
    window.location.href = 'https://m.youtube.com/watch?v=' + videoId;
    return;
  }

  this.setActive_(true, videoId, opt_updateState);
  if (player && videoId == this.activeVideoId_) {
    return;
  } else if (player && videoId != this.activeVideoId_) {
    player.loadVideoById(videoId, 0, 'large');
    this.activeVideoId_ = videoId;
    return;
  }
  var playerEl = document.querySelector('.' + this.config.className + '-player');
  var options = {
    'videoId': videoId,
    'playerVars': objects.clone(this.config.playerVars)
  };
  player = new YT.Player(playerEl, options);
  this.activeVideoId_ = videoId;
}

/**
 * Initializes a YouTube modal dialog singleton.
 * @param {Object=} opt_config Config options.
 */
function init(opt_config) {
  if (initted) {
    return;
  }
  var config = objects.clone(defaultConfig);
  if (opt_config) {
    objects.merge(config, opt_config);
  }

  new YouTubeModal(config);
  initted = true;
}

module.exports = {
  init: init
};
<|endoftext|>


<commit_before>define('pace',
	[        'jquery', 'crafty', 'canvas', 'support'],
	function(    $,     Crafty,   canvas,   support) {
	'use strict';
	console.log('pace loaded');

	return {
		jQuery: $,
		Crafty: Crafty,
		canvas: canvas,
		support: support
	};
});
<commit_msg>testing<commit_after>define('pace',
	[        'jquery', 'crafty', 'canvas', 'support'],
	function(    $,     Crafty,   canvas,   support) {
	'use strict';
	console.log('pace dev loaded');

	return {
		jQuery: $,
		Crafty: Crafty,
		canvas: canvas,
		support: support
	};
});
<|endoftext|>


<commit_before>"use strict";

require('agency-pkg-service-animation-frame');
require('agency-pkg-element-link/touch-indicator');

var js = require('agency-pkg-service-parser').setup(require('./packages'));

(function(){
    $(function() {
        js.parse();
    });
})();
<commit_msg>update parser call<commit_after>"use strict";

require('agency-pkg-service-animation-frame');
require('agency-pkg-element-link/touch-indicator');

var js = require('agency-pkg-service-parser')(require('./packages'));

(function(){
    $(function() {
        js.parse();
    });
})();
<|endoftext|>