<commit_before>// general web MIDI variables
var midiAccess;
var selectedInput;
var selectedOutput;
var queue = []; // the queue. for now we'll only support one note cannon
var previewQueue = []; // preview queue for hearing before adding
var lastQueue = []; // last queue for retroactively adding
var canAdvance = true; // if a note is already being played we'll need to finish it first
var replaceOnRest = false; // if this flag is set then clear the queue the next note played
// FIXME: this doesn't work when we switch it in the middle of a mode
// TODO: make it so that we can hold as many keys as we want (perhaps a map of each key being held)
// TODO: allow MIDI input to be used in "performance" mode or define an octave or note range for each cannon

// the position in the current queue
var position = -1;

$(document).ready(function() {
	if (navigator.requestMIDIAccess !== undefined) {
		navigator.requestMIDIAccess().then(initMIDI, alert);
	} else {
		alert('No access to MIDI devices: browser does not support Web MIDI! :(');
	}

	$('#selInputs').change(function() {
		var inputs = midiAccess.inputs;
		inputs.forEach(function(port) {
			if (port.id === $('#selInputs :selected').val()) {
				selectedInput = port;
				hookUpMIDI(selectedInput);
			}
		});
	});

	$('#selOutputs').change(function() {
		var outputs = midiAccess.outputs;
		outputs.forEach(function(port) {
			if (port.id === $('#selOutputs :selected').val()) {
				selectedOutput = port;
			}
		});
	});

	for (var i = 1; i < 17; i++) {
		$('#selInputChannel').append($('<option>').val(i).text(i));
		// $('#selOutputChannel').append($('<option>').val(i).text(i));
	};

	// Don't allow the space key to trigger buttons
	$('button').focus(function() {
        this.blur();
    });

	// Queue logic
	$('#btnPlay').mousedown(function() {
		if (!canAdvance) return;
		else canAdvance = false;
		advanceQueue();
	});

	$('#btnPlay').mouseup(function() {
		// FIXME: if both mouse and keyboard are down this may break
		finishAdvanceQueue();
	});

	$('#btnReset').click(function() {
		position = -1;
		$('#queue tbody tr').removeClass('active');
	})

	$('#txtTrigger').keydown(function(ev) {
		if (ev.repeat !== undefined) canAdvance = !ev.repeat;
		if (!canAdvance) return;
		else canAdvance = false;

		advanceQueue();
		return false;
	});

	$('#txtTrigger').keyup(function(ev) {
		// FIXME: if both mouse and keyboard are down this may break
		// or if more than one key is down at a time
		finishAdvanceQueue();
		return false;
	});

	$('#txtTrigger').keypress(function () {
		return false;
	});

	$('#btnClear').click(clearQueue);
	$('#btnAddLast').click(function() { addToQueue(true); });
	$('#btnPreview').mousedown(startPreviewNotes).mouseup(endPreviewNotes);

	key('command+z, ctrl+z', function() {
		removeFromQueue();
		// TODO: when we add to the queue, we should be able to append at certain parts
	});
});

// When MIDI access is requested this function is run.
function initMIDI(access) {
	midiAccess = access;
	showMIDIPorts();
	midiAccess.onstatechange = showMIDIPorts;
}

// Populates select box with MIDI port list.
function showMIDIPorts() {
	// FIXME: Why are there duplicate ports showing up?
	// $('#selInputs option, #selInputs option').remove();

	var inputs = midiAccess.inputs;
	var first = true;
	inputs.forEach(function(port) {
		if (first && !selectedInput) selectedInput = port;
		else first = false;
		$('#selInputs').append($('<option>').val(port.id).text(port.manufacturer + " " + port.name));
	});

	var outputs = midiAccess.outputs;
	first = true;
	outputs.forEach(function(port) {
		if (first && !selectedOutput) selectedOutput = port;
		else first = false;
		$('#selOutputs').append($('<option>').val(port.id).text(port.manufacturer + " " + port.name));
	});

	if (inputs.length === 0) alert('No inputs are available! :(');
	else hookUpMIDI(selectedInput);
	if (outputs.length === 0) alert('No outputs are available! :(');
}

// Hooks up one MIDI port and unhooks all the others.
function hookUpMIDI(port) {
	for (var input of midiAccess.inputs.values())
		input.onmidimessage = null;
	port.onmidimessage = midiMessageReceived;
}

// Every time we receive a MIDI message, determine whether it's a note and deal with it accordingly.
function midiMessageReceived(ev) {
	var cmd = ev.data[0] >> 4;
    var channel = ev.data[0] & 0xf;
    var noteNumber = ev.data[1];
    var velocity = 0;
    if (ev.data.length > 2)
    	velocity = ev.data[2];

    // MIDI noteon with velocity = 0 is the same as noteoff
    if (cmd === 8 || ((cmd === 9) && (velocity === 0))) { // noteoff
      noteOff(noteNumber, channel);
    } else if (cmd === 9) { // note on
      noteOn(noteNumber, velocity, channel);
    } else if (cmd === 11) { // controller message
      //controller(noteNumber, velocity);
    }
}

// When a note is ON, this function will execute
function noteOn(noteNumber, velocity, channel) {
	// Log the note
	logNote(true, noteNumber, velocity, channel);

	if ($('#cbUseChannelFiltering').prop('checked') && channel.toString() !== $('#selInputChannel :selected').val()) return;

	var note = {number: noteNumber, velocity: velocity};

	// Clear the queue if we're replacing notes on rest
	if (replaceOnRest) {
		lastQueue = [];
		replaceOnRest = false;
	}

	// If the note is already in the queue (same number) don't include it
	if (!_.findWhere(lastQueue, {number: note.number})) lastQueue.push(note);

	// Preview the note
	previewQueue.push(note);
	if (selectedOutput) selectedOutput.send([0x90, note.number, $('#cbFixedVelocity').prop('checked') ? 127 : note.velocity]);

	// Display it on the output
	$('#lastQueue tr td').remove();
	$.each(lastQueue, function(i, _note) {
		$('#lastQueue tr').append($('<td>').text(_note.number + ', ' + _note.velocity));
	});
}

// When a note is OFF, this function will execute
function noteOff(noteNumber, channel) {
	// Log the note
	logNote(false, noteNumber, 0, channel);

	// Remove it from the preview queue
	previewQueue = _.filter(previewQueue, function(note) {
		return note.number !== noteNumber;
	});

	if (selectedOutput) selectedOutput.send([0x90, noteNumber, 0]);

	if (previewQueue.length === 0) {
		// Shut off the envelope
		if ($('#cbEagerInput').prop('checked')) {
			// If there are no notes being played right now, add the last played notes to the queue
			addToQueue();
		} else if ($('#cbReplaceOnRest').prop('checked')) {
			replaceOnRest = true;
		}
	}
}

// Adds a series of notes to the cannon
function addToQueue(keepQueue) {
	if (lastQueue.length <= 0) return;
	queue.push(lastQueue);
	var longest = $('#queue th').length - 1;
	var next = $('#queue tbody tr').length + 1;
	var toAdd = lastQueue.length - longest;

	// fill out the rest of the headers with <th>'s if more notes are played than the longest chord we've heard
	if (lastQueue.length > longest) {
		for (var i = 1; i < toAdd + 1; i++) {
			$('#queue thead tr').append($('<th>').text('Note #' + (longest + i)));
			$('#queue tbody tr').append($('<td>'));
		}
	}

	var row = $('<tr>');
	row.append($('<td>').text(next));
	$.each(lastQueue, function(i, note) {
		row.append($('<td>').text(note.number + ', ' + note.velocity));
	});

	// fill out the rest of the row with empty <td>'s if necessary
	if (toAdd * -1 > 0) {
		for (var i = 0; i < toAdd * -1; i++) {
			row.append($('<td>'));
		}
	}

	$('#queue tbody').append(row);

	// unless flag is set, remove the current queue
	if (!keepQueue) {
		$('#lastQueue tr td').remove();
		$('#lastQueue tr').append($('<td>').text('None'));
		lastQueue = [];
	}

	// scroll to note when added
	var queueBox = $('#box');
	var scrollTo = $('#queue tbody tr:last-child');
	queueBox.scrollTop(scrollTo.offset().top - queueBox.offset().top + queueBox.scrollTop());
}

// "Undo" functionality
function removeFromQueue(pos) {
	// TODO: a button for this needs to be on the main screen
	// TODO: UI overhaul
	if (!pos) pos = queue.length - 1;
	queue.splice(pos);

	// TODO: remove empty columns
	$('#queue tbody tr:last-child').remove();
}

// Resets the cannon
function clearQueue() {
	queue = [];
	lastQueue = [];
	previewQueue = [];
	position = -1;
	canAdvance = true;
	$('#queue thead th:not(#counter), #queue tbody tr').remove();
}

// Advances the cannon's position by one and sends out the start of a note
function advanceQueue(over) {
	var longest = $('#queue tbody tr').length;
	if (longest === 0) {
		canAdvance = true;
		return;
	}
	if (position < 0 || position === longest - 1) position = 0;
	else position++;

	$('#queue tbody tr').removeClass('active');
	$($('#queue tbody tr')[position]).addClass('active');

	// scroll to note being played
	var queueBox = $('#box');
	var scrollTo = $('#queue tbody tr.active');
	queueBox.scrollTop(scrollTo.offset().top - queueBox.offset().top + queueBox.scrollTop());

	var notes = queue[position];
	$.each(notes, function(i, note) {
		selectedOutput.send([0x90, note.number, $('#cbFixedVelocity').prop('checked') ? 127 : note.velocity]);
	});
}

// Finishes advancing the cannon's position and sends the end of the note
function finishAdvanceQueue() {
	var longest = $('#queue tbody tr').length;
	if (longest === 0) return;
	var notes = queue[position];
	$.each(notes, function(i, note) {
		selectedOutput.send([0x90, note.number, 0]);
	});
	canAdvance = true;
}

// Preview notes
function startPreviewNotes() {
	$.each(lastQueue, function(i, note) {
		selectedOutput.send([0x90, note.number, $('#cbFixedVelocity').prop('checked') ? 127 : note.velocity]);
	});
}
// Preview notes
function endPreviewNotes() {
	$.each(lastQueue, function(i, note) {
		selectedOutput.send([0x90, note.number, 0]);
	});
}

// Log note to the MIDI monitor
function logNote(pressed, noteNumber, velocity, channel) {
	onOrOff = pressed ? 'ON: ' : 'OFF: ';
	$('#monitor').append($('<div>').addClass(pressed ? 'note-on' : 'note-off').text(onOrOff + noteNumber + (pressed ? ',' + velocity : '') + ', CH: ' + channel));
	$('#monitor').scrollTop($('#monitor')[0].scrollHeight);
}<commit_msg>Update replace notes on rest settings immediately when checkbox checked. Fixes #1<commit_after>// general web MIDI variables
var midiAccess;
var selectedInput;
var selectedOutput;
var queue = []; // the queue. for now we'll only support one note cannon
var previewQueue = []; // preview queue for hearing before adding
var lastQueue = []; // last queue for retroactively adding
var canAdvance = true; // if a note is already being played we'll need to finish it first
var replaceOnRest = true; // if this flag is set then clear the queue the next note played
// FIXME: this doesn't work when we switch it in the middle of a mode
// TODO: make it so that we can hold as many keys as we want (perhaps a map of each key being held)
// TODO: allow MIDI input to be used in "performance" mode or define an octave or note range for each cannon

// the position in the current queue
var position = -1;

$(document).ready(function() {
	if (navigator.requestMIDIAccess !== undefined) {
		navigator.requestMIDIAccess().then(initMIDI, alert);
	} else {
		alert('No access to MIDI devices: browser does not support Web MIDI! :(');
	}

	$('#selInputs').change(function() {
		var inputs = midiAccess.inputs;
		inputs.forEach(function(port) {
			if (port.id === $('#selInputs :selected').val()) {
				selectedInput = port;
				hookUpMIDI(selectedInput);
			}
		});
	});

	$('#selOutputs').change(function() {
		var outputs = midiAccess.outputs;
		outputs.forEach(function(port) {
			if (port.id === $('#selOutputs :selected').val()) {
				selectedOutput = port;
			}
		});
	});

	// Listen for replace checkbox change
	$('#cbReplaceOnRest').change(function() {
		replaceOnRest = this.checked;
	});

	for (var i = 1; i < 17; i++) {
		$('#selInputChannel').append($('<option>').val(i).text(i));
		// $('#selOutputChannel').append($('<option>').val(i).text(i));
	};

	// Don't allow the space key to trigger buttons
	$('button').focus(function() {
        this.blur();
    });

	// Queue logic
	$('#btnPlay').mousedown(function() {
		if (!canAdvance) return;
		else canAdvance = false;
		advanceQueue();
	});

	$('#btnPlay').mouseup(function() {
		// FIXME: if both mouse and keyboard are down this may break
		finishAdvanceQueue();
	});

	$('#btnReset').click(function() {
		position = -1;
		$('#queue tbody tr').removeClass('active');
	})

	$('#txtTrigger').keydown(function(ev) {
		if (ev.repeat !== undefined) canAdvance = !ev.repeat;
		if (!canAdvance) return;
		else canAdvance = false;

		advanceQueue();
		return false;
	});

	$('#txtTrigger').keyup(function(ev) {
		// FIXME: if both mouse and keyboard are down this may break
		// or if more than one key is down at a time
		finishAdvanceQueue();
		return false;
	});

	$('#txtTrigger').keypress(function () {
		return false;
	});

	$('#btnClear').click(clearQueue);
	$('#btnAddLast').click(function() { addToQueue(true); });
	$('#btnPreview').mousedown(startPreviewNotes).mouseup(endPreviewNotes);

	key('command+z, ctrl+z', function() {
		removeFromQueue();
		// TODO: when we add to the queue, we should be able to append at certain parts
	});
});

// When MIDI access is requested this function is run.
function initMIDI(access) {
	midiAccess = access;
	showMIDIPorts();
	midiAccess.onstatechange = showMIDIPorts;
}

// Populates select box with MIDI port list.
function showMIDIPorts() {
	// FIXME: Why are there duplicate ports showing up?
	// $('#selInputs option, #selInputs option').remove();

	var inputs = midiAccess.inputs;
	var first = true;
	inputs.forEach(function(port) {
		if (first && !selectedInput) selectedInput = port;
		else first = false;
		$('#selInputs').append($('<option>').val(port.id).text(port.manufacturer + " " + port.name));
	});

	var outputs = midiAccess.outputs;
	first = true;
	outputs.forEach(function(port) {
		if (first && !selectedOutput) selectedOutput = port;
		else first = false;
		$('#selOutputs').append($('<option>').val(port.id).text(port.manufacturer + " " + port.name));
	});

	if (inputs.length === 0) alert('No inputs are available! :(');
	else hookUpMIDI(selectedInput);
	if (outputs.length === 0) alert('No outputs are available! :(');
}

// Hooks up one MIDI port and unhooks all the others.
function hookUpMIDI(port) {
	for (var input of midiAccess.inputs.values())
		input.onmidimessage = null;
	port.onmidimessage = midiMessageReceived;
}

// Every time we receive a MIDI message, determine whether it's a note and deal with it accordingly.
function midiMessageReceived(ev) {
	var cmd = ev.data[0] >> 4;
    var channel = ev.data[0] & 0xf;
    var noteNumber = ev.data[1];
    var velocity = 0;
    if (ev.data.length > 2)
    	velocity = ev.data[2];

    // MIDI noteon with velocity = 0 is the same as noteoff
    if (cmd === 8 || ((cmd === 9) && (velocity === 0))) { // noteoff
      noteOff(noteNumber, channel);
    } else if (cmd === 9) { // note on
      noteOn(noteNumber, velocity, channel);
    } else if (cmd === 11) { // controller message
      //controller(noteNumber, velocity);
    }
}

// When a note is ON, this function will execute
function noteOn(noteNumber, velocity, channel) {
	// Log the note
	logNote(true, noteNumber, velocity, channel);

	if ($('#cbUseChannelFiltering').prop('checked') && channel.toString() !== $('#selInputChannel :selected').val()) return;

	var note = {number: noteNumber, velocity: velocity};

	// Clear the queue if we're replacing notes on rest
	if (replaceOnRest) {
		lastQueue = [];
		replaceOnRest = false;
	}

	// If the note is already in the queue (same number) don't include it
	if (!_.findWhere(lastQueue, {number: note.number})) lastQueue.push(note);

	// Preview the note
	previewQueue.push(note);
	if (selectedOutput) selectedOutput.send([0x90, note.number, $('#cbFixedVelocity').prop('checked') ? 127 : note.velocity]);

	// Display it on the output
	$('#lastQueue tr td').remove();
	$.each(lastQueue, function(i, _note) {
		$('#lastQueue tr').append($('<td>').text(_note.number + ', ' + _note.velocity));
	});
}

// When a note is OFF, this function will execute
function noteOff(noteNumber, channel) {
	// Log the note
	logNote(false, noteNumber, 0, channel);

	// Remove it from the preview queue
	previewQueue = _.filter(previewQueue, function(note) {
		return note.number !== noteNumber;
	});

	if (selectedOutput) selectedOutput.send([0x90, noteNumber, 0]);

	if (previewQueue.length === 0) {
		// Shut off the envelope
		if ($('#cbEagerInput').prop('checked')) {
			// If there are no notes being played right now, add the last played notes to the queue
			addToQueue();
		} else if ($('#cbReplaceOnRest').prop('checked')) {
			// we need to set replaceOnRest again since the next note will be cleared out
			replaceOnRest = true;
		}
	}
}

// Adds a series of notes to the cannon
function addToQueue(keepQueue) {
	if (lastQueue.length <= 0) return;
	queue.push(lastQueue);
	var longest = $('#queue th').length - 1;
	var next = $('#queue tbody tr').length + 1;
	var toAdd = lastQueue.length - longest;

	// fill out the rest of the headers with <th>'s if more notes are played than the longest chord we've heard
	if (lastQueue.length > longest) {
		for (var i = 1; i < toAdd + 1; i++) {
			$('#queue thead tr').append($('<th>').text('Note #' + (longest + i)));
			$('#queue tbody tr').append($('<td>'));
		}
	}

	var row = $('<tr>');
	row.append($('<td>').text(next));
	$.each(lastQueue, function(i, note) {
		row.append($('<td>').text(note.number + ', ' + note.velocity));
	});

	// fill out the rest of the row with empty <td>'s if necessary
	if (toAdd * -1 > 0) {
		for (var i = 0; i < toAdd * -1; i++) {
			row.append($('<td>'));
		}
	}

	$('#queue tbody').append(row);

	// unless flag is set, remove the current queue
	if (!keepQueue) {
		$('#lastQueue tr td').remove();
		$('#lastQueue tr').append($('<td>').text('None'));
		lastQueue = [];
	}

	// scroll to note when added
	var queueBox = $('#box');
	var scrollTo = $('#queue tbody tr:last-child');
	queueBox.scrollTop(scrollTo.offset().top - queueBox.offset().top + queueBox.scrollTop());
}

// "Undo" functionality
function removeFromQueue(pos) {
	// TODO: a button for this needs to be on the main screen
	// TODO: UI overhaul
	if (!pos) pos = queue.length - 1;
	queue.splice(pos);

	// TODO: remove empty columns
	$('#queue tbody tr:last-child').remove();
}

// Resets the cannon
function clearQueue() {
	queue = [];
	lastQueue = [];
	previewQueue = [];
	position = -1;
	canAdvance = true;
	$('#queue thead th:not(#counter), #queue tbody tr').remove();
}

// Advances the cannon's position by one and sends out the start of a note
function advanceQueue(over) {
	var longest = $('#queue tbody tr').length;
	if (longest === 0) {
		canAdvance = true;
		return;
	}
	if (position < 0 || position === longest - 1) position = 0;
	else position++;

	$('#queue tbody tr').removeClass('active');
	$($('#queue tbody tr')[position]).addClass('active');

	// scroll to note being played
	var queueBox = $('#box');
	var scrollTo = $('#queue tbody tr.active');
	queueBox.scrollTop(scrollTo.offset().top - queueBox.offset().top + queueBox.scrollTop());

	var notes = queue[position];
	$.each(notes, function(i, note) {
		selectedOutput.send([0x90, note.number, $('#cbFixedVelocity').prop('checked') ? 127 : note.velocity]);
	});
}

// Finishes advancing the cannon's position and sends the end of the note
function finishAdvanceQueue() {
	var longest = $('#queue tbody tr').length;
	if (longest === 0) return;
	var notes = queue[position];
	$.each(notes, function(i, note) {
		selectedOutput.send([0x90, note.number, 0]);
	});
	canAdvance = true;
}

// Preview notes
function startPreviewNotes() {
	$.each(lastQueue, function(i, note) {
		selectedOutput.send([0x90, note.number, $('#cbFixedVelocity').prop('checked') ? 127 : note.velocity]);
	});
}
// Preview notes
function endPreviewNotes() {
	$.each(lastQueue, function(i, note) {
		selectedOutput.send([0x90, note.number, 0]);
	});
}

// Log note to the MIDI monitor
function logNote(pressed, noteNumber, velocity, channel) {
	onOrOff = pressed ? 'ON: ' : 'OFF: ';
	$('#monitor').append($('<div>').addClass(pressed ? 'note-on' : 'note-off').text(onOrOff + noteNumber + (pressed ? ',' + velocity : '') + ', CH: ' + channel));
	$('#monitor').scrollTop($('#monitor')[0].scrollHeight);
}<|endoftext|>


<commit_before>const moment             = require('moment');
const countDecimalPlaces = require('./common_independent').countDecimalPlaces;
const Contract           = require('./contract');
const Defaults           = require('./defaults');
const Tick               = require('./tick');
const elementTextContent = require('../../../_common/common_functions').elementTextContent;
const getElementById     = require('../../../_common/common_functions').getElementById;
const isVisible          = require('../../../_common/common_functions').isVisible;

/*
 * Handles barrier processing and display
 *
 * It process `Contract.barriers` and display them if its applicable
 * for current `Contract.form()
 */

const Barriers = (() => {
    let is_barrier_updated = false;

    const display = () => {
        const barriers  = Contract.barriers()[Defaults.get('underlying')];
        const form_name = Contract.form();

        if (barriers && form_name && Defaults.get('formname') !== 'risefall') {
            const barrier = barriers[form_name];
            if (barrier) {
                const current_tick   = Tick.quote();
                const decimal_places = countDecimalPlaces(current_tick);

                const unit                            = getElementById('duration_units');
                const end_time                        = getElementById('expiry_date');
                const indicative_barrier_tooltip      = getElementById('indicative_barrier_tooltip');
                const indicative_high_barrier_tooltip = getElementById('indicative_high_barrier_tooltip');
                const indicative_low_barrier_tooltip  = getElementById('indicative_low_barrier_tooltip');

                if (barrier.count === 1) {
                    getElementById('high_barrier_row').style.display = 'none';
                    getElementById('low_barrier_row').style.display  = 'none';
                    getElementById('barrier_row').setAttribute('style', '');

                    const defaults_barrier = Defaults.get('barrier');
                    const elm              = getElementById('barrier');
                    const tooltip          = getElementById('barrier_tooltip');
                    const span             = getElementById('barrier_span');
                    let barrier_def        = defaults_barrier && !isNaN(defaults_barrier) ?
                        defaults_barrier : (barrier.barrier || 0);
                    let value;
                    if ((unit && isVisible(unit) && unit.value === 'd') ||
                        (end_time && isVisible(end_time) && moment(end_time.getAttribute('data-value')).isAfter(moment(), 'day')) ||
                        !String(barrier.barrier).match(/^[+-]/)) {
                        if (current_tick && !isNaN(current_tick) && String(barrier_def).match(/^[+-]/)) {
                            value = (parseFloat(current_tick) + parseFloat(barrier_def)).toFixed(decimal_places);
                        } else {
                            value = parseFloat(barrier_def);
                        }
                        tooltip.style.display = 'none';
                        span.style.display    = 'inherit';
                        // no need to display indicative barrier in case of absolute barrier
                        elementTextContent(indicative_barrier_tooltip, '');
                    } else {
                        if (!String(barrier_def).match(/^[+-]/)) barrier_def = barrier.barrier; // override Defaults value, because it's changing from absolute to relative barrier
                        value                 = barrier_def;
                        span.style.display    = 'none';
                        tooltip.style.display = 'inherit';
                        if (current_tick && !isNaN(current_tick)) {
                            elementTextContent(indicative_barrier_tooltip, (parseFloat(current_tick) +
                                parseFloat(barrier_def)).toFixed(decimal_places));
                        } else {
                            elementTextContent(indicative_barrier_tooltip, '');
                        }
                    }
                    elm.value = elm.textContent = value;
                    Defaults.set('barrier', elm.value);
                    Defaults.remove('barrier_high', 'barrier_low');
                    Barriers.validateBarrier();
                    return;
                } else if (barrier.count === 2) {
                    getElementById('barrier_row').style.display = 'none';
                    getElementById('high_barrier_row').setAttribute('style', '');
                    getElementById('low_barrier_row').setAttribute('style', '');

                    const high_elm     = getElementById('barrier_high');
                    const low_elm      = getElementById('barrier_low');
                    const high_tooltip = getElementById('barrier_high_tooltip');
                    const high_span    = getElementById('barrier_high_span');
                    const low_tooltip  = getElementById('barrier_low_tooltip');
                    const low_span     = getElementById('barrier_low_span');

                    const defaults_high = Defaults.get('barrier_high');
                    const defaults_low  = Defaults.get('barrier_low');

                    let barrier_high = defaults_high && !isNaN(defaults_high) ? defaults_high : (barrier.barrier || 0);
                    let barrier_low  = defaults_low && !isNaN(defaults_low) ?
                        defaults_low : (barrier.barrier1 || 0);
                    let value_high,
                        value_low;
                    if ((unit && isVisible(unit) && unit.value === 'd') ||
                        (end_time && isVisible(end_time) && moment(end_time.getAttribute('data-value')).isAfter(moment(), 'day')) ||
                        !String(barrier.barrier).match(/^[+-]/)) {
                        if (current_tick && !isNaN(current_tick) && String(barrier_high).match(/^[+-]/)) {
                            value_high = (parseFloat(current_tick) + parseFloat(barrier_high)).toFixed(decimal_places);
                            value_low  = (parseFloat(current_tick) + parseFloat(barrier_low)).toFixed(decimal_places);
                        } else {
                            value_high = parseFloat(barrier_high);
                            value_low  = parseFloat(barrier_low);
                        }

                        high_span.style.display    = 'inherit';
                        high_tooltip.style.display = 'none';
                        low_span.style.display     = 'inherit';
                        low_tooltip.style.display  = 'none';

                        elementTextContent(indicative_high_barrier_tooltip, '');
                        elementTextContent(indicative_low_barrier_tooltip, '');
                    } else {
                        // override Defaults value, if it's changing from absolute to relative barrier
                        if (!String(barrier_high).match(/^[+-]/) || !String(barrier_low).match(/^[+-]/)) {
                            barrier_high = barrier.barrier;
                            barrier_low  = barrier.barrier1;
                        }
                        value_high = barrier_high;
                        value_low  = barrier_low;

                        high_span.style.display    = 'none';
                        high_tooltip.style.display = 'inherit';
                        low_span.style.display     = 'none';
                        low_tooltip.style.display  = 'inherit';

                        const barrierVal = (tick, barrier_value) => (
                            (tick + parseFloat(barrier_value)).toFixed(decimal_places)
                        );

                        if (current_tick && !isNaN(current_tick)) {
                            const tick = parseFloat(current_tick);
                            elementTextContent(indicative_high_barrier_tooltip, barrierVal(tick, barrier_high));
                            elementTextContent(indicative_low_barrier_tooltip, barrierVal(tick, barrier_low));
                        } else {
                            elementTextContent(indicative_high_barrier_tooltip, '');
                            elementTextContent(indicative_low_barrier_tooltip, '');
                        }
                    }
                    high_elm.value = high_elm.textContent = value_high;
                    low_elm.value  = low_elm.textContent  = value_low;

                    Defaults.set('barrier_high', high_elm.value);
                    Defaults.set('barrier_low', low_elm.value);
                    Defaults.remove('barrier');
                    Barriers.validateBarrier();
                    return;
                }
                Barriers.validateBarrier();
            }
        }

        const elements = document.getElementsByClassName('barrier_class');
        for (let i = 0; i < elements.length; i++) {
            elements[i].style.display = 'none';
        }
        Defaults.remove('barrier', 'barrier_high', 'barrier_low');
    };

    const validateBarrier = () => {
        const barrier_element = getElementById('barrier');
        const empty           = isNaN(parseFloat(barrier_element.value)) || parseFloat(barrier_element.value) === 0;
        const barrier_high_error_element = getElementById('barrier_high_error');
        const barrier_low_error_element = getElementById('barrier_low_error');
        const barrier_high_element = getElementById('barrier_high');
        const barrier_low_element = getElementById('barrier_low');

        if (isVisible(barrier_element) && empty) {
            barrier_element.classList.add('error-field');
        } else {
            barrier_element.classList.remove('error-field');
        }

        if (+barrier_high_element.value > +barrier_low_element.value) {
            barrier_high_element.classList.remove('error-field');
            barrier_low_element.classList.remove('error-field');
            barrier_high_error_element.classList.add('invisible');
            barrier_low_error_element.classList.add('invisible');
        } else {
            barrier_high_element.classList.add('error-field');
            barrier_low_element.classList.add('error-field');
            barrier_high_error_element.classList.remove('invisible');
            barrier_low_error_element.classList.remove('invisible');
        }
    };

    return {
        display,
        validateBarrier,
        isBarrierUpdated: () => is_barrier_updated,
        setBarrierUpdate: (flag) => { is_barrier_updated = flag; },
    };
})();

module.exports = Barriers;
<commit_msg>delete check higher lower barriers<commit_after>const moment             = require('moment');
const countDecimalPlaces = require('./common_independent').countDecimalPlaces;
const Contract           = require('./contract');
const Defaults           = require('./defaults');
const Tick               = require('./tick');
const elementTextContent = require('../../../_common/common_functions').elementTextContent;
const getElementById     = require('../../../_common/common_functions').getElementById;
const isVisible          = require('../../../_common/common_functions').isVisible;

/*
 * Handles barrier processing and display
 *
 * It process `Contract.barriers` and display them if its applicable
 * for current `Contract.form()
 */

const Barriers = (() => {
    let is_barrier_updated = false;

    const display = () => {
        const barriers  = Contract.barriers()[Defaults.get('underlying')];
        const form_name = Contract.form();

        if (barriers && form_name && Defaults.get('formname') !== 'risefall') {
            const barrier = barriers[form_name];
            if (barrier) {
                const current_tick   = Tick.quote();
                const decimal_places = countDecimalPlaces(current_tick);

                const unit                            = getElementById('duration_units');
                const end_time                        = getElementById('expiry_date');
                const indicative_barrier_tooltip      = getElementById('indicative_barrier_tooltip');
                const indicative_high_barrier_tooltip = getElementById('indicative_high_barrier_tooltip');
                const indicative_low_barrier_tooltip  = getElementById('indicative_low_barrier_tooltip');

                if (barrier.count === 1) {
                    getElementById('high_barrier_row').style.display = 'none';
                    getElementById('low_barrier_row').style.display  = 'none';
                    getElementById('barrier_row').setAttribute('style', '');

                    const defaults_barrier = Defaults.get('barrier');
                    const elm              = getElementById('barrier');
                    const tooltip          = getElementById('barrier_tooltip');
                    const span             = getElementById('barrier_span');
                    let barrier_def        = defaults_barrier && !isNaN(defaults_barrier) ?
                        defaults_barrier : (barrier.barrier || 0);
                    let value;
                    if ((unit && isVisible(unit) && unit.value === 'd') ||
                        (end_time && isVisible(end_time) && moment(end_time.getAttribute('data-value')).isAfter(moment(), 'day')) ||
                        !String(barrier.barrier).match(/^[+-]/)) {
                        if (current_tick && !isNaN(current_tick) && String(barrier_def).match(/^[+-]/)) {
                            value = (parseFloat(current_tick) + parseFloat(barrier_def)).toFixed(decimal_places);
                        } else {
                            value = parseFloat(barrier_def);
                        }
                        tooltip.style.display = 'none';
                        span.style.display    = 'inherit';
                        // no need to display indicative barrier in case of absolute barrier
                        elementTextContent(indicative_barrier_tooltip, '');
                    } else {
                        if (!String(barrier_def).match(/^[+-]/)) barrier_def = barrier.barrier; // override Defaults value, because it's changing from absolute to relative barrier
                        value                 = barrier_def;
                        span.style.display    = 'none';
                        tooltip.style.display = 'inherit';
                        if (current_tick && !isNaN(current_tick)) {
                            elementTextContent(indicative_barrier_tooltip, (parseFloat(current_tick) +
                                parseFloat(barrier_def)).toFixed(decimal_places));
                        } else {
                            elementTextContent(indicative_barrier_tooltip, '');
                        }
                    }
                    elm.value = elm.textContent = value;
                    Defaults.set('barrier', elm.value);
                    Defaults.remove('barrier_high', 'barrier_low');
                    Barriers.validateBarrier();
                    return;
                } else if (barrier.count === 2) {
                    getElementById('barrier_row').style.display = 'none';
                    getElementById('high_barrier_row').setAttribute('style', '');
                    getElementById('low_barrier_row').setAttribute('style', '');

                    const high_elm     = getElementById('barrier_high');
                    const low_elm      = getElementById('barrier_low');
                    const high_tooltip = getElementById('barrier_high_tooltip');
                    const high_span    = getElementById('barrier_high_span');
                    const low_tooltip  = getElementById('barrier_low_tooltip');
                    const low_span     = getElementById('barrier_low_span');

                    const defaults_high = Defaults.get('barrier_high');
                    const defaults_low  = Defaults.get('barrier_low');

                    let barrier_high = defaults_high && !isNaN(defaults_high) ? defaults_high : (barrier.barrier || 0);
                    let barrier_low  = defaults_low && !isNaN(defaults_low) ?
                        defaults_low : (barrier.barrier1 || 0);
                    let value_high,
                        value_low;
                    if ((unit && isVisible(unit) && unit.value === 'd') ||
                        (end_time && isVisible(end_time) && moment(end_time.getAttribute('data-value')).isAfter(moment(), 'day')) ||
                        !String(barrier.barrier).match(/^[+-]/)) {
                        if (current_tick && !isNaN(current_tick) && String(barrier_high).match(/^[+-]/)) {
                            value_high = (parseFloat(current_tick) + parseFloat(barrier_high)).toFixed(decimal_places);
                            value_low  = (parseFloat(current_tick) + parseFloat(barrier_low)).toFixed(decimal_places);
                        } else {
                            value_high = parseFloat(barrier_high);
                            value_low  = parseFloat(barrier_low);
                        }

                        high_span.style.display    = 'inherit';
                        high_tooltip.style.display = 'none';
                        low_span.style.display     = 'inherit';
                        low_tooltip.style.display  = 'none';

                        elementTextContent(indicative_high_barrier_tooltip, '');
                        elementTextContent(indicative_low_barrier_tooltip, '');
                    } else {
                        // override Defaults value, if it's changing from absolute to relative barrier
                        if (!String(barrier_high).match(/^[+-]/) || !String(barrier_low).match(/^[+-]/)) {
                            barrier_high = barrier.barrier;
                            barrier_low  = barrier.barrier1;
                        }
                        value_high = barrier_high;
                        value_low  = barrier_low;

                        high_span.style.display    = 'none';
                        high_tooltip.style.display = 'inherit';
                        low_span.style.display     = 'none';
                        low_tooltip.style.display  = 'inherit';

                        const barrierVal = (tick, barrier_value) => (
                            (tick + parseFloat(barrier_value)).toFixed(decimal_places)
                        );

                        if (current_tick && !isNaN(current_tick)) {
                            const tick = parseFloat(current_tick);
                            elementTextContent(indicative_high_barrier_tooltip, barrierVal(tick, barrier_high));
                            elementTextContent(indicative_low_barrier_tooltip, barrierVal(tick, barrier_low));
                        } else {
                            elementTextContent(indicative_high_barrier_tooltip, '');
                            elementTextContent(indicative_low_barrier_tooltip, '');
                        }
                    }
                    high_elm.value = high_elm.textContent = value_high;
                    low_elm.value  = low_elm.textContent  = value_low;

                    Defaults.set('barrier_high', high_elm.value);
                    Defaults.set('barrier_low', low_elm.value);
                    Defaults.remove('barrier');
                    Barriers.validateBarrier();
                    return;
                }
            }
        }

        const elements = document.getElementsByClassName('barrier_class');
        for (let i = 0; i < elements.length; i++) {
            elements[i].style.display = 'none';
        }
        Defaults.remove('barrier', 'barrier_high', 'barrier_low');
    };

    const validateBarrier = () => {
        const barrier_element = getElementById('barrier');
        const empty           = isNaN(parseFloat(barrier_element.value)) || parseFloat(barrier_element.value) === 0;
        const barrier_high_error_element = getElementById('barrier_high_error');
        const barrier_low_error_element = getElementById('barrier_low_error');
        const barrier_high_element = getElementById('barrier_high');
        const barrier_low_element = getElementById('barrier_low');

        if (isVisible(barrier_element) && empty) {
            barrier_element.classList.add('error-field');
        } else {
            barrier_element.classList.remove('error-field');
        }

        if (+barrier_high_element.value > +barrier_low_element.value) {
            barrier_high_element.classList.remove('error-field');
            barrier_low_element.classList.remove('error-field');
            barrier_high_error_element.classList.add('invisible');
            barrier_low_error_element.classList.add('invisible');
        } else {
            barrier_high_element.classList.add('error-field');
            barrier_low_element.classList.add('error-field');
            barrier_high_error_element.classList.remove('invisible');
            barrier_low_error_element.classList.remove('invisible');
        }
    };

    return {
        display,
        validateBarrier,
        isBarrierUpdated: () => is_barrier_updated,
        setBarrierUpdate: (flag) => { is_barrier_updated = flag; },
    };
})();

module.exports = Barriers;
<|endoftext|>


<commit_before>var USE_FULL_SOUNDFONT_LIBRARY = true, //set this variable to true after downloading https://github.com/gleitz/midi-js-soundfonts and placing in soundfont directory

  FPS = {show: false, last: Date.now(), count: 0},
  NOTE = {last: Date.now(), next: Date.now()},
  INPUT = {last: Date.now(), e: null, x: null, y: null, mousedown: false, cursor: null},
  EFFECTS = {},
  SONG, THEME, SCENE, CAMERA, RENDERER;

////////////////////////////////
// INIT
////////////////////////////////

window.onload = function() {

  //init three.js

  SCENE = new THREE.Scene();

  CAMERA = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
  CAMERA.position.z = 600;

  RENDERER = new THREE.WebGLRenderer();
  RENDERER.setSize(window.innerWidth, window.innerHeight);

  document.body.appendChild(RENDERER.domElement);

  //setup cursor

  var c_mat = new THREE.MeshBasicMaterial({color: 0xdddddd});
  var c_geo = new THREE.CircleGeometry(1, 24);
  INPUT.cursor = new THREE.Mesh(c_geo, c_mat);
  SCENE.add(INPUT.cursor);

  //setup theme, song, and effect mapping

  THEME = THEMES[Math.floor(Math.random() * THEMES.length)];

  SONG = SONGS[Math.floor(Math.random() * SONGS.length)];
  SONG = SONGS[6];

  if(!SONG.effectMapping.hasOwnProperty('channels')) SONG.effectMapping.channels = {};
  if(!SONG.effectMapping.hasOwnProperty('globals')) SONG.effectMapping.globals = [];

  for(var i = 0; i < SONG.effectMapping.globals.length; i++) {
    if(EFFECTS.hasOwnProperty(SONG.effectMapping.globals[i])) {
      SONG.effectMapping.globals[i] = EFFECTS[SONG.effectMapping.globals[i]];
      if(SONG.effectMapping.globals[i].hasOwnProperty('setup')) SONG.effectMapping.globals[i].setup();
    }
  }

  for(var i in SONG.effectMapping.channels) {
    if(EFFECTS.hasOwnProperty(SONG.effectMapping.channels[i])) {
      SONG.effectMapping.channels[i] = EFFECTS[SONG.effectMapping.channels[i]];
      if(SONG.effectMapping.channels[i].hasOwnProperty('setup')) SONG.effectMapping.channels[i].setup();
    }
  }

  //init MIDI.js

  if(SONG.hasOwnProperty('bpm')) MIDI.Player.BPM = SONG.bpm;

  MIDI.loadPlugin({
    soundfontUrl: "soundfont/",
    onsuccess: function() {
      MIDI.Player.loadFile(SONG.path, function() {

        //seek?
        if(SONG.hasOwnProperty('wadsworth')) MIDI.Player.currentTime = SONG.wadsworth * 1000;

        //if we are using the full soundfont library, load the instruments needed for this song

        if(USE_FULL_SOUNDFONT_LIBRARY) {
          var instruments = MIDI.Player.getFileInstruments();
          var instrumentsToLoad = instruments.length;
          for(var i = 0; i < instruments.length; i++) {
            var channel = i;
            MIDI.loadResource({
              instrument: instruments[i],
              onsuccess: function(c) {
                MIDI.programChange(c, MIDI.GM.byName[instruments[c]].number);
                instrumentsToLoad--;
                if(instrumentsToLoad == 0) appReady();
              } (channel)
            });
          }
        }

        else appReady();

      });
    }
  });

  //init user/midi input and run the animation after file (and possibly all instruments) load

  function appReady() {

    MIDI.Player.addListener(function(e) {
      NOTE.last = Date.now();

      var eMap = SONG.effectMapping.channels;
      if(e.hasOwnProperty('channel') && eMap[e.channel]) {
        if(e.message == 144 && eMap[e.channel].hasOwnProperty('spawn')) {
          eMap[e.channel].spawn(e);
        } else if(e.message == 128 && eMap[e.channel].hasOwnProperty('despawn')) {
          eMap[e.channel].despawn(e);
        }
      }

      for(var i = 0; i < SONG.effectMapping.globals.length; i++) {
        if(e.message == 144 && SONG.effectMapping.globals[i].hasOwnProperty('spawn')) {
          SONG.effectMapping.globals[i].spawn(e);
        } else if(e.message == 128 && SONG.effectMapping.globals[i].hasOwnProperty('despawn')) {
          SONG.effectMapping.globals[i].despawn(e);
        }
      }
    });

    function inputEvent(e) {
      INPUT.x = ((e.clientX / window.innerWidth) - 0.5) * window.innerWidth;
      INPUT.y = ((e.clientY / window.innerHeight) - 0.5) * -window.innerHeight;
      INPUT.cursor.position.x = INPUT.x;
      INPUT.cursor.position.y = INPUT.y;
      INPUT.e = e;
      INPUT.last = Date.now();

      if(!MIDI.Player.playing) {
        MIDI.Player.resume();
      }

      for(var i in SONG.effectMapping.channels) {
        if(SONG.effectMapping.channels[i] && SONG.effectMapping.channels[i].hasOwnProperty('input')) {
          SONG.effectMapping.channels[i].input();
        }
      }

      for(var i = 0; i < SONG.effectMapping.globals.length; i++) {
        if(SONG.effectMapping.globals[i] && SONG.effectMapping.globals[i].hasOwnProperty('input')) {
          SONG.effectMapping.globals[i].input();
        }
      }
    }

    window.onmousemove = inputEvent;

    window.onmousedown = function(e) {
      INPUT.mousedown = true;
      inputEvent(e);
    }

    window.onmouseup = function(e) {
      INPUT.mousedown = false;
    }

    window.ontouchmove = function(e) {
      e.clientX = e.touches[0].clientX;
      e.clientY = e.touches[0].clientY;
      inputEvent(e);
    }

    window.onkeypress = function(e) {
      e.clientX = Math.floor(Math.random() * window.innerWidth);
      e.clientY = Math.floor(Math.random() * window.innerHeight);
      inputEvent(e);

      if(e.which == 32) {
        //change theme
        THEME = THEMES[Math.floor(Math.random() * THEMES.length)];

        //dispatch randomize events
        for(var i in SONG.effectMapping.channels) {
          if(SONG.effectMapping.channels[i] && SONG.effectMapping.channels[i].hasOwnProperty('randomize')) {
            SONG.effectMapping.channels[i].randomize();
          }
        }

        for(var i = 0; i < SONG.effectMapping.globals.length; i++) {
          if(SONG.effectMapping.globals[i] && SONG.effectMapping.globals[i].hasOwnProperty('randomize')) {
            SONG.effectMapping.globals[i].randomize();
          }
        }
      }

      //return false;

    }

    loop();

  }

}

////////////////////////////////
// MAIN LOOP
////////////////////////////////

function loop() {

  requestAnimationFrame(loop);

  //pause midi if mouse has been idle and there have been notes recent enough

  if(MIDI.Player.playing && !INPUT.mousedown && (Date.now() - INPUT.last) > (60000 / MIDI.Player.BPM) && NOTE.last > (INPUT.last + (60000 / MIDI.Player.BPM))) {
    MIDI.Player.pause();
  }

  //simulate click track events (32nd notes in 4/4)
  if(MIDI.Player.playing && Date.now() > NOTE.next) {
    NOTE.next = Date.now() + (60000 / (MIDI.Player.BPM * 8));

    for(var i in SONG.effectMapping.channels) {
      if(SONG.effectMapping.channels[i] && SONG.effectMapping.channels[i].hasOwnProperty('click')) {
        SONG.effectMapping.channels[i].click();
      }
    }

    for(var i = 0; i < SONG.effectMapping.globals.length; i++) {
      if(SONG.effectMapping.globals[i] && SONG.effectMapping.globals[i].hasOwnProperty('click')) {
        SONG.effectMapping.globals[i].click();
      }
    }
  }

  //dispatch tick events
  for(var i in SONG.effectMapping.channels) {
    if(SONG.effectMapping.channels[i] && SONG.effectMapping.channels[i].hasOwnProperty('tick')) {
      SONG.effectMapping.channels[i].tick();
    }
  }

  for(var i = 0; i < SONG.effectMapping.globals.length; i++) {
    if(SONG.effectMapping.globals[i] && SONG.effectMapping.globals[i].hasOwnProperty('tick')) {
      SONG.effectMapping.globals[i].tick();
    }
  }

  //render

  RENDERER.render(SCENE, CAMERA);

  //fps

  if(FPS.show && Date.now() - FPS.last > 1000) {
    console.log(FPS.count);
    FPS.count = 0;
    FPS.last = Date.now();
  } else if(FPS.show) {
    FPS.count++;
  }

}
<commit_msg>Theme cyclying<commit_after>var USE_FULL_SOUNDFONT_LIBRARY = true, //set this variable to true after downloading https://github.com/gleitz/midi-js-soundfonts and placing in soundfont directory

  FPS = {show: false, last: Date.now(), count: 0},
  NOTE = {last: Date.now(), next: Date.now()},
  INPUT = {last: Date.now(), e: null, x: null, y: null, mousedown: false, cursor: null},
  EFFECTS = {},
  SONG, THEME, THEMEPTR, SCENE, CAMERA, RENDERER;

////////////////////////////////
// INIT
////////////////////////////////

window.onload = function() {

  //init three.js

  SCENE = new THREE.Scene();

  CAMERA = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
  CAMERA.position.z = 600;

  RENDERER = new THREE.WebGLRenderer();
  RENDERER.setSize(window.innerWidth, window.innerHeight);

  document.body.appendChild(RENDERER.domElement);

  //setup cursor

  var c_mat = new THREE.MeshBasicMaterial({color: 0xdddddd});
  var c_geo = new THREE.CircleGeometry(1, 24);
  INPUT.cursor = new THREE.Mesh(c_geo, c_mat);
  SCENE.add(INPUT.cursor);

  //setup theme, song, and effect mapping

  THEMEPTR = Math.floor(Math.random() * THEMES.length);
  THEME = THEMES[THEMEPTR];

  SONG = SONGS[Math.floor(Math.random() * SONGS.length)];
  SONG = SONGS[6];

  if(!SONG.effectMapping.hasOwnProperty('channels')) SONG.effectMapping.channels = {};
  if(!SONG.effectMapping.hasOwnProperty('globals')) SONG.effectMapping.globals = [];

  for(var i = 0; i < SONG.effectMapping.globals.length; i++) {
    if(EFFECTS.hasOwnProperty(SONG.effectMapping.globals[i])) {
      SONG.effectMapping.globals[i] = EFFECTS[SONG.effectMapping.globals[i]];
      if(SONG.effectMapping.globals[i].hasOwnProperty('setup')) SONG.effectMapping.globals[i].setup();
    }
  }

  for(var i in SONG.effectMapping.channels) {
    if(EFFECTS.hasOwnProperty(SONG.effectMapping.channels[i])) {
      SONG.effectMapping.channels[i] = EFFECTS[SONG.effectMapping.channels[i]];
      if(SONG.effectMapping.channels[i].hasOwnProperty('setup')) SONG.effectMapping.channels[i].setup();
    }
  }

  //init MIDI.js

  if(SONG.hasOwnProperty('bpm')) MIDI.Player.BPM = SONG.bpm;

  MIDI.loadPlugin({
    soundfontUrl: "soundfont/",
    onsuccess: function() {
      MIDI.Player.loadFile(SONG.path, function() {

        //seek?
        if(SONG.hasOwnProperty('wadsworth')) MIDI.Player.currentTime = SONG.wadsworth * 1000;

        //if we are using the full soundfont library, load the instruments needed for this song

        if(USE_FULL_SOUNDFONT_LIBRARY) {
          var instruments = MIDI.Player.getFileInstruments();
          var instrumentsToLoad = instruments.length;
          for(var i = 0; i < instruments.length; i++) {
            var channel = i;
            MIDI.loadResource({
              instrument: instruments[i],
              onsuccess: function(c) {
                MIDI.programChange(c, MIDI.GM.byName[instruments[c]].number);
                instrumentsToLoad--;
                if(instrumentsToLoad == 0) appReady();
              } (channel)
            });
          }
        }

        else appReady();

      });
    }
  });

  //init user/midi input and run the animation after file (and possibly all instruments) load

  function appReady() {

    MIDI.Player.addListener(function(e) {
      NOTE.last = Date.now();

      var eMap = SONG.effectMapping.channels;
      if(e.hasOwnProperty('channel') && eMap[e.channel]) {
        if(e.message == 144 && eMap[e.channel].hasOwnProperty('spawn')) {
          eMap[e.channel].spawn(e);
        } else if(e.message == 128 && eMap[e.channel].hasOwnProperty('despawn')) {
          eMap[e.channel].despawn(e);
        }
      }

      for(var i = 0; i < SONG.effectMapping.globals.length; i++) {
        if(e.message == 144 && SONG.effectMapping.globals[i].hasOwnProperty('spawn')) {
          SONG.effectMapping.globals[i].spawn(e);
        } else if(e.message == 128 && SONG.effectMapping.globals[i].hasOwnProperty('despawn')) {
          SONG.effectMapping.globals[i].despawn(e);
        }
      }
    });

    function inputEvent(e) {
      INPUT.x = ((e.clientX / window.innerWidth) - 0.5) * window.innerWidth;
      INPUT.y = ((e.clientY / window.innerHeight) - 0.5) * -window.innerHeight;
      INPUT.cursor.position.x = INPUT.x;
      INPUT.cursor.position.y = INPUT.y;
      INPUT.e = e;
      INPUT.last = Date.now();

      if(!MIDI.Player.playing) {
        MIDI.Player.resume();
      }

      for(var i in SONG.effectMapping.channels) {
        if(SONG.effectMapping.channels[i] && SONG.effectMapping.channels[i].hasOwnProperty('input')) {
          SONG.effectMapping.channels[i].input();
        }
      }

      for(var i = 0; i < SONG.effectMapping.globals.length; i++) {
        if(SONG.effectMapping.globals[i] && SONG.effectMapping.globals[i].hasOwnProperty('input')) {
          SONG.effectMapping.globals[i].input();
        }
      }
    }

    window.onmousemove = inputEvent;

    window.onmousedown = function(e) {
      INPUT.mousedown = true;
      inputEvent(e);
    }

    window.onmouseup = function(e) {
      INPUT.mousedown = false;
    }

    window.ontouchmove = function(e) {
      e.clientX = e.touches[0].clientX;
      e.clientY = e.touches[0].clientY;
      inputEvent(e);
    }

    window.onkeypress = function(e) {
      e.clientX = Math.floor(Math.random() * window.innerWidth);
      e.clientY = Math.floor(Math.random() * window.innerHeight);
      inputEvent(e);

      if(e.which == 32) {
        //change theme
        THEME = THEMES[THEMEPTR++ % THEMES.length];

        //dispatch randomize events
        for(var i in SONG.effectMapping.channels) {
          if(SONG.effectMapping.channels[i] && SONG.effectMapping.channels[i].hasOwnProperty('randomize')) {
            SONG.effectMapping.channels[i].randomize();
          }
        }

        for(var i = 0; i < SONG.effectMapping.globals.length; i++) {
          if(SONG.effectMapping.globals[i] && SONG.effectMapping.globals[i].hasOwnProperty('randomize')) {
            SONG.effectMapping.globals[i].randomize();
          }
        }
      }

      //return false;

    }

    loop();

  }

}

////////////////////////////////
// MAIN LOOP
////////////////////////////////

function loop() {

  requestAnimationFrame(loop);

  //pause midi if mouse has been idle and there have been notes recent enough

  if(MIDI.Player.playing && !INPUT.mousedown && (Date.now() - INPUT.last) > (60000 / MIDI.Player.BPM) && NOTE.last > (INPUT.last + (60000 / MIDI.Player.BPM))) {
    MIDI.Player.pause();
  }

  //simulate click track events (32nd notes in 4/4)
  if(MIDI.Player.playing && Date.now() > NOTE.next) {
    NOTE.next = Date.now() + (60000 / (MIDI.Player.BPM * 8));

    for(var i in SONG.effectMapping.channels) {
      if(SONG.effectMapping.channels[i] && SONG.effectMapping.channels[i].hasOwnProperty('click')) {
        SONG.effectMapping.channels[i].click();
      }
    }

    for(var i = 0; i < SONG.effectMapping.globals.length; i++) {
      if(SONG.effectMapping.globals[i] && SONG.effectMapping.globals[i].hasOwnProperty('click')) {
        SONG.effectMapping.globals[i].click();
      }
    }
  }

  //dispatch tick events
  for(var i in SONG.effectMapping.channels) {
    if(SONG.effectMapping.channels[i] && SONG.effectMapping.channels[i].hasOwnProperty('tick')) {
      SONG.effectMapping.channels[i].tick();
    }
  }

  for(var i = 0; i < SONG.effectMapping.globals.length; i++) {
    if(SONG.effectMapping.globals[i] && SONG.effectMapping.globals[i].hasOwnProperty('tick')) {
      SONG.effectMapping.globals[i].tick();
    }
  }

  //render

  RENDERER.render(SCENE, CAMERA);

  //fps

  if(FPS.show && Date.now() - FPS.last > 1000) {
    console.log(FPS.count);
    FPS.count = 0;
    FPS.last = Date.now();
  } else if(FPS.show) {
    FPS.count++;
  }

}
<|endoftext|>


<commit_before>function notify (message, type, time) {
    var $element = $('

');

    $element.append(message);

    if (type) {
        $element.addClass(type);
    }

    $('body').append($element);

    setTimeout(function() {
        $element.fadeOut(function() { $element.remove(); });
    }, time || 5000);
}

var socket   = io('http://nantes.nekland.fr:8888'),
    gameData = {
        idents: {
            pseudo:   null,
            email:    null,
            gravatar: null
        }
    };

socket.on('game.players', function (data) {
    gameData.players = data.players;
});

$(document).ready(function () {

    $('#login-form').submit(function (e) {
        e.preventDefault();

        var $pseudo = $('#pseudo'),
            pseudo  = $pseudo.val(),
            $email  = $('#email'),
            email   = $email.val()
        ;

        if (pseudo.trim().length === 0 && gameData.players.indexOf(pseudo) !== '-1') {
            notify('Pseudo invalide.', 'error');
            return;
        }

        if (email.trim().length === 0) {
            if (!confirm('Attention, vous n\'avez pas précisé votre adresse email, vous n\'aurez pas d\'avatar. Voulez vous continuer ?')) {
                return;
            }
        }

        launchApp(pseudo, email);

        return false;
    });
});

function launchApp (pseudo, email) {

    gameData.idents.pseudo   = pseudo;
    gameData.idents.email    = email;
    gameData.idents.gravatar = 'http://www.gravatar.com/avatar/' + md5(email) + '.jpg?s=' + '80&d=' + encodeURI('http://file.nekland.fr/dev/avatar_normal.png');

    var $login = $('#login');
    $login.addClass('closed');
    setTimeout(function () { $login.remove(); }, 1500);

    var chat = new ChatApp($('#message-box input'), $('#messages-list'));

    socket.on('disconnect', function () { alert('Une erreur s\'est produite sur le serveur, tu dois recharger ta page, désolé !'); });
    socket.emit('game.connection', { pseudo: pseudo, email: email, avatar: gameData.idents.gravatar });

    // Lorsqu'un message doit être affiché
    socket.on('message', function(data) {

        // Le type du message peut être
        //   - info
        //   - error
        var messageType    = data.type,
            messageContent = data.content;

        // ça serait certainement mieux de l'ajouter dans le dom avec une box, un truc comme as
        notify(messageContent, messageType);
    });

    new GameApp($('#game'));
}

var ChatApp = function ($input, $messages) {
    this.$input    = $input;
    this.$messages = $messages;
    var self       = this;

    $input.bind('keydown', function (e) {
        if (e.which === 13) {
            var message = { pseudo: gameData.idents.pseudo, message: $input.val() };

            if (message.message !== '') {
                socket.emit('chat.message', message);
                this.addMessage(message);
                this.$input.val('');
            }
        }

        e.stopPropagation();
    }.bind(this));

    socket.on('chat.message', function (data) {
        self.addMessage(data);
    });

    socket.on('chat.lastMessages', function (data) {
        $.each(data.messages, function (index, value) {
            self.addMessage(value);
        });
    });

    this.addMessage = function (message) {
        this.$messages.append('
<' + message.pseudo + '> ' + message.message + '
');
        this.$messages.animate({
            scrollTop: this.$messages.prop("scrollHeight") - this.$messages.height()
        }, 100);
    };
};

var GameApp = function ($game) {
    this.$game     = $game;
    this.$buttons  = $game.find('#buttons');
    this.$letters  = $game.find('#letters');
    this.$me       = null;
    this.templates = {
        player: '\

\
        \

\

_
\

',
        letters: '
Trouvez un mot composé de ces lettres:

'
    };

    this.timeout      = null;
    this.timeoutRound = null;
    this.clock        = 0;
    this.clockRound   = 0;
    this.places       = [
        'pos7',
        'pos3',
        'pos8',
        'pos5',
        'pos1',
        'pos4',
        'pos6',
        'pos2'
    ];
    this.currentPlayer = null;
    this.players       = [];
    this.avatars       = [];

    /**
     * When the user click on a button, the server will start accepting
     * new guys in the game
     *
     * Cette méthode est exécutée lorsque l'utilisateur clique sur le bouton pour
     * démarrer une partie
     */
    this.emitStart = function () {
        socket.emit('game.start', {});
    };

    /**
     * React to the socket that tell a game is started
     *
     * Cette méthode réagit au socket qui est envoyé par le serveur
     * pour démarrer le jeu
     */
    this.start = function () {
        this.$buttons.html('<button>Rejoindre la partie</button>');
        this.$buttons.find('button').click(this.addMe.bind(this));
    };

    /**
     * Cette méthode demande au serveur pour jouer dans la partie
     * qui vient de démarrer
     */
    this.addMe = function() {
        socket.emit('game.iWantToPlay', {});
        this.$buttons.html('
En attente d\'autres joueurs...
');
    };

    /**
     * Is executed after people are registered in a game
     *
     * Cette méthode est exécutée lorsque le compteur de temps permettant
     * de rejoindre la partie est arrivé à expiration
     */
    this.realStart = function (data) {
        this.$buttons.html('');
        this.players = data.players;
        this.avatars = data.avatars;
        this.showPlayers();
    };

    this.showPlayers = function () {
        $.each(this.players, function (i, value) {
            this.addPlayer(value, i);
        }.bind(this));
    };

    this.addPlayer = function (player, position) {
        var $template = $(this.templates.player);
        $template.addClass(this.places[position]);
        $template.find('.nickname').html(player);
        $template.find('img').attr('src', this.avatars[position]);

        if (player === gameData.idents.pseudo) {

            this.$me = $template;
        }

        this.$game.append($template);
    };

    /**
     * Cette méthode est appelée lorsqu'un joueur a perdu et qu'on démarre un nouveau tour
     */
    this.newRound = function (data) {
        this.turn(data);
    };

    /**
     * Chaque fois que quelqu'un trouve la bonne réponse
     * cette méthode est appelée pour passer à la personne suivante
     */
    this.turn = function (data) {
        this.currentPlayer = data.player;
        this.$letters.html(this.templates.letters);
        this.$letters.find('.big').html(data.letters);
        this.$game.find('.word .text').html('');

        // Retire la classe inactive
        // Au joueur qui joue
        this.$game
            .find('.player:not(.inactive)')
            .addClass('inactive');
        this.getCurrentPlayerDom()
            .removeClass('inactive');

        if (this.isMyTurn()) {
            this.$buttons.html('
Appuyez sur entrée pour valider
');
        } else {
            this.$buttons.html('');
        }
    };

    this.isMyTurn = function () {
        return this.currentPlayer == gameData.idents.pseudo;
    };

    this.getCurrentPlayerDom = function () {
        return this.$game.find('.player.'+this.places[this.players.indexOf(this.currentPlayer)]);
    };

    this.onKeyPressed = function (e) {
        if (e.which === 8) {
            e.preventDefault();
        }

        if (this.isMyTurn()) {
            var $text = this.$me.find('.text');

            if (e.which === 13) {
                socket.emit('game.answer', { answer: $text.html() });
            } else if (e.which === 8) {
                var text = $text.html();
                $text.html(text.substring(0, text.length-1));
            } else {
                this.$me.removeClass('fail');
                $text.html($text.html() + String.fromCharCode(e.which));
            }

            socket.emit('game.type', { word: $text.html() });
        }
    };

    this.end = function() {
        this.$game.find('.player').remove();
        this.$buttons.html('<button>Lancer une nouvelle partie</button>');
        this.$buttons.find('button').click(this.emitStart.bind(this));
        this.$letters.html('');
    };

    this.winner = function (data) {
        notify(data.pseudo + ' a remporté la partie :) ');
        this.end();
    };

    this.tryAgain = function () {
        this.$me.addClass('fail');
    };

    this.showGame = function (data) {
        this.$buttons.html('
Une partie est en cours merci de patienter :)
');
        this.players = data.players;
        this.showPlayers();
    };

    this.currentPlayerTypes = function (data) {
        this.getCurrentPlayerDom().find('.text').html(data.word);
    };

    socket.on('game.start', this.start.bind(this));
    socket.on('game.realStart', this.realStart.bind(this));
    socket.on('game.cantStart', this.end.bind(this));
    socket.on('game.round', this.newRound.bind(this));
    socket.on('game.turn', this.turn.bind(this));
    socket.on('game.winner', this.winner.bind(this));
    socket.on('game.tryAgain', this.tryAgain.bind(this));
    socket.on('game.inProgress', this.showGame.bind(this));
    socket.on('game.type', this.currentPlayerTypes.bind(this));

    $(document).unbind('keydown').bind('keydown', this.onKeyPressed.bind(this));

    this.end();
};<commit_msg>Fixed bug for letters<commit_after>function notify (message, type, time) {
    var $element = $('

');

    $element.append(message);

    if (type) {
        $element.addClass(type);
    }

    $('body').append($element);

    setTimeout(function() {
        $element.fadeOut(function() { $element.remove(); });
    }, time || 5000);
}

var socket   = io('http://nantes.nekland.fr:8888'),
    gameData = {
        idents: {
            pseudo:   null,
            email:    null,
            gravatar: null
        }
    };

socket.on('game.players', function (data) {
    gameData.players = data.players;
});

$(document).ready(function () {

    $('#login-form').submit(function (e) {
        e.preventDefault();

        var $pseudo = $('#pseudo'),
            pseudo  = $pseudo.val(),
            $email  = $('#email'),
            email   = $email.val()
        ;

        if (pseudo.trim().length === 0 && gameData.players.indexOf(pseudo) !== '-1') {
            notify('Pseudo invalide.', 'error');
            return;
        }

        if (email.trim().length === 0) {
            if (!confirm('Attention, vous n\'avez pas précisé votre adresse email, vous n\'aurez pas d\'avatar. Voulez vous continuer ?')) {
                return;
            }
        }

        launchApp(pseudo, email);

        return false;
    });
});

function launchApp (pseudo, email) {

    gameData.idents.pseudo   = pseudo;
    gameData.idents.email    = email;
    gameData.idents.gravatar = 'http://www.gravatar.com/avatar/' + md5(email) + '.jpg?s=' + '80&d=' + encodeURI('http://file.nekland.fr/dev/avatar_normal.png');

    var $login = $('#login');
    $login.addClass('closed');
    setTimeout(function () { $login.remove(); }, 1500);

    var chat = new ChatApp($('#message-box input'), $('#messages-list'));

    socket.on('disconnect', function () { alert('Une erreur s\'est produite sur le serveur, tu dois recharger ta page, désolé !'); });
    socket.emit('game.connection', { pseudo: pseudo, email: email, avatar: gameData.idents.gravatar });

    // Lorsqu'un message doit être affiché
    socket.on('message', function(data) {

        // Le type du message peut être
        //   - info
        //   - error
        var messageType    = data.type,
            messageContent = data.content;

        // ça serait certainement mieux de l'ajouter dans le dom avec une box, un truc comme as
        notify(messageContent, messageType);
    });

    new GameApp($('#game'));
}

var ChatApp = function ($input, $messages) {
    this.$input    = $input;
    this.$messages = $messages;
    var self       = this;

    $input.bind('keydown', function (e) {
        if (e.which === 13) {
            var message = { pseudo: gameData.idents.pseudo, message: $input.val() };

            if (message.message !== '') {
                socket.emit('chat.message', message);
                this.addMessage(message);
                this.$input.val('');
            }
        }

        e.stopPropagation();
    }.bind(this));

    socket.on('chat.message', function (data) {
        self.addMessage(data);
    });

    socket.on('chat.lastMessages', function (data) {
        $.each(data.messages, function (index, value) {
            self.addMessage(value);
        });
    });

    this.addMessage = function (message) {
        this.$messages.append('
<' + message.pseudo + '> ' + message.message + '
');
        this.$messages.animate({
            scrollTop: this.$messages.prop("scrollHeight") - this.$messages.height()
        }, 100);
    };
};

var GameApp = function ($game) {
    this.$game     = $game;
    this.$buttons  = $game.find('#buttons');
    this.$letters  = $game.find('#letters');
    this.$me       = null;
    this.templates = {
        player: '\

\
        \

\

_
\

',
        letters: '
Trouvez un mot composé de ces lettres:

'
    };

    this.timeout      = null;
    this.timeoutRound = null;
    this.clock        = 0;
    this.clockRound   = 0;
    this.places       = [
        'pos7',
        'pos3',
        'pos8',
        'pos5',
        'pos1',
        'pos4',
        'pos6',
        'pos2'
    ];
    this.currentPlayer = null;
    this.players       = [];
    this.avatars       = [];

    /**
     * When the user click on a button, the server will start accepting
     * new guys in the game
     *
     * Cette méthode est exécutée lorsque l'utilisateur clique sur le bouton pour
     * démarrer une partie
     */
    this.emitStart = function () {
        socket.emit('game.start', {});
    };

    /**
     * React to the socket that tell a game is started
     *
     * Cette méthode réagit au socket qui est envoyé par le serveur
     * pour démarrer le jeu
     */
    this.start = function () {
        this.$buttons.html('<button>Rejoindre la partie</button>');
        this.$buttons.find('button').click(this.addMe.bind(this));
    };

    /**
     * Cette méthode demande au serveur pour jouer dans la partie
     * qui vient de démarrer
     */
    this.addMe = function() {
        socket.emit('game.iWantToPlay', {});
        this.$buttons.html('
En attente d\'autres joueurs...
');
    };

    /**
     * Is executed after people are registered in a game
     *
     * Cette méthode est exécutée lorsque le compteur de temps permettant
     * de rejoindre la partie est arrivé à expiration
     */
    this.realStart = function (data) {
        this.$buttons.html('');
        this.players = data.players;
        this.avatars = data.avatars;
        this.showPlayers();
    };

    this.showPlayers = function () {
        $.each(this.players, function (i, value) {
            this.addPlayer(value, i);
        }.bind(this));
    };

    this.addPlayer = function (player, position) {
        var $template = $(this.templates.player);
        $template.addClass(this.places[position]);
        $template.find('.nickname').html(player);
        $template.find('img').attr('src', this.avatars[position]);

        if (player === gameData.idents.pseudo) {

            this.$me = $template;
        }

        this.$game.append($template);
    };

    /**
     * Cette méthode est appelée lorsqu'un joueur a perdu et qu'on démarre un nouveau tour
     */
    this.newRound = function (data) {
        this.turn(data);
    };

    /**
     * Chaque fois que quelqu'un trouve la bonne réponse
     * cette méthode est appelée pour passer à la personne suivante
     */
    this.turn = function (data) {
        this.currentPlayer = data.player;
        this.$letters.html(this.templates.letters);
        this.$letters.find('.big').html(data.letters);
        this.$game.find('.word .text').html('');

        // Retire la classe inactive
        // Au joueur qui joue
        this.$game
            .find('.player:not(.inactive)')
            .addClass('inactive');
        this.getCurrentPlayerDom()
            .removeClass('inactive');

        if (this.isMyTurn()) {
            this.$buttons.html('
Appuyez sur entrée pour valider
');
        } else {
            this.$buttons.html('');
        }
    };

    this.isMyTurn = function () {
        return this.currentPlayer == gameData.idents.pseudo;
    };

    this.getCurrentPlayerDom = function () {
        return this.$game.find('.player.'+this.places[this.players.indexOf(this.currentPlayer)]);
    };

    this.onKeyPressed = function (e) {
        if (e.which === 8) {
            e.preventDefault();
        }

        if (this.isMyTurn()) {
            var $text = this.$me.find('.text');

            if (e.which === 13) {
                socket.emit('game.answer', { answer: $text.html() });
            } else if (e.which === 8) {
                var text = $text.html();
                $text.html(text.substring(0, text.length-1));
            } else {
                this.$me.removeClass('fail');
                var letter = String.fromCharCode(e.which);

                if (letterExists(letter)) {
                    $text.html($text.html() + letter);
                }
            }

            socket.emit('game.type', { word: $text.html() });
        }
    };

    this.end = function() {
        this.$game.find('.player').remove();
        this.$buttons.html('<button>Lancer une nouvelle partie</button>');
        this.$buttons.find('button').click(this.emitStart.bind(this));
        this.$letters.html('');
    };

    this.winner = function (data) {
        notify(data.pseudo + ' a remporté la partie :) ');
        this.end();
    };

    this.tryAgain = function () {
        this.$me.addClass('fail');
    };

    this.showGame = function (data) {
        this.$buttons.html('
Une partie est en cours merci de patienter :)
');
        this.players = data.players;
        this.showPlayers();
    };

    this.currentPlayerTypes = function (data) {
        this.getCurrentPlayerDom().find('.text').html(data.word);
    };

    function letterExists(letter) {
        var alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';

        if(alphabet.indexOf(letter) > -1) {
            return true;
        }

        return false;
    }

    socket.on('game.start', this.start.bind(this));
    socket.on('game.realStart', this.realStart.bind(this));
    socket.on('game.cantStart', this.end.bind(this));
    socket.on('game.round', this.newRound.bind(this));
    socket.on('game.turn', this.turn.bind(this));
    socket.on('game.winner', this.winner.bind(this));
    socket.on('game.tryAgain', this.tryAgain.bind(this));
    socket.on('game.inProgress', this.showGame.bind(this));
    socket.on('game.type', this.currentPlayerTypes.bind(this));

    $(document).unbind('keydown').bind('keydown', this.onKeyPressed.bind(this));

    this.end();
};<|endoftext|>


<commit_before>// Setting up the token
$.jribbble.setToken('eb2f71409041cec665c16eff0e8ae1af05cf3ac2d833682d3c67f08de7f53d8a');

$.jribbble.users('RikkeGantzel').shots({per_page: 36}).then(function(shots) {
  var html = [];

  shots.forEach(function(shot) {
    html.push('
');
    html.push('');
    html.push('');
    html.push('
');
  });

  $('.shots').html(html.join(''));
});<commit_msg>Performance optimization using srcset attribute: requesting double size images for Retina displays, and ordinary size images non-Retina.<commit_after>// Setting up the token
$.jribbble.setToken('eb2f71409041cec665c16eff0e8ae1af05cf3ac2d833682d3c67f08de7f53d8a');

$.jribbble.users('RikkeGantzel').shots({per_page: 36}).then(function(shots) {
  var html = [];

  shots.forEach(function(shot) {
    html.push('
');
    html.push('');
    html.push('');
    html.push('
');
  });

  $('.shots').html(html.join(''));
});<|endoftext|>


<commit_before>/* Global variables */
var last_sms_id = -1;
var httpServer = new HTTPServer(8080);

/* Logging the result from messages */
function logMsg(msg){
	var r = "";
	['type', 'id', 'threadId', 'body', 'delivery', 'deliveryStatus', 'read', 'receiver', 'sender', 'timestamp', 'messageClass'].forEach(function (key){
		r += '
 ' + key + ': ' + msg[key];
	});
	console.log(r);
}

/* TODO: May have a deprecated call */
function update_loc(){
	$('[data-l10n-id]').each(function(index){
		$(this).html(navigator.mozL10n.get($(this).attr('data-l10n-id')));
	});
}

/* Functions to stop and start the server from the app */
function fox_server_stop(httpServer, sstatus){
	console.log('Clicked on stop');
  	httpServer.stop();
	sstatus.textContent = navigator.mozL10n.get('stopped');
}
function fox_server_start(httpServer, sstatus){
	console.log('Clicked on start');
  	httpServer.start();
	sstatus.textContent = navigator.mozL10n.get('running');
}

/* Loading the page */
function load_page(requested_page){
	console.log('Loading page ' + requested_page);

	$("#main-container").load("../content/" + requested_page + "_content.html", function(){
		console.log('Loading HTML performed!');
		update_loc();

		if (requested_page == "server"){
			/* Getting the elements */
			var sstatus = document.getElementById('server-status');
			var ip     = document.getElementById('ip-address');
			var port   = document.getElementById('listening-port');
			var start_b  = document.getElementById('start-server');
			var stop_b   = document.getElementById('stop-server');

			/* Displaying */
			IPUtils.getAddresses(function(ipAddress) {
				ip.textContent = ip.textContent || ipAddress;
			});

			port.textContent = httpServer.port;

			if (httpServer.running){
				sstatus.textContent = navigator.mozL10n.get('running');
			} else {
				sstatus.textContent = navigator.mozL10n.get('stopped');
			}

			/* Adding listeners in the buttons */
			start_b.addEventListener('click', function() {
				fox_server_start(httpServer, sstatus);
			});

			stop_b.addEventListener('click', function() {
				fox_server_stop(httpServer, sstatus);
			});

			$('#testing-server').on('click', function(e){
				console.log('Clicked on testing');

				e.preventDefault();
				var activity = new MozActivity({
					name: "view",
					data: {
						type: "url",
						url: 'http://' + ip.textContent + ':' + port.textContent
					}
				});
			});
		} else if (requested_page == "settings"){
			/* Initializing the selects */
			$('select').material_select();

			/* Modifying the app language */
			$("#select-language").change(function() {
				var l = $("#select-language").val();
				console.log('New selected language: ' + l);
				navigator.mozL10n.language.code = l;
			});
		} else if (requested_page == "index"){
			last_sms_id = -1;

			/* Settings the behavior on click : sending SMS */
			$('#sms-submit').on("click", function (ev){
				console.log('Submitting SMS form...');

				/* Creating the response div, if not existing */
				var resp = document.getElementById('response');
				if (resp == null) {
					$("#main-container").append('

');
				}

				$("#response").html(navigator.mozL10n.get('submitting_sms') + '...');

				var msg = document.getElementById('message').value;
				var phone = document.getElementById('contacts').value;
				console.log('Submitted message : ' + msg + ' Phone nb: ' + phone);

				var request;
				request = navigator.mozMobileMessage.send(phone, msg);

				/* When the message was successfully sent */
				request.onsuccess = function (){
					window.thing = this;
					console.log(this.result);
					console.log('Sent to: ' + this.result);
					last_sms_id = this.result['id'];
					logMsg(this.result);
					$("#response").html('' + navigator.mozL10n.get('successfully_sent') + ' ✓
');

					/* Check if the last sms was well delivered (receipt) */
					var checking_last_sms = window.setInterval(function(){
						if (last_sms_id != -1){
							var request = navigator.mozMobileMessage.getMessage(last_sms_id);
							request.onsuccess = function (){
								window.thing = this;
								console.error(this.result);

								if (this.result['deliveryStatus'] == 'success'){
									clearInterval(checking_last_sms);
									$("#response").append('' + navigator.mozL10n.get('successfully_received') + ' ✓');
								}

								logMsg(this.result);
							}

							request.onerror = function (){
								$("#response").html('Couldn\'t retrieve last sent SMS...');
								clearInterval(checking_last_sms);
							}
						}
					}, 5000);
				};

				/* When the message wasn't sent correctly */
				request.onerror = function (){
					window.thing = this;
					console.error(this.error.name);
					console.error(this.error.message);
					$("#response").html('' + navigator.mozL10n.get('error_sending_message') + ' ✗');
					$("#response").append('' + this.error.name + ':' + this.error.message + '');
				};
			});

			var allContacts = navigator.mozContacts.getAll();

			allContacts.onsuccess = function(event) {
				var cursor = event.target;
				var gn, fn, tl;
				if (cursor.result) {
					gn = (cursor.result.givenName == null) ? "" : cursor.result.givenName[0]
					fn = (cursor.result.familyName == null) ? "" : cursor.result.familyName[0]
					tl = (cursor.result.tel == null) ? "" : cursor.result.tel[0].value
					console.log('Found one contact... Given name : ' + gn + ', Family name : ' + fn + ', Tel : ' + tl);

					/* Append new contact to the select */
					$('#contacts').append('<option value="' + tl + '">' + gn + ' ' + fn + '</option>');

					/* Go to the next contact */
					cursor.continue();
				} else {
					console.log('No more contacts, creating the Materialize select...');
					/* Once the contacts are all retrieved, we create the Materialize select */
					$('select').material_select();
				}
			};

			allContacts.onerror = function() {
				console.warn('Something went terribly wrong while retrieving the contacts!');
			};
		}
	});
}

/* DOMContentLoaded is fired once the document has been loaded and parsed,
but without waiting for other external resources to load (css/images/etc)
That makes the app more responsive and perceived as faster.
https://developer.mozilla.org/Web/Reference/Events/DOMContentLoaded */
window.addEventListener('DOMContentLoaded', function() {

	/* We'll ask the browser to use strict code to help us catch errors earlier.
	https://developer.mozilla.org/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode */
	'use strict';

	/* Adding listener to the server (when the server is getting a request) */
	httpServer.addEventListener('request', function(evt) {
		var request  = evt.request;
		var response = evt.response;

		console.log(request);

		var paramsString = JSON.stringify(request.params, null, 2);
		var bodyString   = JSON.stringify(request.body, null, 2);

		var firstName = (request.body && request.body.first_name) || '';
		var lastName  = (request.body && request.body.last_name)  || '';

		var hello_world_content = '<!DOCTYPE html><title>Firefox OS Web Server</title>
Hello World!

If you can read this, the Firefox OS Web Server is operational!

The path you requested is: ' + request.path + '

URL Parameters:

' + paramsString + '

POST Data:

' + bodyString + '

Sample Form
<form method="POST" action=".">
First Name:<input type="text" name="first_name" value="' + firstName + '">

Last Name:<input type="text" name="last_name" value="' + lastName + '">
<input type="submit" value="Submit"></form>';
		var send_content = '<!DOCTYPE html><title>SMSFox Server</title>
Send a message through your phone
<form method="POST" action=".">
Phone number:<input type="text" name="first_name" value="">

Message:<input type="text" name="last_name" value="">
<input type="submit" value="Submit"></form>';
		var main_content = '<!DOCTYPE html><title>SMSFox Server</title>Sending SMSStart serverStop server';

		if (request.path === '/image.jpg') {
		    response.headers['Content-Type'] = 'image/png';
		    response.sendFile('../img/icons/fox128x128.png');
		    return;
		} else if (request.path === '/send/') {
			response.send(send_content);
			return;
		} else {
			response.send(main_content);
			return;
		}
	});

	/* Loading the side nav */
	var e = document.getElementById('nav-slide');
	if (e != null){
		console.log('Successfully retrieved nav-slide');
		$("#nav-slide").load('../slide.html', function() {
			$('.button-collapse').sideNav({
				menuWidth: 200, /* Default is 240 */
				edge: 'left', /* Choose the horizontal origin */
				closeOnClick: true /* Closes side-nav on  clicks, useful for Angular/Meteor */
			});

			$('#home').on("click", function(ev){
				console.log("Clicked home");
				load_page("index");
			});
			$('#objects').on("click", function(ev){
				console.log("Clicked objects");
				Materialize.toast('Work in progress', 4000);
			});
			$('#server').on("click", function(ev){
				console.log("Clicked server");
				load_page("server");
			});
			$('#settings').on("click", function(ev){
				console.log("Clicked settings");
				load_page("settings");
			});
			$('#about').on("click", function(ev){
				console.log("Clicked about");
				load_page("about");
			});

			load_page("index");

		});
	} else {
		console.log('Error while retrieving nav-slide');
	}

	/* We want to wait until the localisations library has loaded all the strings.
	So we'll tell it to let us know once it's ready. */
	navigator.mozL10n.once(start);

	function start() {
		// var message = document.getElementById('message');
		// message.textContent = translate('message');
		$('select').material_select();
	}

});

/* Stopping the server when unload */
window.addEventListener('beforeunload', function() {
	httpServer.stop();
});

<commit_msg>Factorizing<commit_after>/* Global variables */
var last_sms_id = -1;
var httpServer = new HTTPServer(8080);

/* Logging the result from messages */
function logMsg(msg){
	var r = "";
	['type', 'id', 'threadId', 'body', 'delivery', 'deliveryStatus', 'read', 'receiver', 'sender', 'timestamp', 'messageClass'].forEach(function (key){
		r += '
 ' + key + ': ' + msg[key];
	});
	console.log(r);
}

/* TODO: May have a deprecated call */
function update_loc(){
	$('[data-l10n-id]').each(function(index){
		$(this).html(navigator.mozL10n.get($(this).attr('data-l10n-id')));
	});
}

/* Functions to stop and start the server from the app */
function fox_server_stop(httpServer, sstatus){
	console.log('Clicked on stop');
  	httpServer.stop();
	sstatus.textContent = navigator.mozL10n.get('stopped');
}
function fox_server_start(httpServer, sstatus){
	console.log('Clicked on start');
  	httpServer.start();
	sstatus.textContent = navigator.mozL10n.get('running');
}

function fox_send_sms(msg, phone){
	console.log('Submitting SMS form...');
	console.log('Submitted message : ' + msg + ' Phone nb: ' + phone);

	/* Creating the response div, if not existing */
	var resp = document.getElementById('response');
	if (resp == null) {
		$("#main-container").append('

');
	}

	$("#response").html(navigator.mozL10n.get('submitting_sms') + '...');

	var request;
	request = navigator.mozMobileMessage.send(phone, msg);

	/* When the message was successfully sent */
	request.onsuccess = function (){
		window.thing = this;
		console.log(this.result);
		console.log('Sent to: ' + this.result);
		last_sms_id = this.result['id'];
		logMsg(this.result);
		$("#response").html('' + navigator.mozL10n.get('successfully_sent') + ' ✓
');

		/* Check if the last sms was well delivered (receipt) */
		var checking_last_sms = window.setInterval(function(){
			if (last_sms_id != -1){
				var request = navigator.mozMobileMessage.getMessage(last_sms_id);
				request.onsuccess = function (){
					window.thing = this;
					console.error(this.result);

					if (this.result['deliveryStatus'] == 'success'){
						clearInterval(checking_last_sms);
						$("#response").append('' + navigator.mozL10n.get('successfully_received') + ' ✓');
					}

					logMsg(this.result);
				}

				request.onerror = function (){
					$("#response").html('Couldn\'t retrieve last sent SMS...');
					clearInterval(checking_last_sms);
				}
			}
		}, 5000);
	};

	/* When the message wasn't sent correctly */
	request.onerror = function (){
		window.thing = this;
		console.error(this.error.name);
		console.error(this.error.message);
		$("#response").html('' + navigator.mozL10n.get('error_sending_message') + ' ✗');
		$("#response").append('' + this.error.name + ':' + this.error.message + '');
	};
}

/* Loading the page */
function load_page(requested_page){
	console.log('Loading page ' + requested_page);

	$("#main-container").load("../content/" + requested_page + "_content.html", function(){
		console.log('Loading HTML performed!');
		update_loc();

		if (requested_page == "server"){
			/* Getting the elements */
			var sstatus = document.getElementById('server-status');
			var ip     = document.getElementById('ip-address');
			var port   = document.getElementById('listening-port');
			var start_b  = document.getElementById('start-server');
			var stop_b   = document.getElementById('stop-server');

			/* Displaying */
			IPUtils.getAddresses(function(ipAddress) {
				ip.textContent = ip.textContent || ipAddress;
			});

			port.textContent = httpServer.port;

			if (httpServer.running){
				sstatus.textContent = navigator.mozL10n.get('running');
			} else {
				sstatus.textContent = navigator.mozL10n.get('stopped');
			}

			/* Adding listeners in the buttons */
			start_b.addEventListener('click', function() {
				fox_server_start(httpServer, sstatus);
			});

			stop_b.addEventListener('click', function() {
				fox_server_stop(httpServer, sstatus);
			});

			$('#testing-server').on('click', function(e){
				console.log('Clicked on testing');

				e.preventDefault();
				var activity = new MozActivity({
					name: "view",
					data: {
						type: "url",
						url: 'http://' + ip.textContent + ':' + port.textContent
					}
				});
			});
		} else if (requested_page == "settings"){
			/* Initializing the selects */
			$('select').material_select();

			/* Modifying the app language */
			$("#select-language").change(function() {
				var l = $("#select-language").val();
				console.log('New selected language: ' + l);
				navigator.mozL10n.language.code = l;
			});
		} else if (requested_page == "index"){
			last_sms_id = -1;

			/* Settings the behavior on click : sending SMS */
			$('#sms-submit').on("click", function (ev){
				var msg = document.getElementById('message').value;
				var phone = document.getElementById('contacts').value;
				fox_send_sms(msg, phone);
			});

			var allContacts = navigator.mozContacts.getAll();

			allContacts.onsuccess = function(event) {
				var cursor = event.target;
				var gn, fn, tl;
				if (cursor.result) {
					gn = (cursor.result.givenName == null) ? "" : cursor.result.givenName[0]
					fn = (cursor.result.familyName == null) ? "" : cursor.result.familyName[0]
					tl = (cursor.result.tel == null) ? "" : cursor.result.tel[0].value
					console.log('Found one contact... Given name : ' + gn + ', Family name : ' + fn + ', Tel : ' + tl);

					/* Append new contact to the select */
					$('#contacts').append('<option value="' + tl + '">' + gn + ' ' + fn + '</option>');

					/* Go to the next contact */
					cursor.continue();
				} else {
					console.log('No more contacts, creating the Materialize select...');
					/* Once the contacts are all retrieved, we create the Materialize select */
					$('select').material_select();
				}
			};

			allContacts.onerror = function() {
				console.warn('Something went terribly wrong while retrieving the contacts!');
			};
		}
	});
}

/* DOMContentLoaded is fired once the document has been loaded and parsed,
but without waiting for other external resources to load (css/images/etc)
That makes the app more responsive and perceived as faster.
https://developer.mozilla.org/Web/Reference/Events/DOMContentLoaded */
window.addEventListener('DOMContentLoaded', function() {

	/* We'll ask the browser to use strict code to help us catch errors earlier.
	https://developer.mozilla.org/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode */
	'use strict';

	/* Adding listener to the server (when the server is getting a request) */
	httpServer.addEventListener('request', function(evt) {
		var request  = evt.request;
		var response = evt.response;

		console.log(request);

		var paramsString = JSON.stringify(request.params, null, 2);
		var bodyString   = JSON.stringify(request.body, null, 2);

		var firstName = (request.body && request.body.first_name) || '';
		var lastName  = (request.body && request.body.last_name)  || '';

		var hello_world_content = '<!DOCTYPE html><title>Firefox OS Web Server</title>
Hello World!

If you can read this, the Firefox OS Web Server is operational!

The path you requested is: ' + request.path + '

URL Parameters:

' + paramsString + '

POST Data:

' + bodyString + '

Sample Form
<form method="POST" action=".">
First Name:<input type="text" name="first_name" value="' + firstName + '">

Last Name:<input type="text" name="last_name" value="' + lastName + '">
<input type="submit" value="Submit"></form>';
		var send_content = '<!DOCTYPE html><title>SMSFox Server</title>
Send a message through your phone
<form method="POST" action=".">
Phone number:<input type="text" name="first_name" value="">

Message:<input type="text" name="last_name" value="">
<input type="submit" value="Submit"></form>';
		var main_content = '<!DOCTYPE html><title>SMSFox Server</title>Sending SMSStart serverStop server';

		if (request.path === '/image.jpg') {
		    response.headers['Content-Type'] = 'image/png';
		    response.sendFile('../img/icons/fox128x128.png');
		    return;
		} else if (request.path === '/send/') {
			response.send(send_content);
			return;
		} else {
			response.send(main_content);
			return;
		}
	});

	/* Loading the side nav */
	var e = document.getElementById('nav-slide');
	if (e != null){
		console.log('Successfully retrieved nav-slide');
		$("#nav-slide").load('../slide.html', function() {
			$('.button-collapse').sideNav({
				menuWidth: 200, /* Default is 240 */
				edge: 'left', /* Choose the horizontal origin */
				closeOnClick: true /* Closes side-nav on  clicks, useful for Angular/Meteor */
			});

			$('#home').on("click", function(ev){
				console.log("Clicked home");
				load_page("index");
			});
			$('#objects').on("click", function(ev){
				console.log("Clicked objects");
				Materialize.toast('Work in progress', 4000);
			});
			$('#server').on("click", function(ev){
				console.log("Clicked server");
				load_page("server");
			});
			$('#settings').on("click", function(ev){
				console.log("Clicked settings");
				load_page("settings");
			});
			$('#about').on("click", function(ev){
				console.log("Clicked about");
				load_page("about");
			});

			load_page("index");

		});
	} else {
		console.log('Error while retrieving nav-slide');
	}

	/* We want to wait until the localisations library has loaded all the strings.
	So we'll tell it to let us know once it's ready. */
	navigator.mozL10n.once(start);

	function start() {
		// var message = document.getElementById('message');
		// message.textContent = translate('message');
		$('select').material_select();
	}

});

/* Stopping the server when unload */
window.addEventListener('beforeunload', function() {
	httpServer.stop();
});

<|endoftext|>