<commit_before>;(function () {
  'use strict'
  console.log('in main.js')

// SOCKETS
  const ws = io.connect()

  ws.on('connect', () => {
    console.log('browser socket connected')
  })

  ws.on('receiveSound', sound => {
    // console.log(sound)
    receiveSound(sound)
  })

  ws.on('receiveNotes', notes => {
    // console.log(notes)
    receiveNotes(notes)
  })

// END SOCKETS

// AUDIO CONTEXT
  window.AudioContext = window.AudioContext || window.webkitAudioContext

  if (!AudioContext) {
    alert("Sorry, your browser doesn't support the Web Audio APIs.")
    throw new Error("Sorry, your browser doesn't support the Web Audio APIs. Execution Aborted.") // ABORT ALL
  }

  // default
  // const audio = new AudioContext()
  const audio = new (window.AudioContext || window.webkitAudioContext)()
  const gain = audio.createGain()
  const analyser = audio.createAnalyser()
  gain.gain.value = 0.5;
  gain.connect(audio.destination)
  // audio.connect(analyser)

  // adjust volume
  function volume () {
    // console.log('slider', slider.value)
    gain.gain.value = slider.value
    volumeText.innerHTML = slider.value
  }

  // display values
  function updateDisplay (element, control) {
    // console.log(element, control)
    // console.log('in updateDisplay')
    element.innerHTML = control.value
  }

// END AUDIO CONTEXT

// TEST

// the problem right now is that the bars aren't going down after a certain time
// also i'd like the notes to be spaced out more
// ANALYZER TEST
var canvas = document.querySelector('canvas');
var canvasWidth = canvas.width = window.innerWidth - 40;
var canvasHeight = canvas.height = 300;
var ctx = canvas.getContext('2d');

// var analyzer = synth.audio.createAnalyser();
var analyzer = audio.createAnalyser()
// synth.output.connect(  analyzer );
gain.connect(analyzer)

analyzer.minDecibels = -90;
analyzer.maxDecibels = -10;
analyzer.smoothingTimeConstant = 0.85;

// analyzer.fftSize = 512;
analyzer.fftSize = 2048
var bufferLength = analyzer.frequencyBinCount;
var dataArray = new Uint8Array( bufferLength );

ctx.fillStyle = 'white';
ctx.fillRect( 0, 0, canvasWidth, canvasHeight );

function render() {
  analyzer.getByteFrequencyData( dataArray );

  // shift down
  var canvasImageData = ctx.getImageData( 0, 0, canvasWidth, canvasHeight );
  ctx.putImageData( canvasImageData, 0, 6 );

  ctx.fillStyle = 'black';
  ctx.fillRect( 0, 0, canvasWidth, canvasHeight );

  var barWidth = Math.ceil( canvasWidth / bufferLength * 16);

  for ( var i = 0; i < bufferLength; i++ ) {
    var x = Math.floor( i * barWidth);
    // var x = Math.floor (i * barWidth * 2)
    var amp = dataArray[i] / 200; // should be 256
    // var amp = dataArray[i] / 256
    var hue = Math.round( amp * 210 + 210 );
    var sat = 50 + ( 1- amp) * 50;
    var alpha = amp
    ctx.fillStyle = 'hsla(' + hue + ', 100%, ' + 50 + '%, ' + 1 + ')';
    var barHeight = amp * canvasHeight;
    var y = canvasHeight - barHeight;
    ctx.fillRect( x, y, barWidth, barHeight );
  }

  requestAnimationFrame( render );
}

render();

// END ANALYZER TEST

// LISTENERS

  // label spans
  const hertzText = document.getElementById('hertzText')
  const volumeText = document.getElementById('volumeText')
  const osc1detune = document.getElementById('osc1detune')
  const osc2detune = document.getElementById('osc2detune')
  const slider = document.getElementById('slider')

  slider.addEventListener('input', volume)

  // should only listen when this div has focus so typing in chat doesn't trigger sounds
  const pageContentWrapper = document.getElementById('page-content-wrapper')
  // keydown function
  pageContentWrapper.addEventListener('keydown', pressKey)
  // keyup function
  pageContentWrapper.addEventListener('keyup', releaseKey)

  // shape 1 listener
  const shape = document.getElementById('shape')
  shape.addEventListener('change', getter(shape))

  // detune 1 listener
  const detune1 = document.getElementById('detune1')
  // detune1.addEventListener('change', getter(detune1))
  // detune1.addEventListener('change', updateDisplay(osc1detune, detune1))
  detune1.addEventListener('change', function () {
    getter(detune1)
    updateDisplay(osc1detune, detune1)
  })

  // detune 2 listener
  const detune2 = document.getElementById('detune2')
  // detune2.addEventListener('change', getter(detune2))
  // detune2.addEventListener('change', updateDisplay(osc2detune, detune2))
  detune2.addEventListener('change', function () {
    getter(detune2)
    updateDisplay(osc2detune, detune2)
  })

  // oscillator 2 listener
  const shape2 = document.getElementById('shape2')
  shape2.addEventListener('change', getter(shape2))

  // tempo listener
  const tempo = document.getElementById('tempo')
// LISTENERS END

  // a getter that can get lots of things
  function getter (element) {
    if (element.id === 'tempo') {
      // return element.value
      // console.log('element2', element)
      return element.value >= element.min && element.value <= element.max ? element.value : element.value = g120
    }
    return element.value
  }

// receive sound from another socket
  function receiveSound (sound) {
    // console.log('received', sound)
    gain.connect(audio.destination)
    const osc = audio.createOscillator()
    osc.start()
    osc.type = sound.shape
    osc.frequency.value = sound.frequency
    osc.connect(gain);
    // hertzText.innerHTML = sound.frequency
  }

// END TEST

// KEYS

  const frequencyByKey = {
    65: 261.626, // C4
    87: 277.183, // C#4
    83: 293.665, // D4
    69: 311.127, // D#4
    68: 329.628, // E4
    70: 349.228, // F4
    84: 369.994, // F#4
    71: 391.995, // G4
    89: 415.305, // G#4
    72: 440.000, // A4
    85: 466.164, // A#4
    74: 493.883, // B4
    75: 523.251, // C5
    79: 554.365, // C#5
    76: 587.330, // D5
    80: 622.254 // D#5
  }

  const nameByKey = {
    65: "C4",
    87: "C#4",
    83: "D4",
    69: "D#4",
    68: "E4",
    70: "F4",
    84: "F#4",
    71: "G4",
    89: "G#4",
    72: "A4",
    85: "A#4",
    74: "B4",
    75: "C5",
    79: "C#5",
    76: "D5",
    80: "D#5"
  }

  let nodes = [];

  // you need to think about when someone is chatting that this is not triggered
  // keydown press
  function pressKey (event) {
    // console.log('in press key')
    // console.log(event.keyCode)
    let alreadyPressed = false;
    for (let i = 0; i < nodes.length; i++) {
      if (nodes[i].code === event.keyCode) {
        alreadyPressed = true
        break
      }
    }
    if (event.keyCode >= 65 && event.keyCode <= 90 && !alreadyPressed) {
      const startNote = new Date()
      const osc = audio.createOscillator()
      const beat = 60 / (getter(tempo) * 4)
      // test for 2 oscillators
      const osc2 = audio.createOscillator()
      osc2.type = getter(shape2)
      osc2.frequency.value = frequencyByKey[event.keyCode]
      osc2.detune.value = getter(detune2)
      osc2.connect(gain)
      osc2.start(0)
      osc2.stop(audio.currentTime + beat)
      // end test
      osc.type = getter(shape)
      osc.frequency.value = frequencyByKey[event.keyCode]
      osc.detune.value = getter(detune1)
      // console.log('detune.value', osc.detune.value)
      // console.log('detune.value', osc2.detune.value)
      osc.connect(gain)
      osc.start(0)
      // HEY MAYBE YOU SHOULD HAVE IT WHERE YOU CAN SELECT THE NOTE LENGTH TOO
      osc.stop(audio.currentTime + beat)
      // testing length
      // const beat = getter(tempo) / 60 / 16
      nodes.push({code: event.keyCode, node: osc, length: startNote})
      // const notesToSend = {frequency: frequencyByKey[event.keyCode], shape: getter(shape), notes: nodes, beat: beat }
      const notesToSend = {frequency: osc.frequency.value, shape1: osc.type, shape2: osc2.type, notes: nodes, beat: beat, detune1: osc.detune.value, detune2: osc2.detune.value}
      // console.log("notes", notesToSend)
      ws.emit('sendNotes', notesToSend)

    }
  }

  function receiveNotes (notes) {
    const osc = audio.createOscillator()
    // osc.type = getter(shape)
    osc.type = notes.shape1
    // osc.frequency.value = frequencyByKey[event.keyCode]
    osc.frequency.value = notes.frequency
    osc.detune.value = notes.detune1
    osc.connect(gain)
    // const beat = getter(tempo) / 60 / 16

    // second note
    const osc2 = audio.createOscillator()
    osc2.type = notes.shape2
    osc2.frequency.value = notes.frequency
    osc2.detune.value = notes.detune2
    osc2.connect(gain)
    // end second note

    osc.start(0)
    osc2.start(0)

    osc.stop(audio.currentTime + notes.beat)
    osc2.stop(audio.currentTime + notes.beat)

    // console.log('received notes', notes)
  }

  function releaseKey (event) {
    // console.log('released key')
    const garbage = []
    for (let i = 0; i < nodes.length; i++) {
      if (nodes[i].code === event.keyCode) {
        nodes[i].node.stop(0)
        nodes[i].node.disconnect()
        // testing end note
        const endNote = new Date()
        nodes[i].length = endNote - nodes[i].length
        // console.log('nodes i dot length', nodes[i].length)
        ws.emit('sendNoteEnd')
        // end testing
        garbage.push(i)
      }
    }
    for (let i = 0; i < garbage.length; i++) {
      nodes.splice(garbage[i], 1)
    }
  }

// END KEYS

})();
<commit_msg>tried some things that didn't work<commit_after>;(function () {
  'use strict'
  console.log('in main.js')

// SOCKETS
  const ws = io.connect()

  ws.on('connect', () => {
    console.log('browser socket connected')
  })

  ws.on('receiveSound', sound => {
    // console.log(sound)
    receiveSound(sound)
  })

  ws.on('receiveNotes', notes => {
    // console.log(notes)
    receiveNotes(notes)
  })

// END SOCKETS

// AUDIO CONTEXT
  window.AudioContext = window.AudioContext || window.webkitAudioContext

  if (!AudioContext) {
    alert("Sorry, your browser doesn't support the Web Audio APIs.")
    throw new Error("Sorry, your browser doesn't support the Web Audio APIs. Execution Aborted.") // ABORT ALL
  }

  // default
  // const audio = new AudioContext()
  const audio = new (window.AudioContext || window.webkitAudioContext)()
  const gain = audio.createGain()
  const analyser = audio.createAnalyser()
  gain.gain.value = 0.5;
  gain.connect(audio.destination)
  // audio.connect(analyser)

  // adjust volume
  function volume () {
    // console.log('slider', slider.value)
    gain.gain.value = slider.value
    volumeText.innerHTML = slider.value
  }

  // display values
  function updateDisplay (element, control) {
    // console.log(element, control)
    // console.log('in updateDisplay')
    element.innerHTML = control.value
  }

// END AUDIO CONTEXT

// TEST

// the problem right now is that the bars aren't going down after a certain time
// also i'd like the notes to be spaced out more
// the canvas will disappear when i go to a new program
// ANALYZER TEST
var canvas = document.querySelector('canvas');
var canvasWidth = canvas.width = window.innerWidth - 40;
var canvasHeight = canvas.height = 300;
var ctx = canvas.getContext('2d');

// commented out for a second
var analyzer = audio.createAnalyser()

gain.connect(analyzer)

analyzer.minDecibels = -90;
analyzer.maxDecibels = -10;
analyzer.smoothingTimeConstant = 0.85;

// analyzer.fftSize = 512;
analyzer.fftSize = 2048
var bufferLength = analyzer.frequencyBinCount;
var dataArray = new Uint8Array( bufferLength );

ctx.fillStyle = 'white';
ctx.fillRect( 0, 0, canvasWidth, canvasHeight );

function render() {
  analyzer.getByteFrequencyData( dataArray );

  // shift down
  var canvasImageData = ctx.getImageData( 0, 0, canvasWidth, canvasHeight );
  ctx.putImageData( canvasImageData, 0, 6 );

  ctx.fillStyle = 'black';
  ctx.fillRect( 0, 0, canvasWidth, canvasHeight );

  var barWidth = Math.ceil( canvasWidth / bufferLength * 16);

  for ( var i = 0; i < bufferLength; i++ ) {
    var x = Math.floor( i * barWidth);
    // var x = Math.floor (i * barWidth * 2)
    var amp = dataArray[i] / 200; // should be 256
    // var amp = dataArray[i] / 256
    var hue = Math.round( amp * 210 + 210 );
    var sat = 50 + ( 1- amp) * 50;
    var alpha = amp
    ctx.fillStyle = 'hsla(' + hue + ', 100%, ' + 50 + '%, ' + 1 + ')';
    var barHeight = amp * canvasHeight;
    var y = canvasHeight - barHeight;
    ctx.fillRect( x, y, barWidth, barHeight );
  }

  requestAnimationFrame( render );
}

render();

// END ANALYZER TEST

// LISTENERS

  // label spans
  const hertzText = document.getElementById('hertzText')
  const volumeText = document.getElementById('volumeText')
  const osc1detune = document.getElementById('osc1detune')
  const osc2detune = document.getElementById('osc2detune')
  const slider = document.getElementById('slider')

  slider.addEventListener('input', volume)

  // should only listen when this div has focus so typing in chat doesn't trigger sounds
  const pageContentWrapper = document.getElementById('page-content-wrapper')
  // keydown function
  pageContentWrapper.addEventListener('keydown', pressKey)
  // keyup function
  pageContentWrapper.addEventListener('keyup', releaseKey)

  // shape 1 listener
  const shape = document.getElementById('shape')
  shape.addEventListener('change', getter(shape))

  // detune 1 listener
  const detune1 = document.getElementById('detune1')
  // detune1.addEventListener('change', getter(detune1))
  // detune1.addEventListener('change', updateDisplay(osc1detune, detune1))
  detune1.addEventListener('change', function () {
    getter(detune1)
    updateDisplay(osc1detune, detune1)
  })

  // detune 2 listener
  const detune2 = document.getElementById('detune2')
  // detune2.addEventListener('change', getter(detune2))
  // detune2.addEventListener('change', updateDisplay(osc2detune, detune2))
  detune2.addEventListener('change', function () {
    getter(detune2)
    updateDisplay(osc2detune, detune2)
  })

  // oscillator 2 listener
  const shape2 = document.getElementById('shape2')
  shape2.addEventListener('change', getter(shape2))

  // tempo listener
  const tempo = document.getElementById('tempo')
// LISTENERS END

  // a getter that can get lots of things
  function getter (element) {
    if (element.id === 'tempo') {
      // return element.value
      // console.log('element2', element)
      return element.value >= element.min && element.value <= element.max ? element.value : element.value = g120
    }
    return element.value
  }

// receive sound from another socket
  function receiveSound (sound) {
    // console.log('received', sound)
    gain.connect(audio.destination)
    const osc = audio.createOscillator()
    osc.start()
    osc.type = sound.shape
    osc.frequency.value = sound.frequency
    osc.connect(gain);
    // hertzText.innerHTML = sound.frequency
  }

// END TEST

// KEYS

  const frequencyByKey = {
    65: 261.626, // C4
    87: 277.183, // C#4
    83: 293.665, // D4
    69: 311.127, // D#4
    68: 329.628, // E4
    70: 349.228, // F4
    84: 369.994, // F#4
    71: 391.995, // G4
    89: 415.305, // G#4
    72: 440.000, // A4
    85: 466.164, // A#4
    74: 493.883, // B4
    75: 523.251, // C5
    79: 554.365, // C#5
    76: 587.330, // D5
    80: 622.254 // D#5
  }

  const nameByKey = {
    65: "C4",
    87: "C#4",
    83: "D4",
    69: "D#4",
    68: "E4",
    70: "F4",
    84: "F#4",
    71: "G4",
    89: "G#4",
    72: "A4",
    85: "A#4",
    74: "B4",
    75: "C5",
    79: "C#5",
    76: "D5",
    80: "D#5"
  }

  let nodes = [];

  // you need to think about when someone is chatting that this is not triggered
  // keydown press
  function pressKey (event) {
    // console.log('in press key')
    // console.log(event.keyCode)
    let alreadyPressed = false;
    for (let i = 0; i < nodes.length; i++) {
      if (nodes[i].code === event.keyCode) {
        alreadyPressed = true
        break
      }
    }
    if (event.keyCode >= 65 && event.keyCode <= 90 && !alreadyPressed) {

      // context test
      // const audio = new (window.AudioContext || window.webkitAudioContext)()
      // const gain = audio.createGain()
      // const analyser = audio.createAnalyser()
      // gain.gain.value = 0.5;
      // gain.connect(audio.destination)
      // end context test

      const startNote = new Date()
      const osc = audio.createOscillator()
      const beat = 60 / (getter(tempo) * 4)
      // test for 2 oscillators
      const osc2 = audio.createOscillator()
      osc2.type = getter(shape2)
      osc2.frequency.value = frequencyByKey[event.keyCode]
      osc2.detune.value = getter(detune2)
      // gain.gain.linearRampToValueAtTime(1, audio.currentTime + beat)
      // gain.gain.value = 0.5
      // gain.gain.linearRampToValueAtTime(0, audio.currentTime + 10)
      osc2.connect(gain)
      osc2.start(0)
      osc2.stop(audio.currentTime + beat)
      // end test
      osc.type = getter(shape)
      osc.frequency.value = frequencyByKey[event.keyCode]
      osc.detune.value = getter(detune1)
      // console.log('detune.value', osc.detune.value)
      // console.log('detune.value', osc2.detune.value)
      osc.connect(gain)
      osc.start(0)
      // HEY MAYBE YOU SHOULD HAVE IT WHERE YOU CAN SELECT THE NOTE LENGTH TOO
      osc.stop(audio.currentTime + beat)
      // testing length
      // const beat = getter(tempo) / 60 / 16
      nodes.push({code: event.keyCode, node: osc, length: startNote})
      // const notesToSend = {frequency: frequencyByKey[event.keyCode], shape: getter(shape), notes: nodes, beat: beat }
      const notesToSend = {frequency: osc.frequency.value, shape1: osc.type, shape2: osc2.type, notes: nodes, beat: beat, detune1: osc.detune.value, detune2: osc2.detune.value}
      // console.log("notes", notesToSend)
      ws.emit('sendNotes', notesToSend)

    }
  }

  function receiveNotes (notes) {
    const osc = audio.createOscillator()
    // osc.type = getter(shape)
    osc.type = notes.shape1
    // osc.frequency.value = frequencyByKey[event.keyCode]
    osc.frequency.value = notes.frequency
    osc.detune.value = notes.detune1
    osc.connect(gain)
    // const beat = getter(tempo) / 60 / 16

    // second note
    const osc2 = audio.createOscillator()
    osc2.type = notes.shape2
    osc2.frequency.value = notes.frequency
    osc2.detune.value = notes.detune2
    osc2.connect(gain)
    // end second note

    osc.start(0)
    osc2.start(0)

    osc.stop(audio.currentTime + notes.beat)
    osc2.stop(audio.currentTime + notes.beat)

    // console.log('received notes', notes)
  }

  function releaseKey (event) {
    // console.log('released key')
    const garbage = []
    for (let i = 0; i < nodes.length; i++) {
      if (nodes[i].code === event.keyCode) {
        nodes[i].node.stop(0)
        nodes[i].node.disconnect()
        // testing end note
        const endNote = new Date()
        nodes[i].length = endNote - nodes[i].length
        // console.log('nodes i dot length', nodes[i].length)
        ws.emit('sendNoteEnd')
        // end testing
        garbage.push(i)
      }
    }
    for (let i = 0; i < garbage.length; i++) {
      nodes.splice(garbage[i], 1)
    }
  }

// END KEYS

})();
<|endoftext|>


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

  var events = [];
  var showingEvent = true;
  var eventIndex = 0;
  var eventEls = [];
  var eventStyles = ['event-1', 'event-2'];

  var monthNames = [
    'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec',
  ];

  var dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ];

  var eventTemplate = `

            Next Meeting:

  `;

  function loadEvents() {
    var xhr = new XMLHttpRequest(),
    method = "GET",
    url = "/events";
    xhr.open(method, url, true);
    xhr.onreadystatechange = function () {
      if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
        events = JSON.parse(xhr.responseText);
        events = _.sortedUniqBy(events, function(ev) { return ev.name; });
        renderEvents(events);
      }
    };
    xhr.send();
  }

  function renderEvents(events) {
    for (var i = events.length - 1; i >= 0; i--) {
      var event = events[i];
      var eventEl = elementFromEvent(event, i);
      $(eventEl).addClass(eventStyles[i % (eventStyles.length)]);
      $('#slideshow').append(eventEl);
      eventEls.push(eventEl);
    }
    animateElements();
  }

  function elementFromEvent(event, index) {
    var el = jQuery.parseHTML(eventTemplate);

    var eventTime = new Date(event.start_datetime);
    var hours = eventTime.getHours();
    var pm = false;
    if (hours > 12 ) {
      pm = true;
      hours = hours - 12;
    }

    var formattedTime = dayNames[eventTime.getDay()]
      + ' ' + monthNames[eventTime.getMonth()]
      + ' ' + eventTime.getDate()
      + ' ' + hours + ':' + ("00" +  eventTime.getMinutes()).slice(-2);

    if (pm) {
      formattedTime += ' PM';
    } else {
      formattedTime += ' AM';
    }

    $(el).find('.card-title')[0].innerHTML = event.name;
    $(el).find('.meeting-time')[0].innerHTML = formattedTime;
    $(el).find('.card-body')[0].innerHTML = event.description;
    $(el).addClass('inactive');
    $(el).css('display', 'none');
    return el;
  }

  function animateElements() {
    if (showingEvent) {
      $('.event').css('display', 'none');
      $('.event').removeClass('inactive');
      $('.event').removeClass('active');
      $('.invited').addClass('inactive');
      $('.invited').removeClass('active');

      showingEvent = false;

      var selected = eventEls[eventIndex];

      $(selected).css('display', 'flex');
      $(selected).addClass('active');
      eventIndex = eventIndex + 1;
      if (eventIndex > (events.length - 1)) {
        eventIndex = 0;
      }
      setTimeout(animateElements, 15000);
    } else {
      $('.event').addClass('inactive');
      $('.invited').removeClass('inactive');
      $('.invited').addClass('active');
      showingEvent = true;
      setTimeout(animateElements, 5000);
    }

  }

  function reloadPage() {
    location.reload(true);
  }

  loadEvents();
  setTimeout(reloadPage, 600000);

});

<commit_msg>update to account for TZs in ical<commit_after>$( document ).ready(function() {

  var events = [];
  var showingEvent = true;
  var eventIndex = 0;
  var eventEls = [];
  var eventStyles = ['event-1', 'event-2'];

  var monthNames = [
    'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec',
  ];

  var dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ];

  var eventTemplate = `

            Next Meeting:

  `;

  function loadEvents() {
    var xhr = new XMLHttpRequest(),
    method = "GET",
    url = "/events";
    xhr.open(method, url, true);
    xhr.onreadystatechange = function () {
      if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
        events = JSON.parse(xhr.responseText);
        events = _.sortedUniqBy(events, function(ev) { return ev.name; });
        renderEvents(events);
      }
    };
    xhr.send();
  }

  function renderEvents(events) {
    for (var i = events.length - 1; i >= 0; i--) {
      var event = events[i];
      var eventEl = elementFromEvent(event, i);
      $(eventEl).addClass(eventStyles[i % (eventStyles.length)]);
      $('#slideshow').append(eventEl);
      eventEls.push(eventEl);
    }
    animateElements();
  }

  function elementFromEvent(event, index) {
    var el = jQuery.parseHTML(eventTemplate);

    var eventTime = new Date(event.start_datetime);
    var hours = eventTime.getUTCHours();
    var pm = false;
    if (hours > 12 ) {
      pm = true;
      hours = hours - 12;
    }

    var formattedTime = dayNames[eventTime.getUTCDay()]
      + ' ' + monthNames[eventTime.getUTCMonth()]
      + ' ' + eventTime.getUTCDate()
      + ' ' + hours + ':' + ("00" +  eventTime.getUTCMinutes()).slice(-2);

    if (pm) {
      formattedTime += ' PM';
    } else {
      formattedTime += ' AM';
    }

    $(el).find('.card-title')[0].innerHTML = event.name;
    $(el).find('.meeting-time')[0].innerHTML = formattedTime;
    $(el).find('.card-body')[0].innerHTML = event.description;
    $(el).addClass('inactive');
    $(el).css('display', 'none');
    return el;
  }

  function animateElements() {
    if (showingEvent) {
      $('.event').css('display', 'none');
      $('.event').removeClass('inactive');
      $('.event').removeClass('active');
      $('.invited').addClass('inactive');
      $('.invited').removeClass('active');

      showingEvent = false;

      var selected = eventEls[eventIndex];

      $(selected).css('display', 'flex');
      $(selected).addClass('active');
      eventIndex = eventIndex + 1;
      if (eventIndex > (events.length - 1)) {
        eventIndex = 0;
      }
      setTimeout(animateElements, 15000);
    } else {
      $('.event').addClass('inactive');
      $('.invited').removeClass('inactive');
      $('.invited').addClass('active');
      showingEvent = true;
      setTimeout(animateElements, 5000);
    }

  }

  function reloadPage() {
    location.reload(true);
  }

  loadEvents();
  setTimeout(reloadPage, 600000);

});

<|endoftext|>


<commit_before>// endpoint /api/checkpoint/lat/:param/long/:param
window.onload = function(){
  var geo = navigator.geolocation;
  geo.getCurrentPosition(function (position) {
    sendLocation(position.coords.latitude, position.coords.longitude)
  })

  function sendLocation(lat, lng) {
    var req = new XMLHttpRequest();
    req.addEventListener('load', receiveRotation);
    req.open('GET', `/api/checkpoint/lat/${lat}/long/${lng}`)
    req.send();
  }

  function receiveRotation(){
    console.log(this.responseText)
    var response = JSON.parse(this.responseText)
    setRotation(response.finalBearing)
  }

  function setRotation(deg){
    var rotation = Math.floor(deg);
    var asset = document.querySelector('a-entity[ply-model]');
    asset.setAttribute('rotation', `0 0 ${rotation}`);
  }
}
<commit_msg>renames to bearings. sets negative value for correct direction<commit_after>// endpoint /api/checkpoint/lat/:param/long/:param
window.onload = function(){
  var geo = navigator.geolocation;
  geo.getCurrentPosition(function (position) {
    sendLocation(position.coords.latitude, position.coords.longitude)
  })

  function sendLocation(lat, lng) {
    var req = new XMLHttpRequest();
    req.addEventListener('load', receiveRotation);
    req.open('GET', `/api/checkpoint/lat/${lat}/long/${lng}`)
    req.send();
  }

  function receiveRotation(){
    console.log(this.responseText)
    var response = JSON.parse(this.responseText)
    setRotation(response.finalBearing)
  }

  function setRotation(deg){
    var bearing = -Math.floor(deg);
    var asset = document.querySelector('a-entity[ply-model]');
    asset.setAttribute('rotation', `0 0 ${bearing}`);
  }
}
<|endoftext|>


<commit_before>var root = document.body

var bang = {
  view: function () {
    var alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
      'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
      'z'
    ]

    function alphabetDefinitions (number) {
      var definitions = ['A is for Apple', 'B is for Bug', 'C is for Cat', 'D is for Dog', 'E is for Elephant',
        'F is for Frog', 'G is for Girl', 'H is for Hay', 'I is for Igloo', 'J is for Joke',
        'K is for King', 'L is for Lion', 'M is for Man', 'N is for Night', 'O is for Ocean',
        'P is for Plant', 'Q is for Queen', 'R is for Room', 'S is for Soup', 'T is for Tree',
        'U is for Up', 'V is for Violin', 'W is for World', 'X is for Xylophone', 'Y is for Yogurt',
        'Z is for Zebra'
      ]

      document.getElementById('definition').innerHTML = definitions[number]
    }

    function imageList (number) {
      var list = ['public/imgs/A.jpg', 'public/imgs/B.jpg', 'public/imgs/c.jpg',
        'public/imgs/D.jpg', 'public/imgs/E.jpg', 'public/imgs/F.jpg', 'public/imgs/G.jpg',
        'public/imgs/H.jpg', 'public/imgs/I.jpg', 'public/imgs/J.jpg', 'public/imgs/K.jpg',
        'public/imgs/L.jpeg', 'public/imgs/M.jpg', 'public/imgs/N.jpg', 'public/imgs/O.jpg',
        'public/imgs/P.jpg', 'public/imgs/Q.jpg', 'public/imgs/R.jpeg', 'public/imgs/S.jpeg',
        'public/imgs/T.jpg', 'public/imgs/U.jpg', 'public/imgs/V.jpeg', 'public/imgs/W.jpg',
        'public/imgs/X.jpg', 'public/imgs/Y.jpeg', 'public/imgs/Z.jpeg'
      ]
      document.getElementById('images').height = '200'
      document.getElementById('images').width = '300'
      document.getElementById('images').style.display = 'block'
      document.getElementById('images').style.margin = 'auto'
      document.getElementById('images').src = list[number]
    }

    function soundBytes (number) {
      var sounds = ['http://www.soundjay.com/button/beep-07.wav']
      var getSound = document.getElementById('sound').src = sounds[number]
      document.getElementById('sound').play(getSound)
    }

    return m('bang', [
      m('h2.w3-center', 'Learn the Alphabet'),
      m("h3.w3-center[id='definition']"),
      m("img[id='images']"),
      m("audio[id='sound']"),
      m('br'),
      m('.w3-container.w3-center.w3-bar',
                m('button.w3-btn.w3-blue.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(0)
                    imageList(0)
                    soundBytes(0)
                  }

                },
                    alphabet[0]),
                m('button.w3-btn.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(1)
                    imageList(1)
                  }
                },
                    alphabet[1]),
                m('button.w3-btn.w3-blue.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(2)
                    imageList(2)
                  }
                },
                    alphabet[2]),
                m('button.w3-btn.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(3)
                    imageList(3)
                  }
                },
                    alphabet[3]),

                m('button.w3-btn.w3-blue.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(4)
                    imageList(4)
                  }
                },
                    alphabet[4]),
                m('button.w3-btn.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(5)
                    imageList(5)
                  }
                },
                    alphabet[5]),
                m('button.w3-btn.w3-blue.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(6)
                    imageList(6)
                  }
                },
                    alphabet[6]),
                m('button.w3-btn.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(7)
                    imageList(7)
                  }
                },
                    alphabet[7]),
                m('button.w3-btn.w3-blue.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(8)
                    imageList(8)
                  }
                },
                    alphabet[8]),
                m('button.w3-btn.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(9)
                    imageList(9)
                  }
                },
                    alphabet[9]),

                m('button.w3-btn.w3-blue.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(10)
                    imageList(10)
                  }
                },
                    alphabet[10]),
                m('button.w3-btn.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(11)
                    imageList(11)
                  }
                },
                    alphabet[11]),
                m('button.w3-btn.w3-blue.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(12)
                    imageList(12)
                  }
                },
                    alphabet[12]),
                m('button.w3-btn.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(13)
                    imageList(13)
                  }
                },
                    alphabet[13]),

                m('button.w3-btn.w3-blue.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(14)
                    imageList(14)
                  }
                },
                    alphabet[14]),
                m('button.w3-btn.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(15)
                    imageList(15)
                  }
                },
                    alphabet[15]),
                m('button.w3-btn.w3-blue.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(16)
                    imageList(16)
                  }
                },
                    alphabet[16]),
                m('button.w3-btn.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(17)
                    imageList(17)
                  }
                },
                    alphabet[17]),
                m('button.w3-btn.w3-blue.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(18)
                    imageList(18)
                  }
                },
                    alphabet[18]),
                m('button.w3-btn.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(19)
                    imageList(19)
                  }
                },
                    alphabet[19]),

                m('button.w3-btn.w3-blue.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(20)
                    imageList(20)
                  }
                },
                    alphabet[20]),
                m('button.w3-btn.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(21)
                    imageList(21)
                  }
                },
                    alphabet[21]),
                m('button.w3-btn.w3-blue.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(22)
                    imageList(22)
                  }
                },
                    alphabet[22]),
                m('button.w3-btn.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(23)
                    imageList(23)
                  }
                },
                    alphabet[23]),

                m('button.w3-btn.w3-blue.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(24)
                    imageList(24)
                  }
                },
                    alphabet[24]),
                m('button.w3-btn.w3-padding-large', {
                  onclick: function () {
                    alphabetDefinitions(25)
                    imageList(25)
                  }
                },
                    alphabet[25])

            )

    ])
  }

}

m.route(root, '/bang', {
  '/bang': bang
})
<commit_msg>Add all letters to array and onclick function for sound<commit_after>var root = document.body

var bang = {
  view: function () {
    var alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
      'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
      'z'
    ]

    function alphabetDefinitions (number) {
      var definitions = ['A is for Apple', 'B is for Bug', 'C is for Cat', 'D is for Dog', 'E is for Elephant',
        'F is for Frog', 'G is for Girl', 'H is for Hay', 'I is for Igloo', 'J is for Joke',
        'K is for King', 'L is for Lion', 'M is for Man', 'N is for Night', 'O is for Ocean',
        'P is for Plant', 'Q is for Queen', 'R is for Room', 'S is for Soup', 'T is for Tree',
        'U is for Up', 'V is for Violin', 'W is for World', 'X is for Xylophone', 'Y is for Yogurt',
        'Z is for Zebra'
      ]

      document.getElementById('definition').innerHTML = definitions[number]
    }

    function imageList (number) {
      var list = ['public/imgs/A.jpg', 'public/imgs/B.jpg', 'public/imgs/c.jpg',
        'public/imgs/D.jpg', 'public/imgs/E.jpg', 'public/imgs/F.jpg', 'public/imgs/G.jpg',
        'public/imgs/H.jpg', 'public/imgs/I.jpg', 'public/imgs/J.jpg', 'public/imgs/K.jpg',
        'public/imgs/L.jpeg', 'public/imgs/M.jpg', 'public/imgs/N.jpg', 'public/imgs/O.jpg',
        'public/imgs/P.jpg', 'public/imgs/Q.jpg', 'public/imgs/R.jpeg', 'public/imgs/S.jpeg',
        'public/imgs/T.jpg', 'public/imgs/U.jpg', 'public/imgs/V.jpeg', 'public/imgs/W.jpg',
        'public/imgs/X.jpg', 'public/imgs/Y.jpeg', 'public/imgs/Z.jpeg'
      ]
      document.getElementById('images').height = '200'
      document.getElementById('images').width = '300'
      document.getElementById('images').style.display = 'block'
      document.getElementById('images').style.margin = 'auto'
      document.getElementById('images').src = list[number]
    }

    function soundBytes (number) {
      var sounds = ['public/sound/67712__corsica-s__a.mp3', 'public/sound/67713__corsica-s__b.mp3', 'public/sound/67714__corsica-s__c.mp3',
        'public/sound/67715__corsica-s__d.mp3', 'public/sound/67716__corsica-s__e.mp3', 'public/sound/67717__corsica-s__f.mp3',
        'public/sound/67718__corsica-s__g.mp3', 'public/sound/67719__corsica-s__h.mp3', 'public/sound/67720__corsica-s__i.mp3',
        'public/sound/67721__corsica-s__j.mp3', 'public/sound/67722__corsica-s__k.mp3', 'public/sound/67723__corsica-s__l.mp3',
        'public/sound/67724__corsica-s__m.mp3', 'public/sound/67725__corsica-s__n.mp3', 'public/sound/67726__corsica-s__o.mp3',
        'public/sound/67727__corsica-s__p.mp3', 'public/sound/67728__corsica-s__q.mp3', 'public/sound/67729__corsica-s__r.mp3',
        'public/sound/67730__corsica-s__s.mp3', 'public/sound/67731__corsica-s__t.mp3', 'public/sound/67732__corsica-s__u.mp3',
        'public/sound/67733__corsica-s__v.mp3', 'public/sound/67734__corsica-s__w.mp3', 'public/sound/67735__corsica-s__x.mp3',
        'public/sound/67736__corsica-s__y.mp3', 'public/sound/67737__corsica-s__z.mp3']
      var getSound = document.getElementById('sound').src = sounds[number]
      document.getElementById('sound').play(getSound)
    };

    return m('bang', [
      m('h2.w3-center', 'Learn the Alphabet'),
      m("h3.w3-center[id='definition']"),
      m("img[id='images']"),
      m("audio[id='sound']"),
      m('br'),
      m('.w3-container.w3-center.w3-bar',
        m('button.w3-btn.w3-blue.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(0)
            imageList(0)
            soundBytes(0)
          }

        },
          alphabet[0]),
        m('button.w3-btn.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(1)
            imageList(1)
            soundBytes(1)
          }
        },
          alphabet[1]),
        m('button.w3-btn.w3-blue.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(2)
            imageList(2)
            soundBytes(2)
          }
        },
          alphabet[2]),
        m('button.w3-btn.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(3)
            imageList(3)
            soundBytes(3)
          }
        },
          alphabet[3]),

        m('button.w3-btn.w3-blue.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(4)
            imageList(4)
            soundBytes(4)
          }
        },
          alphabet[4]),
        m('button.w3-btn.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(5)
            imageList(5)
            soundBytes(5)
          }
        },
          alphabet[5]),
        m('button.w3-btn.w3-blue.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(6)
            imageList(6)
            soundBytes(6)
          }
        },
          alphabet[6]),
        m('button.w3-btn.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(7)
            imageList(7)
            soundBytes(7)
          }
        },
          alphabet[7]),
        m('button.w3-btn.w3-blue.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(8)
            imageList(8)
            soundBytes(8)
          }
        },
          alphabet[8]),
        m('button.w3-btn.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(9)
            imageList(9)
            soundBytes(9)
          }
        },
          alphabet[9]),

        m('button.w3-btn.w3-blue.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(10)
            imageList(10)
            soundBytes(10)
          }
        },
          alphabet[10]),
        m('button.w3-btn.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(11)
            imageList(11)
            soundBytes(11)
          }
        },
          alphabet[11]),
        m('button.w3-btn.w3-blue.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(12)
            imageList(12)
            soundBytes(12)
          }
        },
          alphabet[12]),
        m('button.w3-btn.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(13)
            imageList(13)
            soundBytes(13)
          }
        },
          alphabet[13]),

        m('button.w3-btn.w3-blue.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(14)
            imageList(14)
            soundBytes(14)
          }
        },
          alphabet[14]),
        m('button.w3-btn.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(15)
            imageList(15)
            soundBytes(15)
          }
        },
          alphabet[15]),
        m('button.w3-btn.w3-blue.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(16)
            imageList(16)
            soundBytes(16)
          }
        },
          alphabet[16]),
        m('button.w3-btn.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(17)
            imageList(17)
            soundBytes(17)
          }
        },
          alphabet[17]),
        m('button.w3-btn.w3-blue.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(18)
            imageList(18)
            soundBytes(18)
          }
        },
          alphabet[18]),
        m('button.w3-btn.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(19)
            imageList(19)
            soundBytes(19)
          }
        },
          alphabet[19]),

        m('button.w3-btn.w3-blue.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(20)
            imageList(20)
            soundBytes(20)
          }
        },
          alphabet[20]),
        m('button.w3-btn.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(21)
            imageList(21)
            soundBytes(21)
          }
        },
          alphabet[21]),
        m('button.w3-btn.w3-blue.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(22)
            imageList(22)
            soundBytes(22)
          }
        },
          alphabet[22]),
        m('button.w3-btn.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(23)
            imageList(23)
            soundBytes(23)
          }
        },
          alphabet[23]),

        m('button.w3-btn.w3-blue.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(24)
            imageList(24)
            soundBytes(24)
          }
        },
          alphabet[24]),
        m('button.w3-btn.w3-padding-large', {
          onclick: function () {
            alphabetDefinitions(25)
            imageList(25)
            soundBytes(25)
          }
        },
          alphabet[25])

      )

    ])
  }

}

m.route(root, '/bang', {
  '/bang': bang
})
<|endoftext|>


<commit_before>var root = document.body

var bang = {
    view: function() {

        var alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
            'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
            'z'
        ];

        function alphabetDefinitions(number) {
            var definitions = ['A is for Apple', 'B is for Box', 'C is for Cat', 'D is for Dog', 'E is for Elephant',
                'F is for Frog', 'G is for Girl', 'H is for Hay', 'I is for Igloo', 'J is for Joke',
                'K is for King', 'L is for Lion', 'M is for Man', 'N is for Night', 'O is for Open',
                'P is for Plant', 'Q is for Queen', 'R is for Room', 'S is for Soup', 'T is for Tree',
                'U is for Up', 'V is for Violin', 'W is for Water', 'X is for Xylophone', 'Y is for Yogurt',
                'Z is for Zebra'
            ];
            return document.getElementById("definition").innerHTML = definitions[number];
        };

        return m("bang", [
            m("h2.w3-center", "Learn the Alphabet"),
            m("h3.w3-center[id='definition']"),
            m(".w3-container.w3-center.w3-bar",
                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(0)
                        })

                    },
                    alphabet[0]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(1)
                        })
                    },
                    alphabet[1]),
                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(2)
                        })
                    },
                    alphabet[2]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(3)
                        })
                    },
                    alphabet[3]),

                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(4)
                        })
                    },
                    alphabet[4]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(5)
                        })
                    },
                    alphabet[5]),
                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(6)
                        })
                    },
                    alphabet[6]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(7)
                        })
                    },
                    alphabet[7]),
                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(8)
                        })
                    },
                    alphabet[8]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(9)
                        })
                    },
                    alphabet[9]),

                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(10)
                        })
                    },
                    alphabet[10]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(11)
                        })
                    },
                    alphabet[11]),
                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(12)
                        })
                    },
                    alphabet[12]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(13)
                        })
                    },
                    alphabet[13]),

                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(14)
                        })
                    },
                    alphabet[14]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(15)
                        })
                    },
                    alphabet[15]),
                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(16)
                        })
                    },
                    alphabet[16]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(17)
                        })
                    },
                    alphabet[17]),
                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(18)
                        })
                    },
                    alphabet[18]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(19)
                        })
                    },
                    alphabet[19]),

                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(20)
                        })
                    },
                    alphabet[20]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(21)
                        })
                    },
                    alphabet[21]),
                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(22)
                        })
                    },
                    alphabet[22]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(23)
                        })
                    },
                    alphabet[23]),

                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(24)
                        })
                    },
                    alphabet[24]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(25)
                        })
                    },
                    alphabet[25])

            )

        ])
    },

}

m.route(root, "/bang", {
    "/bang": bang,
})<commit_msg>Add Image function<commit_after>var root = document.body

var bang = {
    view: function() {

        var alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
            'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
            'z'
        ];

        function alphabetDefinitions(number) {
            var definitions = ['A is for Apple', 'B is for Box', 'C is for Cat', 'D is for Dog', 'E is for Elephant',
                'F is for Frog', 'G is for Girl', 'H is for Hay', 'I is for Igloo', 'J is for Joke',
                'K is for King', 'L is for Lion', 'M is for Man', 'N is for Night', 'O is for Open',
                'P is for Plant', 'Q is for Queen', 'R is for Room', 'S is for Soup', 'T is for Tree',
                'U is for Up', 'V is for Violin', 'W is for Water', 'X is for Xylophone', 'Y is for Yogurt',
                'Z is for Zebra'
            ];

            return document.getElementById("definition").innerHTML = definitions[number];

        };

        function imageList(number) {
            var list = ['public/imgs/A.jpg'];
            document.getElementById("images").height = "200";
            document.getElementById("images").width = "300";
            document.getElementById("images").style.display = "block";
            document.getElementById("images").style.margin = "auto";
            return document.getElementById("images").src = list[number];

        }

        return m("bang", [
            m("h2.w3-center", "Learn the Alphabet"),
            m("h3.w3-center[id='definition']"),
            m("img[id='images']"),
            m(".w3-container.w3-center.w3-bar",
                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(0);
                            imageList(0);
                        })

                    },
                    alphabet[0]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(1)
                        })
                    },
                    alphabet[1]),
                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(2)
                        })
                    },
                    alphabet[2]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(3)
                        })
                    },
                    alphabet[3]),

                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(4)
                        })
                    },
                    alphabet[4]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(5)
                        })
                    },
                    alphabet[5]),
                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(6)
                        })
                    },
                    alphabet[6]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(7)
                        })
                    },
                    alphabet[7]),
                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(8)
                        })
                    },
                    alphabet[8]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(9)
                        })
                    },
                    alphabet[9]),

                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(10)
                        })
                    },
                    alphabet[10]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(11)
                        })
                    },
                    alphabet[11]),
                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(12)
                        })
                    },
                    alphabet[12]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(13)
                        })
                    },
                    alphabet[13]),

                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(14)
                        })
                    },
                    alphabet[14]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(15)
                        })
                    },
                    alphabet[15]),
                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(16)
                        })
                    },
                    alphabet[16]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(17)
                        })
                    },
                    alphabet[17]),
                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(18)
                        })
                    },
                    alphabet[18]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(19)
                        })
                    },
                    alphabet[19]),

                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(20)
                        })
                    },
                    alphabet[20]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(21)
                        })
                    },
                    alphabet[21]),
                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(22)
                        })
                    },
                    alphabet[22]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(23)
                        })
                    },
                    alphabet[23]),

                m("button.w3-btn.w3-blue.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(24)
                        })
                    },
                    alphabet[24]),
                m("button.w3-btn.w3-padding-large", {
                        onclick: (function() {
                            alphabetDefinitions(25)
                        })
                    },
                    alphabet[25])

            )

        ])
    },

}

m.route(root, "/bang", {
    "/bang": bang,
})<|endoftext|>


<commit_before>/*
 * Preloads an array of images and calls onprogress.
 *
 * var list = ["foo.jpg", "bar.jpg"];
 * preload(list, function(progress) { alert(progress); }
 */
function preload(queue, onprogress)
{
    onprogress(0.0);

    if ($("#preloadpit").size() == 0)
    {
        $("

").appendTo("body").hide();
    }

    function process(remaining, count)
    {
        if (remaining.length >= 1)
        {
            var image = new Image();
            image.onload = function() {

                // force the browser to cache it
                $("").appendTo("#preloadpit");

                if (onprogress)
                {
                    onprogress((count + 1) / (remaining.length + count))
                }
                remaining.shift();

                // javascript's version of tail recursion
                window.setTimeout(function() {
                    process(remaining, count + 1);
                }, 1);
            }
            image.src = remaining[0];
        }
        else
        {
            console.log("Preload of " + count + " images finished.");
        }
    }

    process(queue, 0.0);
}

function preloadvideo(start, stop, generator, onprogress)
{
    var queue = new Array();
    for (var i = start; i <= stop; i++)
    {
        queue[i-start] = generator(i);
    }
    preload(queue, onprogress);
}

/*
 * Updates a slider as the progress continues.
 *
 * var list = ["foo.jpg", "bar.jpg"];
 * preload(list, preloadslider($("#slider")));
 */
function preloadslider(slider, onprogress)
{
    var text = $('

').appendTo(slider);
    text.css({
        'float': 'left',
    });
    var pg = $('

').appendTo(slider);
    pg.css({
        'width': '0%',
        'display': 'block',
        'height': '100%',
    });

    function progress(percent)
    {
        if (onprogress)
        {
            onprogress(percent);
        }
        pg.css('width', percent * 100 + '%');
        text.html(Math.floor(percent * 100) + "%");
    }

    return progress;
}
<commit_msg>concurrent preloading<commit_after>/*
 * Preloads an array of images and calls onprogress.
 *
 * var list = ["foo.jpg", "bar.jpg"];
 * preload(list, function(progress) { alert(progress); }
 */
function preload(queue, onprogress)
{
    onprogress(0.0);

    if ($("#preloadpit").size() == 0)
    {
        $("

").appendTo("body").hide();
    }

    function process(remaining, count)
    {
        var pool = 3;

        if (remaining.length >= 1)
        {
            var roundcount = 0;
            for (var i = 0; i < Math.min(remaining.length, pool); i++)
            {
                (function() { // closure
                    var image = new Image();
                    image.onload = function() {
                        // force the browser to cache it
                        $("").appendTo("#preloadpit");

                        roundcount += 1;

                        if (onprogress)
                        {
                            onprogress((count + roundcount) / (remaining.length + count))
                        }

                        if (roundcount == pool)
                        {
                            // javascript's version of tail recursion
                            window.setTimeout(function() {
                                process(remaining, count + roundcount);
                            }, 1);
                        }
                    }
                    image.src = remaining.shift();
                })();
            }
        }
        else
        {
            console.log("Preload of " + count + " images finished.");
        }
    }

    process(queue, 0.0);
}

function preloadvideo(start, stop, generator, onprogress)
{
    var queue = new Array();
    for (var i = start; i <= stop; i++)
    {
        queue[i-start] = generator(i);
    }
    preload(queue, onprogress);
}

/*
 * Updates a slider as the progress continues.
 *
 * var list = ["foo.jpg", "bar.jpg"];
 * preload(list, preloadslider($("#slider")));
 */
function preloadslider(slider, onprogress)
{
    var text = $('

').appendTo(slider);
    text.css({
        'float': 'left',
    });
    var pg = $('

').appendTo(slider);
    pg.css({
        'width': '0%',
        'display': 'block',
        'height': '100%',
    });

    function progress(percent)
    {
        if (onprogress)
        {
            onprogress(percent);
        }
        pg.css('width', percent * 100 + '%');
        text.html(Math.floor(percent * 100) + "%");
    }

    return progress;
}
<|endoftext|>


<commit_before>/* eslint-disable spellcheck/spell-checker */
import {
  isInternalLink,
  isMessageLink,
  isStreamLink,
  isTopicLink,
  isPmLink,
  isSpecialLink,
  getNarrowFromLink,
  getMessageIdFromLink,
} from '../internalLinks';

import { streamNarrow, topicNarrow } from '../narrow';

describe('isInternalLink', () => {
  test('when link is external, return false', () => {
    expect(isInternalLink('https://example.com', 'https://another.com')).toBe(false);
  });

  test('when link is internal, but not in app, return false', () => {
    expect(isInternalLink('https://example.com/user_uploads', 'https://example.com')).toBe(false);
  });

  test('when link is internal and in app, return true', () => {
    expect(isInternalLink('https://example.com/#narrow/stream/jest', 'https://example.com')).toBe(
      true,
    );
  });

  test('when link is relative and in app, return true', () => {
    expect(isInternalLink('#narrow/stream/jest/topic/topic1', 'https://example.com')).toBe(true);
    expect(isInternalLink('/#narrow/stream/jest', 'https://example.com')).toBe(true);
  });

  test('links including IDs are also recognized', () => {
    expect(isInternalLink('#narrow/stream/123-jest/topic/topic1', 'https://example.com')).toBe(
      true,
    );
    expect(isInternalLink('/#narrow/stream/123-jest', 'https://example.com')).toBe(true);
    expect(isInternalLink('/#narrow/pm-with/123-mark', 'https://example.com')).toBe(true);
  });
});

describe('isMessageLink', () => {
  test('only in-app link containing "near/<message-id>" is a message link', () => {
    expect(isMessageLink('https://example.com/#narrow/stream/jest', 'https://example.com')).toBe(
      false,
    );
    expect(isMessageLink('https://example.com/#narrow/#near/1', 'https://example.com')).toBe(true);
  });
});

describe('isStreamLink', () => {
  test('only in-app link containing "stream" is a stream link', () => {
    expect(
      isStreamLink('https://example.com/#narrow/pm-with/1,2-group', 'https://example.com'),
    ).toBe(false);
    expect(isStreamLink('https://example.com/#narrow/stream/jest', 'https://example.com')).toBe(
      true,
    );
    expect(isStreamLink('https://example.com/#narrow/stream/stream/', 'https://example.com')).toBe(
      true,
    );
  });
});

describe('isTopicLink', () => {
  test('when a url is not a topic narrow return false', () => {
    expect(
      isTopicLink('https://example.com/#narrow/pm-with/1,2-group', 'https://example.com'),
    ).toBe(false);
    expect(isTopicLink('https://example.com/#narrow/stream/jest', 'https://example.com')).toBe(
      false,
    );

    expect(
      isTopicLink(
        'https://example.com/#narrow/stream/stream/topic/topic/near/',
        'https://example.com',
      ),
    ).toBe(false);

    expect(isTopicLink('https://example.com/#narrow/stream/topic/', 'https://example.com')).toBe(
      false,
    );
  });

  test('when a url is a topic narrow return true', () => {
    expect(
      isTopicLink('https://example.com/#narrow/stream/jest/topic/test', 'https://example.com'),
    ).toBe(true);

    expect(
      isTopicLink(
        'https://example.com/#narrow/stream/mobile/subject/topic/near/378333',
        'https://example.com',
      ),
    ).toBe(true);

    expect(
      isTopicLink('https://example.com/#narrow/stream/mobile/topic/topic/', 'https://example.com'),
    ).toBe(true);

    expect(
      isTopicLink(
        'https://example.com/#narrow/stream/stream/topic/topic/near/1',
        'https://example.com',
      ),
    ).toBe(true);

    expect(
      isTopicLink(
        'https://example.com/#narrow/stream/stream/subject/topic/near/1',
        'https://example.com',
      ),
    ).toBe(true);

    expect(isTopicLink('/#narrow/stream/stream/subject/topic', 'https://example.com')).toBe(true);
  });
});

describe('isPmLink', () => {
  test('only in-app link containing "pm-with" is a group link', () => {
    expect(
      isPmLink('https://example.com/#narrow/stream/jest/topic/test', 'https://example.com'),
    ).toBe(false);
    expect(isPmLink('https://example.com/#narrow/pm-with/1,2-group', 'https://example.com')).toBe(
      true,
    );
    expect(
      isPmLink('https://example.com/#narrow/pm-with/1,2-group/near/1', 'https://example.com'),
    ).toBe(true);
    expect(
      isPmLink(
        'https://example.com/#narrow/pm-with/a.40b.2Ecom.c.d.2Ecom/near/3',
        'https://example.com',
      ),
    ).toBe(true);
  });
});

describe('isSpecialLink', () => {
  test('only in-app link containing "is" is a special link', () => {
    expect(
      isSpecialLink('https://example.com/#narrow/stream/jest/topic/test', 'https://example.com'),
    ).toBe(false);

    expect(isSpecialLink('https://example.com/#narrow/is/private', 'https://example.com')).toBe(
      true,
    );

    expect(isSpecialLink('https://example.com/#narrow/is/starred', 'https://example.com')).toBe(
      true,
    );

    expect(isSpecialLink('https://example.com/#narrow/is/mentioned', 'https://example.com')).toBe(
      true,
    );

    expect(isSpecialLink('https://example.com/#narrow/is/men', 'https://example.com')).toBe(false);

    expect(isSpecialLink('https://example.com/#narrow/is/men/stream', 'https://example.com')).toBe(
      false,
    );

    expect(isSpecialLink('https://example.com/#narrow/are/men/stream', 'https://example.com')).toBe(
      false,
    );
  });
});

describe('getNarrowFromLink', () => {
  const usersById = new Map([
    [1, { email: 'abc@example.com', user_id: 1 }],
    [2, { email: 'xyz@example.com', user_id: 2 }],
    [3, { email: 'def@example.com', user_id: 3 }],
  ]);

  test('when link is not in-app link, return default HOME_NARROW', () => {
    expect(getNarrowFromLink('https://example.com/user_uploads', 'https://example.com')).toEqual(
      [],
    );
  });

  test('when link is stream link, return matching streamNarrow', () => {
    expect(
      getNarrowFromLink('https://example.com/#narrow/stream/jest', 'https://example.com'),
    ).toEqual(streamNarrow('jest'));

    expect(
      getNarrowFromLink('https://example.com/#narrow/stream/bot.20testing', 'https://example.com'),
    ).toEqual(streamNarrow('bot testing'));

    expect(
      getNarrowFromLink('https://example.com/#narrow/stream/jest.API', 'https://example.com'),
    ).toEqual(streamNarrow('jest.API'));

    expect(
      getNarrowFromLink('https://example.com/#narrow/stream/stream', 'https://example.com'),
    ).toEqual(streamNarrow('stream'));

    expect(
      getNarrowFromLink('https://example.com/#narrow/stream/topic', 'https://example.com'),
    ).toEqual(streamNarrow('topic'));
  });

  test('when link is stream link, without realm info, return matching streamNarrow', () => {
    expect(getNarrowFromLink('/#narrow/stream/jest', 'https://example.com')).toEqual(
      streamNarrow('jest'),
    );
    expect(getNarrowFromLink('#narrow/stream/jest', 'https://example.com')).toEqual(
      streamNarrow('jest'),
    );
  });

  test('when link is a topic link and encoded, decode stream and topic names and return matching streamNarrow and topicNarrow', () => {
    expect(
      getNarrowFromLink(
        'https://example.com/#narrow/stream/jest/topic/(no.20topic)',
        'https://example.com',
      ),
    ).toEqual(topicNarrow('jest', '(no topic)'));

    expect(
      getNarrowFromLink(
        'https://example.com/#narrow/stream/jest/topic/google.com',
        'https://example.com',
      ),
    ).toEqual(topicNarrow('jest', 'google.com'));

    expect(
      getNarrowFromLink(
        'https://example.com/#narrow/stream/topic/topic/topic.20name',
        'https://example.com',
      ),
    ).toEqual(topicNarrow('topic', 'topic name'));

    expect(
      getNarrowFromLink(
        'https://example.com/#narrow/stream/topic/topic/stream',
        'https://example.com',
      ),
    ).toEqual(topicNarrow('topic', 'stream'));

    expect(
      getNarrowFromLink(
        'https://example.com/#narrow/stream/stream/topic/topic',
        'https://example.com',
      ),
    ).toEqual(topicNarrow('stream', 'topic'));
  });

  test('when link is pointing to a topic without realm info, return matching topicNarrow', () => {
    expect(getNarrowFromLink('/#narrow/stream/stream/topic/topic', 'https://example.com')).toEqual(
      topicNarrow('stream', 'topic'),
    );
    expect(getNarrowFromLink('#narrow/stream/stream/topic/topic', 'https://example.com')).toEqual(
      topicNarrow('stream', 'topic'),
    );
  });

  test('when link is a group link, return matching groupNarrow', () => {
    const expectedValue = [
      {
        operator: 'pm-with',
        operand: 'abc@example.com,xyz@example.com,def@example.com',
      },
    ];
    expect(
      getNarrowFromLink(
        'https://example.com/#narrow/pm-with/1,2,3-group',
        'https://example.com',
        usersById,
      ),
    ).toEqual(expectedValue);
  });

  test('when link is a special link, return matching specialNarrow', () => {
    const expectedValue = [
      {
        operator: 'is',
        operand: 'starred',
      },
    ];
    expect(
      getNarrowFromLink('https://example.com/#narrow/is/starred', 'https://example.com'),
    ).toEqual(expectedValue);
  });

  test('when link is a message link, return matching narrow', () => {
    expect(
      getNarrowFromLink(
        'https://example.com/#narrow/pm-with/1,3-group/near/2',
        'https://example.com',
        usersById,
      ),
    ).toEqual([
      {
        operator: 'pm-with',
        operand: 'abc@example.com,def@example.com',
      },
    ]);

    expect(
      getNarrowFromLink(
        'https://example.com/#narrow/stream/jest/topic/test/near/1',
        'https://example.com',
        usersById,
      ),
    ).toEqual(topicNarrow('jest', 'test'));

    expect(
      getNarrowFromLink(
        'https://example.com/#narrow/stream/jest/subject/test/near/1',
        'https://example.com',
        usersById,
      ),
    ).toEqual(topicNarrow('jest', 'test'));
  });
});

describe('getMessageIdFromLink', () => {
  test('not message link', () => {
    expect(
      getMessageIdFromLink('https://example.com/#narrow/is/private', 'https://example.com'),
    ).toBe(0);
  });

  test('when link is a group link, return anchor message id', () => {
    expect(
      getMessageIdFromLink(
        'https://example.com/#narrow/pm-with/1,3-group/near/1/',
        'https://example.com',
      ),
    ).toBe(1);
  });

  test('when link is a topic link, return anchor message id', () => {
    expect(
      getMessageIdFromLink(
        'https://example.com/#narrow/stream/jest/topic/test/near/1',
        'https://example.com',
      ),
    ).toBe(1);
  });
});
<commit_msg>internal links: Start testing `getLinkType` instead of `is*Link`.<commit_after>/* eslint-disable spellcheck/spell-checker */
import {
  isInternalLink,
  isMessageLink,
  getLinkType,
  getNarrowFromLink,
  getMessageIdFromLink,
} from '../internalLinks';

import { streamNarrow, topicNarrow } from '../narrow';

describe('isInternalLink', () => {
  test('when link is external, return false', () => {
    expect(isInternalLink('https://example.com', 'https://another.com')).toBe(false);
  });

  test('when link is internal, but not in app, return false', () => {
    expect(isInternalLink('https://example.com/user_uploads', 'https://example.com')).toBe(false);
  });

  test('when link is internal and in app, return true', () => {
    expect(isInternalLink('https://example.com/#narrow/stream/jest', 'https://example.com')).toBe(
      true,
    );
  });

  test('when link is relative and in app, return true', () => {
    expect(isInternalLink('#narrow/stream/jest/topic/topic1', 'https://example.com')).toBe(true);
    expect(isInternalLink('/#narrow/stream/jest', 'https://example.com')).toBe(true);
  });

  test('links including IDs are also recognized', () => {
    expect(isInternalLink('#narrow/stream/123-jest/topic/topic1', 'https://example.com')).toBe(
      true,
    );
    expect(isInternalLink('/#narrow/stream/123-jest', 'https://example.com')).toBe(true);
    expect(isInternalLink('/#narrow/pm-with/123-mark', 'https://example.com')).toBe(true);
  });
});

describe('isMessageLink', () => {
  test('only in-app link containing "near/<message-id>" is a message link', () => {
    expect(isMessageLink('https://example.com/#narrow/stream/jest', 'https://example.com')).toBe(
      false,
    );
    expect(isMessageLink('https://example.com/#narrow/#near/1', 'https://example.com')).toBe(true);
  });
});

describe('getLinkType', () => {
  test('only in-app link containing "stream" is a stream link', () => {
    expect(
      getLinkType('https://example.com/#narrow/pm-with/1,2-group', 'https://example.com'),
    ).toBe('pm');
    expect(getLinkType('https://example.com/#narrow/stream/jest', 'https://example.com')).toBe(
      'stream',
    );
    expect(getLinkType('https://example.com/#narrow/stream/stream/', 'https://example.com')).toBe(
      'stream',
    );
  });

  test('when a url is not a topic narrow return false', () => {
    expect(
      getLinkType('https://example.com/#narrow/pm-with/1,2-group', 'https://example.com'),
    ).toBe('pm');
    expect(getLinkType('https://example.com/#narrow/stream/jest', 'https://example.com')).toBe(
      'stream',
    );
    expect(
      getLinkType(
        'https://example.com/#narrow/stream/stream/topic/topic/near/',
        'https://example.com',
      ),
    ).toBe('home');
    expect(getLinkType('https://example.com/#narrow/stream/topic/', 'https://example.com')).toBe(
      'stream',
    );
  });

  test('when a url is a topic narrow return true', () => {
    expect(
      getLinkType('https://example.com/#narrow/stream/jest/topic/test', 'https://example.com'),
    ).toBe('topic');
    expect(
      getLinkType(
        'https://example.com/#narrow/stream/mobile/subject/topic/near/378333',
        'https://example.com',
      ),
    ).toBe('topic');
    expect(
      getLinkType('https://example.com/#narrow/stream/mobile/topic/topic/', 'https://example.com'),
    ).toBe('topic');
    expect(
      getLinkType(
        'https://example.com/#narrow/stream/stream/topic/topic/near/1',
        'https://example.com',
      ),
    ).toBe('topic');
    expect(
      getLinkType(
        'https://example.com/#narrow/stream/stream/subject/topic/near/1',
        'https://example.com',
      ),
    ).toBe('topic');

    expect(getLinkType('/#narrow/stream/stream/subject/topic', 'https://example.com')).toBe(
      'topic',
    );
  });

  test('only in-app link containing "pm-with" is a group link', () => {
    expect(
      getLinkType('https://example.com/#narrow/stream/jest/topic/test', 'https://example.com'),
    ).toBe('topic');
    expect(
      getLinkType('https://example.com/#narrow/pm-with/1,2-group', 'https://example.com'),
    ).toBe('pm');
    expect(
      getLinkType('https://example.com/#narrow/pm-with/1,2-group/near/1', 'https://example.com'),
    ).toBe('pm');
    expect(
      getLinkType(
        'https://example.com/#narrow/pm-with/a.40b.2Ecom.c.d.2Ecom/near/3',
        'https://example.com',
      ),
    ).toBe('pm');
  });

  test('only in-app link containing "is" is a special link', () => {
    expect(
      getLinkType('https://example.com/#narrow/stream/jest/topic/test', 'https://example.com'),
    ).toBe('topic');
    expect(getLinkType('https://example.com/#narrow/is/private', 'https://example.com')).toBe(
      'special',
    );
    expect(getLinkType('https://example.com/#narrow/is/starred', 'https://example.com')).toBe(
      'special',
    );
    expect(getLinkType('https://example.com/#narrow/is/mentioned', 'https://example.com')).toBe(
      'special',
    );
    expect(getLinkType('https://example.com/#narrow/is/men', 'https://example.com')).toBe('home');
    expect(getLinkType('https://example.com/#narrow/is/men/stream', 'https://example.com')).toBe(
      'home',
    );
    expect(getLinkType('https://example.com/#narrow/are/men/stream', 'https://example.com')).toBe(
      'home',
    );
  });
});

describe('getNarrowFromLink', () => {
  const usersById = new Map([
    [1, { email: 'abc@example.com', user_id: 1 }],
    [2, { email: 'xyz@example.com', user_id: 2 }],
    [3, { email: 'def@example.com', user_id: 3 }],
  ]);

  test('when link is not in-app link, return default HOME_NARROW', () => {
    expect(getNarrowFromLink('https://example.com/user_uploads', 'https://example.com')).toEqual(
      [],
    );
  });

  test('when link is stream link, return matching streamNarrow', () => {
    expect(
      getNarrowFromLink('https://example.com/#narrow/stream/jest', 'https://example.com'),
    ).toEqual(streamNarrow('jest'));

    expect(
      getNarrowFromLink('https://example.com/#narrow/stream/bot.20testing', 'https://example.com'),
    ).toEqual(streamNarrow('bot testing'));

    expect(
      getNarrowFromLink('https://example.com/#narrow/stream/jest.API', 'https://example.com'),
    ).toEqual(streamNarrow('jest.API'));

    expect(
      getNarrowFromLink('https://example.com/#narrow/stream/stream', 'https://example.com'),
    ).toEqual(streamNarrow('stream'));

    expect(
      getNarrowFromLink('https://example.com/#narrow/stream/topic', 'https://example.com'),
    ).toEqual(streamNarrow('topic'));
  });

  test('when link is stream link, without realm info, return matching streamNarrow', () => {
    expect(getNarrowFromLink('/#narrow/stream/jest', 'https://example.com')).toEqual(
      streamNarrow('jest'),
    );
    expect(getNarrowFromLink('#narrow/stream/jest', 'https://example.com')).toEqual(
      streamNarrow('jest'),
    );
  });

  test('when link is a topic link and encoded, decode stream and topic names and return matching streamNarrow and topicNarrow', () => {
    expect(
      getNarrowFromLink(
        'https://example.com/#narrow/stream/jest/topic/(no.20topic)',
        'https://example.com',
      ),
    ).toEqual(topicNarrow('jest', '(no topic)'));

    expect(
      getNarrowFromLink(
        'https://example.com/#narrow/stream/jest/topic/google.com',
        'https://example.com',
      ),
    ).toEqual(topicNarrow('jest', 'google.com'));

    expect(
      getNarrowFromLink(
        'https://example.com/#narrow/stream/topic/topic/topic.20name',
        'https://example.com',
      ),
    ).toEqual(topicNarrow('topic', 'topic name'));

    expect(
      getNarrowFromLink(
        'https://example.com/#narrow/stream/topic/topic/stream',
        'https://example.com',
      ),
    ).toEqual(topicNarrow('topic', 'stream'));

    expect(
      getNarrowFromLink(
        'https://example.com/#narrow/stream/stream/topic/topic',
        'https://example.com',
      ),
    ).toEqual(topicNarrow('stream', 'topic'));
  });

  test('when link is pointing to a topic without realm info, return matching topicNarrow', () => {
    expect(getNarrowFromLink('/#narrow/stream/stream/topic/topic', 'https://example.com')).toEqual(
      topicNarrow('stream', 'topic'),
    );
    expect(getNarrowFromLink('#narrow/stream/stream/topic/topic', 'https://example.com')).toEqual(
      topicNarrow('stream', 'topic'),
    );
  });

  test('when link is a group link, return matching groupNarrow', () => {
    const expectedValue = [
      {
        operator: 'pm-with',
        operand: 'abc@example.com,xyz@example.com,def@example.com',
      },
    ];
    expect(
      getNarrowFromLink(
        'https://example.com/#narrow/pm-with/1,2,3-group',
        'https://example.com',
        usersById,
      ),
    ).toEqual(expectedValue);
  });

  test('when link is a special link, return matching specialNarrow', () => {
    const expectedValue = [
      {
        operator: 'is',
        operand: 'starred',
      },
    ];
    expect(
      getNarrowFromLink('https://example.com/#narrow/is/starred', 'https://example.com'),
    ).toEqual(expectedValue);
  });

  test('when link is a message link, return matching narrow', () => {
    expect(
      getNarrowFromLink(
        'https://example.com/#narrow/pm-with/1,3-group/near/2',
        'https://example.com',
        usersById,
      ),
    ).toEqual([
      {
        operator: 'pm-with',
        operand: 'abc@example.com,def@example.com',
      },
    ]);

    expect(
      getNarrowFromLink(
        'https://example.com/#narrow/stream/jest/topic/test/near/1',
        'https://example.com',
        usersById,
      ),
    ).toEqual(topicNarrow('jest', 'test'));

    expect(
      getNarrowFromLink(
        'https://example.com/#narrow/stream/jest/subject/test/near/1',
        'https://example.com',
        usersById,
      ),
    ).toEqual(topicNarrow('jest', 'test'));
  });
});

describe('getMessageIdFromLink', () => {
  test('not message link', () => {
    expect(
      getMessageIdFromLink('https://example.com/#narrow/is/private', 'https://example.com'),
    ).toBe(0);
  });

  test('when link is a group link, return anchor message id', () => {
    expect(
      getMessageIdFromLink(
        'https://example.com/#narrow/pm-with/1,3-group/near/1/',
        'https://example.com',
      ),
    ).toBe(1);
  });

  test('when link is a topic link, return anchor message id', () => {
    expect(
      getMessageIdFromLink(
        'https://example.com/#narrow/stream/jest/topic/test/near/1',
        'https://example.com',
      ),
    ).toBe(1);
  });
});
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2020 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2.wizard',
  name: 'StepWizardletStepsView',
  extends: 'foam.u2.View',

  css: `
    ^item {
      margin-bottom: 15px;
    }
    ^item > .circle {
      margin-right: 15px;
    }
    ^sub-item {
      padding-left: calc(24px + 15px + 4px);
      line-height: 40px;
    }
  `,

  imports: [
    'theme'
  ],

  requires: [
    'foam.u2.detail.AbstractSectionedDetailView',
    'foam.u2.tag.CircleIndicator'
  ],

  methods: [
    function initE() {
      var self = this;
      this
        .add(this.slot(function (data$wizardlets, data$subStack$pos) {
          let elem = this.E();

          let afterCurrent = false;

          // Fixes the sidebar number if a wizardlet is skipped
          let wSkipped = 0;

          for ( let w = 0 ; w < data$wizardlets.length ; w++ ) {
            let wizardlet = this.data.wizardlets[w];
            let isCurrent = wizardlet === this.data.currentWizardlet;

            if ( this.data.countAvailableSections(w) < 1 ) {
              wSkipped++;
              continue;
            }

            let baseCircleIndicator = {
              size: 24,
              borderThickness: 2,
              label: '' + (1 + w - wSkipped),
            };
            elem = elem
              .start()
                .addClass(self.myClass('item'))

                // Render circle indicator
                .start(this.CircleIndicator, {
                  ...baseCircleIndicator,
                  ...(isCurrent ? {
                    borderColor: this.theme.primary1
                  } : afterCurrent ? {
                    borderColor: this.theme.grey2,
                  } : wizardlet.validate() ? {
                    borderColor: this.theme.approval3,
                    backgroundColor: this.theme.approval3,
                    icon: this.theme.glyphs.checkmark.getDataUrl({
                      fill: this.theme.white
                    }),
                    label: ''
                  } : {
                    borderColor: this.theme.warning2
                  })
                })
                  .addClass('circle')
                .end()

                // Render title
                .start('span')
                  .add(wizardlet.title)
                  .style({
                    'font-weight': isCurrent ? 'bold' : 'normal',
                    'color': isCurrent ? this.theme.primary1 : 'inherit'
                  })
                .end();

            // Get section index to highlight current section
            let indices = this.data.screenIndexToSection(data$subStack$pos);

            // Render section labels
            let sections = this.data.sections[w];

            let afterCurrentSection = false;
            for ( let s = 0 ; s < sections.length ; s++ ) {
              let section = sections[s];
              let isCurrentSection = isCurrent && indices[1] === s;
              let onClickSkips = afterCurrent || afterCurrentSection;
              let allowedToSkip = self.data.canSkipTo(w);
              let slot = section.createIsAvailableFor(
                wizardlet.data$
              ).map(function (isAvailable) {
                let e = self.E('span');
                if ( isAvailable ) e = self.renderSectionLabel(
                  e,
                  section, s+1,
                  isCurrentSection,
                  ! isCurrentSection && ( ! onClickSkips || allowedToSkip )
                ).on('click', () => {
                  let targetScreenIndex = self.data.sectionToScreenIndex(w, s);
                  if ( isCurrentSection ) return;
                  if ( onClickSkips ) {
                    if ( allowedToSkip ) {
                      self.data.skipTo(targetScreenIndex);
                    }
                    return;
                  }
                  while ( self.data.subStack.pos !== targetScreenIndex ) {
                    self.data.back();
                  }
                });
                return e;
              })
              if ( isCurrentSection ) afterCurrentSection = true;
              elem.add(slot);
            }

            elem = elem
              .end();

            if ( isCurrent ) afterCurrent = true;
          }

          return elem;
        }))
    },
    function renderSectionLabel(elem, section, index, isCurrent, isClickable) {
      let title = section.title;
      if ( ! title || ! title.trim() ) title = "Part " + index;
      return elem
        .start()
          .addClass(this.myClass('sub-item'))
          .style({
            'color': isCurrent
              ? this.theme.primary1
              : isClickable
                ? 'inherit'
                : this.theme.grey3,
            'font-weight': isCurrent ? 'bold' : 'inherit'
          })
          .add(title)
        .end();
    }
  ]
});<commit_msg>Make step wizard section labels better for long titles<commit_after>/**
 * @license
 * Copyright 2020 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2.wizard',
  name: 'StepWizardletStepsView',
  extends: 'foam.u2.View',

  css: `
    ^item {
      margin-bottom: 15px;
    }
    ^item > .circle {
      margin-right: 15px;
    }
    ^sub-item {
      padding-left: calc(24px + 15px + 4px);
      padding-top: 15px;
    }
  `,

  imports: [
    'theme'
  ],

  requires: [
    'foam.u2.detail.AbstractSectionedDetailView',
    'foam.u2.tag.CircleIndicator'
  ],

  methods: [
    function initE() {
      var self = this;
      this
        .add(this.slot(function (data$wizardlets, data$subStack$pos) {
          let elem = this.E();

          let afterCurrent = false;

          // Fixes the sidebar number if a wizardlet is skipped
          let wSkipped = 0;

          for ( let w = 0 ; w < data$wizardlets.length ; w++ ) {
            let wizardlet = this.data.wizardlets[w];
            let isCurrent = wizardlet === this.data.currentWizardlet;

            if ( this.data.countAvailableSections(w) < 1 ) {
              wSkipped++;
              continue;
            }

            let baseCircleIndicator = {
              size: 24,
              borderThickness: 2,
              label: '' + (1 + w - wSkipped),
            };
            elem = elem
              .start()
                .addClass(self.myClass('item'))

                // Render circle indicator
                .start(this.CircleIndicator, {
                  ...baseCircleIndicator,
                  ...(isCurrent ? {
                    borderColor: this.theme.primary1
                  } : afterCurrent ? {
                    borderColor: this.theme.grey2,
                  } : wizardlet.validate() ? {
                    borderColor: this.theme.approval3,
                    backgroundColor: this.theme.approval3,
                    icon: this.theme.glyphs.checkmark.getDataUrl({
                      fill: this.theme.white
                    }),
                    label: ''
                  } : {
                    borderColor: this.theme.warning2
                  })
                })
                  .addClass('circle')
                .end()

                // Render title
                .start('span')
                  .add(wizardlet.title)
                  .style({
                    'font-weight': isCurrent ? 'bold' : 'normal',
                    'color': isCurrent ? this.theme.primary1 : 'inherit'
                  })
                .end();

            // Get section index to highlight current section
            let indices = this.data.screenIndexToSection(data$subStack$pos);

            // Render section labels
            let sections = this.data.sections[w];

            let afterCurrentSection = false;
            for ( let s = 0 ; s < sections.length ; s++ ) {
              let section = sections[s];
              let isCurrentSection = isCurrent && indices[1] === s;
              let onClickSkips = afterCurrent || afterCurrentSection;
              let allowedToSkip = self.data.canSkipTo(w);
              let slot = section.createIsAvailableFor(
                wizardlet.data$
              ).map(function (isAvailable) {
                let e = self.E('span');
                if ( isAvailable ) e = self.renderSectionLabel(
                  e,
                  section, s+1,
                  isCurrentSection,
                  ! isCurrentSection && ( ! onClickSkips || allowedToSkip )
                ).on('click', () => {
                  let targetScreenIndex = self.data.sectionToScreenIndex(w, s);
                  if ( isCurrentSection ) return;
                  if ( onClickSkips ) {
                    if ( allowedToSkip ) {
                      self.data.skipTo(targetScreenIndex);
                    }
                    return;
                  }
                  while ( self.data.subStack.pos !== targetScreenIndex ) {
                    self.data.back();
                  }
                });
                return e;
              })
              if ( isCurrentSection ) afterCurrentSection = true;
              elem.add(slot);
            }

            elem = elem
              .end();

            if ( isCurrent ) afterCurrent = true;
          }

          return elem;
        }))
    },
    function renderSectionLabel(elem, section, index, isCurrent, isClickable) {
      let title = section.title;
      if ( ! title || ! title.trim() ) title = "Part " + index;
      return elem
        .start()
          .addClass(this.myClass('sub-item'))
          .style({
            'color': isCurrent
              ? this.theme.primary1
              : isClickable
                ? 'inherit'
                : this.theme.grey3,
            'font-weight': isCurrent ? 'bold' : 'inherit'
          })
          .add(title)
        .end();
    }
  ]
});<|endoftext|>