<commit_before>/* Dispatch area - Should be eliminate after dispatching */

var markersGroup = new L.LayerGroup();
console.log("\n\n\n\n");
console.log("printining markersGroup");
console.log(markersGroup);
var isDispatching = false;
var isFilterOpen = false;
var placeIcon = L.icon({
	iconUrl: '/static/icons/place_marker.png',
	iconSize: [40, 40],
	iconAnchor: [20, 40],
	popupAnchor: [0,-40]
});

var dispatchingAmbulances = {};
var numberOfDispatchingAmbulances = 0;

var currentAddress;
var currentLocation;
var currentPatients;
var newPatientIndex;

var submitDispatching = function () {

    // submit form
    $('#dispatch-form-collapse').submit();

};

var beginDispatching = function () {

    isDispatching = true;
    var filtersDiv = $('#filtersDiv');
    isFilterOpen = filtersDiv.hasClass('show');
    console.log('Begin dispatching.');

    $('#dispatchBeginButton').hide();
    $('#dispatchSubmitButton').show();
    $('#dispatchCancelButton').show();

    // open filter and available ambulances
    filtersDiv.addClass('show');
    $('#ambulance_status').addClass('show');
    $('#ambulance_AV').addClass('show');

    // Update current location
    updateCurrentLocation(mymap.getCenter());

    // Update current address
    updateCurrentAddress(currentLocation);

    // Clear current currentPatients
    currentPatients = {};
    newPatientIndex = 0;

    // Initialize patient form
    $('#patients').empty();

    // add new patient form entry
    addPatientForm(newPatientIndex);

    // resize size
    resizeMap();

    // center map
    mymap.setView(currentLocation, mymap.getZoom());

}

var endDispatching = function () {

    isDispatching = false;
    dispatchingAmbulances = {};
    console.log('End dispatching.');

    markersGroup.clearLayers();

    $('#dispatchBeginButton').show();
    $('#dispatchSubmitButton').hide();
    $('#dispatchCancelButton').hide();

    // close dispatch panel
    $('#dispatchDiv').removeClass('show');

    if (!isFilterOpen) {
        // close filter panel
        $('#filtersDiv').removeClass('show');
    }

    // invalidate map size
    mymap.invalidateSize();

}

var removeFromDispatchingList = function(ambulance) {

    // delete from dispatching list
    delete dispatchingAmbulances[ambulance.id];
    numberOfDispatchingAmbulances--;

    // show message if last button
    if (numberOfDispatchingAmbulances == 0)
        $('#ambulance-selection-message').show();

}

var addToDispatchingList = function(ambulance) {

    // quick return if null or not dispatching
    if (ambulance == null || !isDispatching)
        return;

    // add ambulance to dispatching list
    console.log('Adding ambulance ' + ambulance.identifier + ' to dispatching list');

    // already in?
    if (ambulance.id in dispatchingAmbulances) {
        console.log('Already in dispatching list, skip');
        return;
    }

    // not available?
    if (ambulance.status != STATUS_AVAILABLE) {
        console.log('Ambulance is not available');
        bsalert('Can only dispatch available ambulances!');
        return;
    }

    // hide message if first button
    if (numberOfDispatchingAmbulances == 0)
        $('#ambulance-selection-message').hide();

    // add ambulance to list of dispatching ambulances
    dispatchingAmbulances[ambulance.id] = ambulance;
    numberOfDispatchingAmbulances++;

    // add button to ambulance dispatch grid
    $('#ambulance-selection').append(
        '<button id="dispatch-button-' + ambulance.id + '"'
        + ' value="' + ambulance.id + '"'
        + ' type="button" class="btn btn-sm '+ ambulance_buttons['AV'] + '"'
        + ' style="margin: 2px 2px;"'
        + ' draggable="true">'
        + ambulance.identifier
        + '</button>'
    );
    $('#dispatch-button-' + ambulance.id)
        .on('dragstart', function (e) {
            // on start of drag, copy information and fade button
            console.log('dragstart');
            this.style.opacity = '0.4';
            e.originalEvent.dataTransfer.setData("text/plain", ambulance.id);
        })
        .on('dragend', function (e) {
            console.log('dragend');
            if (e.originalEvent.dataTransfer.dropEffect == 'none') {
                // Remove button if not dropped back
                removeFromDispatchingList(ambulance);
                // Remove button
                $(this).remove();
            } else {
                // Restore opacity if dropped back in
                this.style.opacity = '1.0';
            }
        });
}

var updateCurrentLocation = function(location) {

    console.log('Setting current location to: ' + location.lat + ', ' + location.lng);

    // set currentLocation
    currentLocation = location;

    // update coordinates on form
    $('#curr-lat').html(currentLocation.lat.toFixed(6));
    $('#curr-lng').html(currentLocation.lng.toFixed(6));

    // remove existing marker
    markersGroup.clearLayers();

    // laydown marker
    var marker = L.marker(location,
        {
            icon: placeIcon,
            draggable: true
        })
        .addTo(markersGroup);
    markersGroup.addTo(mymap);

		mymap.on('dblclick', function(e) {
			console.log("right click at:", e.latlng.lat, e.latlng.lng);
			console.log(e);

			updateCurrentLocation(e.latlng);
			// var popOpt = L.popup().setContent('
Hello world!
This is a nice popup.
');
			// popOpt.openOn(mymap);
			if ($('#update-address').prop('checked'))
					updateCurrentAddress(currentLocation);

			if(e) {
				console.log("***********");
				console.log(e);
				e.stopPropagation();
			}
		})

    // pan to location
    mymap.panTo(location);

    // events
    marker.on('dragend', function(e) {

			console.log("clicked in dblclick");
        updateCurrentLocation(marker.getLatLng());

        // update address?
        if ($('#update-address').prop('checked'))
            updateCurrentAddress(currentLocation);

    })

		// commented out by kaung to test double click
    // marker.on('dragend', function(e) {
		//
    //     // update current location
    //     updateCurrentLocation(marker.getLatLng());
		//
    //     // update address?
    //     if ($('#update-address').prop('checked'))
    //         updateCurrentAddress(currentLocation);
		//
    // })

}

var updateCurrentAddress = function(location) {

    var options = {
        types: 'address',
        limit: 1
    };
    geocoder.reverse(location, options,
        function (results, status) {

        if (status != "success") {
            bsalert("Could not geocode:\nError " + status + ", " + results['error']);
            return;
        }

        // quick return if found nothing
        if (results.length == 0) {
            console.log('Got nothing from geocode');
            return;
        }

        // parse features into current address
        currentAddress = geocoder.parse_feature(results[0]);

        console.log(
            'Setting currentAddress to:'
            + '\nnumber: ' + currentAddress['number']
            + '\nstreet: ' + currentAddress['street']
            + '\nunit: ' + currentAddress['unit']
            + '\nlocation: ' + currentAddress['location']['latitude']
            + ',' + currentAddress['location']['longitude']
            + '\nneighborhood: ' + currentAddress['neighborhood']
            + '\nzipcode: ' + currentAddress['zipcode']
            + '\ncity: ' + currentAddress['city']
            + '\nstate: ' + currentAddress['state']
            + '\ncountry: ' + currentAddress['country']
        );

        // set input text
        $('#street').val(currentAddress['street_address']);

    });

}

var updateCoordinates = function() {

    // when the user changes the street address
    var address =$('#street').val();

    // quick return if no address
    if (!address)
        return;

    // otherwise geocode and update
    var options = {
        types: 'address',
        limit: 1,
        autocomplete: 'true'
    };
    geocoder.geocode(address, options,
        function (results, status) {

            if (status != "success") {
                bsalert("Could not geocode:\nError " + status + ", " + results['error']);
                return;
            }

            // quick return if found nothing
            if (results.length == 0) {
                console.log('Got nothing from geocode');
                return;
            }

            // parse features into address
            var address = geocoder.parse_feature(results[0]);

            console.log(
                'Setting currentLocation to:'
                + '\nnumber: ' + address['number']
                + '\nstreet: ' + address['street']
                + '\nunit: ' + address['unit']
                + '\nlocation: ' + address['location']['latitude']
                + ',' + address['location']['longitude']
                + '\nneighborhood: ' + address['neighborhood']
                + '\nzipcode: ' + address['zipcode']
                + '\ncity: ' + address['city']
                + '\nstate: ' + address['state']
                + '\ncountry: ' + address['country']
            );

            // set current location
            updateCurrentLocation({
                lat: address['location']['latitude'],
                lng: address['location']['longitude']
            });

        });
}

function dispatchCall() {

    var form = {};

    // call information
    var street_address = $('#street').val().trim();
    form['details'] = $('#comment').val().trim();
    form['priority'] = $('input:radio[name=priority]:checked').val();

    // checks
    if (form["priority"] === undefined) {
        bsalert("Please select the priority level.");
        return;
    }
    if (numberOfDispatchingAmbulances == 0) {
        bsalert("Please dispatch at least one ambulance.");
        return;
    }

    // address information
    form['neighborhood'] = currentAddress['neighborhood'];
    form['city'] = currentAddress['city'];
    form['state'] = currentAddress['state'];
    form['country'] = currentAddress['country'];
    form['zipcode'] = currentAddress['zipcode'];
    form['location'] = currentAddress['location'];

    // Has the user modified the street address?
    if (street_address != currentAddress['street_address']) {

        // parse street address
        var address = geocoder.parse_street_address(street_address, form['country']);

        form['number'] = address['number'];
        form['street'] = address['street'];
        form['unit'] = address['unit'];

    } else {

        form['number'] = currentAddress['number'];
        form['street'] = currentAddress['street'];
        form['unit'] = currentAddress['unit'];

    }

    // Make sure blanks are undefined
    if (form['number'] == "") {
        form['number'] = undefined;
    }

    // ambulances
    var ambulances = [];
    for (var id in dispatchingAmbulances) {
        if (dispatchingAmbulances.hasOwnProperty(id))
            ambulances.push({ 'ambulance_id': id });
		}
    form['ambulancecall_set'] = ambulances;

    // patients
    var patients = [];
    for (var index in currentPatients)
        if (currentPatients.hasOwnProperty(index)) {
            var patient = currentPatients[index];
            var obj = { 'name': patient[0] };
            if (patient[1])
                // add age
                obj['age'] = parseInt(patient[1]);
            patients.push(obj);
        }
    form['patient_set'] = patients;

    // make json call
    var postJsonUrl = APIBaseUrl + 'call/';
    console.log("Form:");
    console.log(form);
    console.log("Will post:");
    console.log(JSON.stringify(form));

    var CSRFToken = Cookies.get('csrftoken');
    console.log('csrftoken = ' + CSRFToken);

    // retrieve csrf token
    $.ajaxSetup({
        beforeSend: function (xhr, settings) {
            if (!CSRFSafeMethod(settings.type) && !this.crossDomain) {
                xhr.setRequestHeader("X-CSRFToken", CSRFToken);
            }
        }
    });

    // make ajax call
    $.ajax({
        url: postJsonUrl,
        type: 'POST',
        dataType: 'json',
        contentType: 'application/json',
        data: JSON.stringify(form),
        success: function (data) {

            // Log success
            console.log("Succesfully posted new call.");

            // End dispatching
            endDispatching();

        },
        error: function (jqXHR, textStatus, errorThrown) {

            // Log failure
            console.log("Failed to post new call.");
            console.log(jqXHR.responseText);

            // Show modal
            bsalert(jqXHR.responseText, 'alert-danger', 'Failure');

            // End dispatching
            endDispatching();

        }
    });
}

// patient functions

var addPatient = function(index) {

    console.log('Adding patient index ' + index);

    var name = $('#patient-' + index + '-name').val().trim();
    var age = $('#patient-' + index + '-age').val().trim();

    // is name empty?
    if (!name) {
        bsalert('Empty name');
        return;
    }

    // add name
    currentPatients[index] = [name, age];
    newPatientIndex++;

    // change button symbol
    var symbol = $('#patient-' + index + '-symbol');
    symbol.removeClass('fa-plus');
    symbol.addClass('fa-minus');

    // change button action from add to remove
    $('#patients').find('#patient-' + index + '-button')
        .off()
        .on('click', function(e) { removePatient(index); });

    // add new form
    addPatientForm(newPatientIndex);

}

var removePatient = function(index) {

    console.log('Removing patient index ' + index);

    // remove from storage
    delete currentPatients[index];

    // remove from form
    $('#patients')
        .find('#patient-' + index + '-form')
        .remove();

}

var addPatientForm = function(index) {

    // add new patient form entry
    $('#patients').append(newPatientForm(index, 'fa-plus'));

    // bind addPatient to click
    $('#patients')
        .on('click',
            '#patient-' + index + '-button',
            function(e) { addPatient(index); });

}

var newPatientForm = function(index, symbol) {

    var html =
        '
' +
            '
' +
                '<input id="patient-' + index + '-name" ' +
                       'type="text" ' +
                       'class="form-control" ' +
                       'placeholder="Name">' +
            '
' +
            '
' +
                '<input id="patient-' + index + '-age" ' +
                       'type="number" min="0" ' +
                       'class="form-control" ' +
                       'placeholder="Age">' +
            '
' +
            '
' +
                '<button class="btn btn-default btn-block new-patient" ' +
                       ' type="button" ' +
                       ' id="patient-' + index + '-button">' +
                    '' +
                '</button>' +
            '
' +
        '
';

    // console.log('html = "' + html + '"');

    return html;

}

// Ready function
$(function() {

    // connect actions to inputs

    $("#street").change(function () {

        // update coordinates?
        if ($('#update-coordinates').prop('checked'))
            updateCoordinates();

    });

    $('#update-coordinates').change(function () {

        // update coordinates?
        if ($('#update-coordinates').prop('checked'))
            updateCoordinates();

    });

    $('#update-address').change(function () {

        // update address?
        if ($('#update-address').prop('checked'))
            updateCurrentAddress(currentLocation);

    });

    $('#dispatch-form-collapse').submit(function (e) {

        // prevent normal form submission
        e.preventDefault();

        // dispatch call
        dispatchCall();

    });

});

// CSRF functions

function CSRFSafeMethod(method) {
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
<commit_msg>double click to move the marker pin on the map while dispatching is implemented<commit_after>/* Dispatch area - Should be eliminate after dispatching */

var markersGroup = new L.LayerGroup();
console.log("\n\n\n\n");
console.log("printining markersGroup");
console.log(markersGroup);
var isDispatching = false;
var isFilterOpen = false;
var placeIcon = L.icon({
	iconUrl: '/static/icons/place_marker.png',
	iconSize: [40, 40],
	iconAnchor: [20, 40],
	popupAnchor: [0,-40]
});

var dispatchingAmbulances = {};
var numberOfDispatchingAmbulances = 0;

var currentAddress;
var currentLocation;
var currentPatients;
var newPatientIndex;

var submitDispatching = function () {

    // submit form
    $('#dispatch-form-collapse').submit();

};

var beginDispatching = function () {

    isDispatching = true;
    var filtersDiv = $('#filtersDiv');
    isFilterOpen = filtersDiv.hasClass('show');
    console.log('Begin dispatching.');

    $('#dispatchBeginButton').hide();
    $('#dispatchSubmitButton').show();
    $('#dispatchCancelButton').show();

    // open filter and available ambulances
    filtersDiv.addClass('show');
    $('#ambulance_status').addClass('show');
    $('#ambulance_AV').addClass('show');

    // Update current location
    updateCurrentLocation(mymap.getCenter());

    // Update current address
    updateCurrentAddress(currentLocation);

    // Clear current currentPatients
    currentPatients = {};
    newPatientIndex = 0;

    // Initialize patient form
    $('#patients').empty();

    // add new patient form entry
    addPatientForm(newPatientIndex);

    // resize size
    resizeMap();

    // center map
    mymap.setView(currentLocation, mymap.getZoom());

}

var endDispatching = function () {

    isDispatching = false;
    dispatchingAmbulances = {};
    console.log('End dispatching.');

    markersGroup.clearLayers();

    $('#dispatchBeginButton').show();
    $('#dispatchSubmitButton').hide();
    $('#dispatchCancelButton').hide();

    // close dispatch panel
    $('#dispatchDiv').removeClass('show');

    if (!isFilterOpen) {
        // close filter panel
        $('#filtersDiv').removeClass('show');
    }

    // invalidate map size
    mymap.invalidateSize();

}

var removeFromDispatchingList = function(ambulance) {

    // delete from dispatching list
    delete dispatchingAmbulances[ambulance.id];
    numberOfDispatchingAmbulances--;

    // show message if last button
    if (numberOfDispatchingAmbulances == 0)
        $('#ambulance-selection-message').show();

}

var addToDispatchingList = function(ambulance) {

    // quick return if null or not dispatching
    if (ambulance == null || !isDispatching)
        return;

    // add ambulance to dispatching list
    console.log('Adding ambulance ' + ambulance.identifier + ' to dispatching list');

    // already in?
    if (ambulance.id in dispatchingAmbulances) {
        console.log('Already in dispatching list, skip');
        return;
    }

    // not available?
    if (ambulance.status != STATUS_AVAILABLE) {
        console.log('Ambulance is not available');
        bsalert('Can only dispatch available ambulances!');
        return;
    }

    // hide message if first button
    if (numberOfDispatchingAmbulances == 0)
        $('#ambulance-selection-message').hide();

    // add ambulance to list of dispatching ambulances
    dispatchingAmbulances[ambulance.id] = ambulance;
    numberOfDispatchingAmbulances++;

    // add button to ambulance dispatch grid
    $('#ambulance-selection').append(
        '<button id="dispatch-button-' + ambulance.id + '"'
        + ' value="' + ambulance.id + '"'
        + ' type="button" class="btn btn-sm '+ ambulance_buttons['AV'] + '"'
        + ' style="margin: 2px 2px;"'
        + ' draggable="true">'
        + ambulance.identifier
        + '</button>'
    );
    $('#dispatch-button-' + ambulance.id)
        .on('dragstart', function (e) {
            // on start of drag, copy information and fade button
            console.log('dragstart');
            this.style.opacity = '0.4';
            e.originalEvent.dataTransfer.setData("text/plain", ambulance.id);
        })
        .on('dragend', function (e) {
            console.log('dragend');
            if (e.originalEvent.dataTransfer.dropEffect == 'none') {
                // Remove button if not dropped back
                removeFromDispatchingList(ambulance);
                // Remove button
                $(this).remove();
            } else {
                // Restore opacity if dropped back in
                this.style.opacity = '1.0';
            }
        });
}

var updateCurrentLocation = function(location) {

    console.log('Setting current location to: ' + location.lat + ', ' + location.lng);

    // set currentLocation
    currentLocation = location;

    // update coordinates on form
    $('#curr-lat').html(currentLocation.lat.toFixed(6));
    $('#curr-lng').html(currentLocation.lng.toFixed(6));

    // remove existing marker
    markersGroup.clearLayers();

    // laydown marker
    var marker = L.marker(location,
        {
            icon: placeIcon,
            draggable: true
        })
        .addTo(markersGroup);
    markersGroup.addTo(mymap);

		mymap.on('dblclick', function(e) {
			console.log("right click at:", e.latlng.lat, e.latlng.lng);
			console.log(e);

			updateCurrentLocation(e.latlng);
			// var popOpt = L.popup().setContent('
Hello world!
This is a nice popup.
');
			// popOpt.openOn(mymap);
			if ($('#update-address').prop('checked'))
					updateCurrentAddress(currentLocation);

			if(e) {
				console.log("***********");
				console.log(e);
				e.stopImmediatePropagation();
			}
		})

    // pan to location
    mymap.panTo(location);

    // events
    marker.on('dragend', function(e) {

			console.log("clicked in dblclick");
        updateCurrentLocation(marker.getLatLng());

        // update address?
        if ($('#update-address').prop('checked'))
            updateCurrentAddress(currentLocation);

    })

		// commented out by kaung to test double click
    // marker.on('dragend', function(e) {
		//
    //     // update current location
    //     updateCurrentLocation(marker.getLatLng());
		//
    //     // update address?
    //     if ($('#update-address').prop('checked'))
    //         updateCurrentAddress(currentLocation);
		//
    // })

}

var updateCurrentAddress = function(location) {

    var options = {
        types: 'address',
        limit: 1
    };
    geocoder.reverse(location, options,
        function (results, status) {

        if (status != "success") {
            bsalert("Could not geocode:\nError " + status + ", " + results['error']);
            return;
        }

        // quick return if found nothing
        if (results.length == 0) {
            console.log('Got nothing from geocode');
            return;
        }

        // parse features into current address
        currentAddress = geocoder.parse_feature(results[0]);

        console.log(
            'Setting currentAddress to:'
            + '\nnumber: ' + currentAddress['number']
            + '\nstreet: ' + currentAddress['street']
            + '\nunit: ' + currentAddress['unit']
            + '\nlocation: ' + currentAddress['location']['latitude']
            + ',' + currentAddress['location']['longitude']
            + '\nneighborhood: ' + currentAddress['neighborhood']
            + '\nzipcode: ' + currentAddress['zipcode']
            + '\ncity: ' + currentAddress['city']
            + '\nstate: ' + currentAddress['state']
            + '\ncountry: ' + currentAddress['country']
        );

        // set input text
        $('#street').val(currentAddress['street_address']);

    });

}

var updateCoordinates = function() {

    // when the user changes the street address
    var address =$('#street').val();

    // quick return if no address
    if (!address)
        return;

    // otherwise geocode and update
    var options = {
        types: 'address',
        limit: 1,
        autocomplete: 'true'
    };
    geocoder.geocode(address, options,
        function (results, status) {

            if (status != "success") {
                bsalert("Could not geocode:\nError " + status + ", " + results['error']);
                return;
            }

            // quick return if found nothing
            if (results.length == 0) {
                console.log('Got nothing from geocode');
                return;
            }

            // parse features into address
            var address = geocoder.parse_feature(results[0]);

            console.log(
                'Setting currentLocation to:'
                + '\nnumber: ' + address['number']
                + '\nstreet: ' + address['street']
                + '\nunit: ' + address['unit']
                + '\nlocation: ' + address['location']['latitude']
                + ',' + address['location']['longitude']
                + '\nneighborhood: ' + address['neighborhood']
                + '\nzipcode: ' + address['zipcode']
                + '\ncity: ' + address['city']
                + '\nstate: ' + address['state']
                + '\ncountry: ' + address['country']
            );

            // set current location
            updateCurrentLocation({
                lat: address['location']['latitude'],
                lng: address['location']['longitude']
            });

        });
}

function dispatchCall() {

    var form = {};

    // call information
    var street_address = $('#street').val().trim();
    form['details'] = $('#comment').val().trim();
    form['priority'] = $('input:radio[name=priority]:checked').val();

    // checks
    if (form["priority"] === undefined) {
        bsalert("Please select the priority level.");
        return;
    }
    if (numberOfDispatchingAmbulances == 0) {
        bsalert("Please dispatch at least one ambulance.");
        return;
    }

    // address information
    form['neighborhood'] = currentAddress['neighborhood'];
    form['city'] = currentAddress['city'];
    form['state'] = currentAddress['state'];
    form['country'] = currentAddress['country'];
    form['zipcode'] = currentAddress['zipcode'];
    form['location'] = currentAddress['location'];

    // Has the user modified the street address?
    if (street_address != currentAddress['street_address']) {

        // parse street address
        var address = geocoder.parse_street_address(street_address, form['country']);

        form['number'] = address['number'];
        form['street'] = address['street'];
        form['unit'] = address['unit'];

    } else {

        form['number'] = currentAddress['number'];
        form['street'] = currentAddress['street'];
        form['unit'] = currentAddress['unit'];

    }

    // Make sure blanks are undefined
    if (form['number'] == "") {
        form['number'] = undefined;
    }

    // ambulances
    var ambulances = [];
    for (var id in dispatchingAmbulances) {
        if (dispatchingAmbulances.hasOwnProperty(id))
            ambulances.push({ 'ambulance_id': id });
		}
    form['ambulancecall_set'] = ambulances;

    // patients
    var patients = [];
    for (var index in currentPatients)
        if (currentPatients.hasOwnProperty(index)) {
            var patient = currentPatients[index];
            var obj = { 'name': patient[0] };
            if (patient[1])
                // add age
                obj['age'] = parseInt(patient[1]);
            patients.push(obj);
        }
    form['patient_set'] = patients;

    // make json call
    var postJsonUrl = APIBaseUrl + 'call/';
    console.log("Form:");
    console.log(form);
    console.log("Will post:");
    console.log(JSON.stringify(form));

    var CSRFToken = Cookies.get('csrftoken');
    console.log('csrftoken = ' + CSRFToken);

    // retrieve csrf token
    $.ajaxSetup({
        beforeSend: function (xhr, settings) {
            if (!CSRFSafeMethod(settings.type) && !this.crossDomain) {
                xhr.setRequestHeader("X-CSRFToken", CSRFToken);
            }
        }
    });

    // make ajax call
    $.ajax({
        url: postJsonUrl,
        type: 'POST',
        dataType: 'json',
        contentType: 'application/json',
        data: JSON.stringify(form),
        success: function (data) {

            // Log success
            console.log("Succesfully posted new call.");

            // End dispatching
            endDispatching();

        },
        error: function (jqXHR, textStatus, errorThrown) {

            // Log failure
            console.log("Failed to post new call.");
            console.log(jqXHR.responseText);

            // Show modal
            bsalert(jqXHR.responseText, 'alert-danger', 'Failure');

            // End dispatching
            endDispatching();

        }
    });
}

// patient functions

var addPatient = function(index) {

    console.log('Adding patient index ' + index);

    var name = $('#patient-' + index + '-name').val().trim();
    var age = $('#patient-' + index + '-age').val().trim();

    // is name empty?
    if (!name) {
        bsalert('Empty name');
        return;
    }

    // add name
    currentPatients[index] = [name, age];
    newPatientIndex++;

    // change button symbol
    var symbol = $('#patient-' + index + '-symbol');
    symbol.removeClass('fa-plus');
    symbol.addClass('fa-minus');

    // change button action from add to remove
    $('#patients').find('#patient-' + index + '-button')
        .off()
        .on('click', function(e) { removePatient(index); });

    // add new form
    addPatientForm(newPatientIndex);

}

var removePatient = function(index) {

    console.log('Removing patient index ' + index);

    // remove from storage
    delete currentPatients[index];

    // remove from form
    $('#patients')
        .find('#patient-' + index + '-form')
        .remove();

}

var addPatientForm = function(index) {

    // add new patient form entry
    $('#patients').append(newPatientForm(index, 'fa-plus'));

    // bind addPatient to click
    $('#patients')
        .on('click',
            '#patient-' + index + '-button',
            function(e) { addPatient(index); });

}

var newPatientForm = function(index, symbol) {

    var html =
        '
' +
            '
' +
                '<input id="patient-' + index + '-name" ' +
                       'type="text" ' +
                       'class="form-control" ' +
                       'placeholder="Name">' +
            '
' +
            '
' +
                '<input id="patient-' + index + '-age" ' +
                       'type="number" min="0" ' +
                       'class="form-control" ' +
                       'placeholder="Age">' +
            '
' +
            '
' +
                '<button class="btn btn-default btn-block new-patient" ' +
                       ' type="button" ' +
                       ' id="patient-' + index + '-button">' +
                    '' +
                '</button>' +
            '
' +
        '
';

    // console.log('html = "' + html + '"');

    return html;

}

// Ready function
$(function() {

    // connect actions to inputs

    $("#street").change(function () {

        // update coordinates?
        if ($('#update-coordinates').prop('checked'))
            updateCoordinates();

    });

    $('#update-coordinates').change(function () {

        // update coordinates?
        if ($('#update-coordinates').prop('checked'))
            updateCoordinates();

    });

    $('#update-address').change(function () {

        // update address?
        if ($('#update-address').prop('checked'))
            updateCurrentAddress(currentLocation);

    });

    $('#dispatch-form-collapse').submit(function (e) {

        // prevent normal form submission
        e.preventDefault();

        // dispatch call
        dispatchCall();

    });

});

// CSRF functions

function CSRFSafeMethod(method) {
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
<|endoftext|>


<commit_before>;
(function (d, n) {
  'use strict';
  var os = n.platform.match(/(Win|Mac|Linux)/);
  var x = n.userAgent.match(/x86_64|Win64|WOW64/) ||
    n.cpuClass === 'x64' ? 'x64' : 'x86';
  var db = d.getElementById('home-downloadbutton');
  if (!db) { return; }
  var version = db.dataset.version;
  var dlLocal = db.dataset.dlLocal;
  switch (os && os[1]) {
    case 'Mac':
      db.href += 'node-' + version + '.pkg';
      db.innerText = dlLocal + ' OS X (x64)';
      break;
    case 'Win':
      db.href += (version[0] == '0' && x == 'x64' ? x + '/' : '') + 'node-' + version + '-' + x + '.msi';
      db.innerText = dlLocal + ' Windows (' + x +')';
      break;
    case 'Linux':
      db.href += 'node-' + version + '-linux-' + x + '.tar.gz';
      db.innerText = dlLocal + ' Linux (' + x + ')';
      break;
  }
})(document, navigator);
<commit_msg>js: Fix version check for win-x64<commit_after>;
(function (d, n) {
  'use strict';
  var os = n.platform.match(/(Win|Mac|Linux)/);
  var x = n.userAgent.match(/x86_64|Win64|WOW64/) ||
    n.cpuClass === 'x64' ? 'x64' : 'x86';
  var db = d.getElementById('home-downloadbutton');
  if (!db) { return; }
  var version = db.dataset.version;
  var dlLocal = db.dataset.dlLocal;
  switch (os && os[1]) {
    case 'Mac':
      db.href += 'node-' + version + '.pkg';
      db.innerText = dlLocal + ' OS X (x64)';
      break;
    case 'Win':
      // Windows 64-bit files for 0.x.x need to be prefixed with 'x64/'
      db.href += (version[1] == '0' && x == 'x64' ? x + '/' : '') + 'node-' + version + '-' + x + '.msi';
      db.innerText = dlLocal + ' Windows (' + x +')';
      break;
    case 'Linux':
      db.href += 'node-' + version + '-linux-' + x + '.tar.gz';
      db.innerText = dlLocal + ' Linux (' + x + ')';
      break;
  }
})(document, navigator);
<|endoftext|>


<commit_before>$.widget( "ui.timespinner", $.ui.spinner, {
  options: {
    // seconds
    step: 60 * 1000,
    // hours
    page: 60
  },
  _parse: function( value ) {
    if ( typeof value === "string" ) {
      // already a timestamp
      if ( Number( value ) == value ) {
        return Number( value );
      }
      return +Globalize.parseDate( value );
    }
    return value;
  },
  _format: function( value ) {
    return Globalize.format( new Date(value), "t" );
  }
});

$(function() {
  $( "#jobListDateRange" ).hide();

  $( "#jobsFrom" ).datepicker({
    defaultDate: "-1",
    changeMonth: true,
    numberOfMonths: 2,
    dateFormat: "yy-mm-dd",
    onClose: function( selectedDate ) {
      $( "#jobsTo" ).datepicker( "option", "minDate", selectedDate );
    }
  });

  $( "#jobsTo" ).datepicker({
    defaultDate: "+7",
    changeMonth: true,
    numberOfMonths: 2,
    dateFormat: "yy-mm-dd",
    onClose: function( selectedDate ) {
      $( "#jobsFrom" ).datepicker( "option", "maxDate", selectedDate );
    }

  });

  $( "#jobsFrom" ).datepicker("setDate",-1);
  $( "#jobsTo" ).datepicker("setDate",30);

//   Globalize.culture( "de-DE" );
});

function populatePanes()
{
  var fromDate = $("#jobsFrom").datepicker('getDate');
  var fromEpoch = fromDate.getTime()/1000.0;

  var toDate = $("#jobsTo").datepicker('getDate');
  //add a day - want everything up to the end of midnight
  //on the to date
  toDate.setDate(toDate.getDate()+1);
  var toEpoch = toDate.getTime()/1000.0;

  $("#jobCandidates").html( "" );
  // get images from the db
  $.ajax({
    url: "../image",
    dataType: 'json',
    async: false,
    data: {jobList: 0,
     status: "pending"},
    success: function(json) {
      $.each(json, function (e, y) {
        var li = createImageListElement(y);
        $( "#jobCandidates").append(li);
      });
    }
  });

  $.ajax({
    url: "../image",
    dataType: 'json',
    async: false,
    data: {jobList: 0,
     status: "queued",
     minDate: fromEpoch,
     maxDate: toEpoch},
    success: function(json) {
      $.each(json, function (e, y) {
        var li = createImageListElement(y);
        li.attr("jobTime",y[2]);
        $( "#jobQueued").append(li);
      });
    }
  });

}

function setupCalendar()
{
  var fromDate = $("#jobsFrom").datepicker('getDate');
  var toDate = $("#jobsTo").datepicker('getDate');
  $("#jobQueued").html( "" );

  while (fromDate < toDate)
  {
    var hour = 2;
    var minute = 0;
    var dayDate = new Date(fromDate);
    var day = dayDate.getDate();
    var month = dayDate.getMonth();
    var year = dayDate.getFullYear();
    var displayId = day + "/" + (month+1) + "/" + year;
    var id = day + "_" + month + "_" + year;

    var li = $('
');
    li.attr("class","fixed dateHeader");
    li.attr("hour", hour);
    li.attr("minute", minute);
    li.attr("day", day);
    li.attr("month", month);
    li.attr("year", year);
    var unixTime =  dayDate.getTime() / 1000.0;
    li.attr("jobTime", unixTime);
    li.append(displayId);
    li.append('
');

    $("#jobQueued").append(li);

    fromDate.setDate(fromDate.getDate()+1);
  }

}

function commitJobs()
{
  var nQueued = 0;
  var currDate = new Date();
  var initialised = false;

  $("#jobQueued li").each (function (index, li) {
    if ($(this).hasClass("fixed"))
    {
      hour = $(this).attr("hour");
      minute = $(this).attr("minute");
      day = $(this).attr("day");
      month = $(this).attr("month");
      year = $(this).attr("year");
      currDate = new Date(year,month,day,hour,minute,0,0);
      initialised = true;
      nQueued += 1;
    }
    else
    {
      if (initialised == false)
      {
        alert("UNQUEUEABLE IMAGE: no date assigned!");
        return true;
      }
      var dateString = currDate.toDateString();
      var timeString = currDate.toTimeString();
      var dbid = jQuery(this).find("img").attr("dbid");
      var status = 'queued';
      var timeStamp = currDate.getTime() / 1000.0;

      submitDict = {}
      submitDict["queueJob"] = 0;
      submitDict["imageId"] = dbid;
      submitDict["status"] = status;
      submitDict["jobTime"] = timeStamp;

      $.post('../image',
      submitDict,
      function(response) {
        //no-op, probably
      }, 'json');

      var delay = 5 * 60 * 1000; //5 mins
      var newDateObj = new Date();
      newDateObj.setTime(currDate.getTime() + delay);
      currDate = newDateObj;
    }
  });

  $("#jobCandidates li").each (function (index, li) {
    var dbid = jQuery(this).find("img").attr("dbid");

    submitDict = {}
    submitDict["queueJob"] = 0;
    submitDict["imageId"] = dbid;
    submitDict["status"] = "pending";
    submitDict["jobTime"] = 0;

    $.post('../image',
    submitDict,
    function(response) {
      //no-op, probably
    }, 'json');
  });
}

$("#jobsApplyButton").click(function () {
  commitJobs();
  showMain();
});

$("#jobsDatesButton").click(function () {
  setupJobsPane();
});

function setupJobsPane()
{
  setupCalendar();
  populatePanes();

  var mylist = $('#jobQueued');
  var listitems = mylist.children('li').get();
  listitems.sort(function(a, b) {
    var aAttr = $(a).attr("jobTime");
    var bAttr = $(b).attr("jobTime");
    return parseInt(aAttr)>parseInt(bAttr);
  });
  $.each(listitems, function(idx, itm) { mylist.append(itm); });

  $( "#jobCandidates, #jobQueued" ).sortable({
    connectWith: ".connectedSortable",
    cancel: ".fixed"
  }).disableSelection();

}

$( "#jobListDateRangeShow" ).click(function() {
  $("#jobListDateRangeShow").hide("fast");
  $("#jobListDateRange").show("fast");
});

$( "#jobListDateRangeHide" ).click(function() {
  $("#jobListDateRange").hide("fast");
  $("#jobListDateRangeShow").show("fast");
});<commit_msg>Time fix - go for 1am upload!<commit_after>$.widget( "ui.timespinner", $.ui.spinner, {
  options: {
    // seconds
    step: 60 * 1000,
    // hours
    page: 60
  },
  _parse: function( value ) {
    if ( typeof value === "string" ) {
      // already a timestamp
      if ( Number( value ) == value ) {
        return Number( value );
      }
      return +Globalize.parseDate( value );
    }
    return value;
  },
  _format: function( value ) {
    return Globalize.format( new Date(value), "t" );
  }
});

$(function() {
  $( "#jobListDateRange" ).hide();

  $( "#jobsFrom" ).datepicker({
    defaultDate: "-1",
    changeMonth: true,
    numberOfMonths: 2,
    dateFormat: "yy-mm-dd",
    onClose: function( selectedDate ) {
      $( "#jobsTo" ).datepicker( "option", "minDate", selectedDate );
    }
  });

  $( "#jobsTo" ).datepicker({
    defaultDate: "+7",
    changeMonth: true,
    numberOfMonths: 2,
    dateFormat: "yy-mm-dd",
    onClose: function( selectedDate ) {
      $( "#jobsFrom" ).datepicker( "option", "maxDate", selectedDate );
    }

  });

  $( "#jobsFrom" ).datepicker("setDate",-1);
  $( "#jobsTo" ).datepicker("setDate",30);

//   Globalize.culture( "de-DE" );
});

function populatePanes()
{
  var fromDate = $("#jobsFrom").datepicker('getDate');
  var fromEpoch = fromDate.getTime()/1000.0;

  var toDate = $("#jobsTo").datepicker('getDate');
  //add a day - want everything up to the end of midnight
  //on the to date
  toDate.setDate(toDate.getDate()+1);
  var toEpoch = toDate.getTime()/1000.0;

  $("#jobCandidates").html( "" );
  // get images from the db
  $.ajax({
    url: "../image",
    dataType: 'json',
    async: false,
    data: {jobList: 0,
     status: "pending"},
    success: function(json) {
      $.each(json, function (e, y) {
        var li = createImageListElement(y);
        $( "#jobCandidates").append(li);
      });
    }
  });

  $.ajax({
    url: "../image",
    dataType: 'json',
    async: false,
    data: {jobList: 0,
     status: "queued",
     minDate: fromEpoch,
     maxDate: toEpoch},
    success: function(json) {
      $.each(json, function (e, y) {
        var li = createImageListElement(y);
        li.attr("jobTime",y[2]);
        $( "#jobQueued").append(li);
      });
    }
  });

}

function setupCalendar()
{
  var fromDate = $("#jobsFrom").datepicker('getDate');
  var toDate = $("#jobsTo").datepicker('getDate');
  $("#jobQueued").html( "" );

  while (fromDate < toDate)
  {
    var hour = 9;
    var minute = 0;
    var dayDate = new Date(fromDate);
    var day = dayDate.getDate();
    var month = dayDate.getMonth();
    var year = dayDate.getFullYear();
    var displayId = day + "/" + (month+1) + "/" + year;
    var id = day + "_" + month + "_" + year;

    var li = $('
');
    li.attr("class","fixed dateHeader");
    li.attr("hour", hour);
    li.attr("minute", minute);
    li.attr("day", day);
    li.attr("month", month);
    li.attr("year", year);
    var unixTime =  dayDate.getTime() / 1000.0;
    li.attr("jobTime", unixTime);
    li.append(displayId);
    li.append('
');

    $("#jobQueued").append(li);

    fromDate.setDate(fromDate.getDate()+1);
  }

}

function commitJobs()
{
  var nQueued = 0;
  var currDate = new Date();
  var initialised = false;

  $("#jobQueued li").each (function (index, li) {
    if ($(this).hasClass("fixed"))
    {
      hour = $(this).attr("hour");
      minute = $(this).attr("minute");
      day = $(this).attr("day");
      month = $(this).attr("month");
      year = $(this).attr("year");
      currDate = new Date(year,month,day,hour,minute,0,0);
      initialised = true;
      nQueued += 1;
    }
    else
    {
      if (initialised == false)
      {
        alert("UNQUEUEABLE IMAGE: no date assigned!");
        return true;
      }
      var dateString = currDate.toDateString();
      var timeString = currDate.toTimeString();
      var dbid = jQuery(this).find("img").attr("dbid");
      var status = 'queued';
      var timeStamp = currDate.getTime() / 1000.0;

      submitDict = {}
      submitDict["queueJob"] = 0;
      submitDict["imageId"] = dbid;
      submitDict["status"] = status;
      submitDict["jobTime"] = timeStamp;

      $.post('../image',
      submitDict,
      function(response) {
        //no-op, probably
      }, 'json');

      var delay = 5 * 60 * 1000; //5 mins
      var newDateObj = new Date();
      newDateObj.setTime(currDate.getTime() + delay);
      currDate = newDateObj;
    }
  });

  $("#jobCandidates li").each (function (index, li) {
    var dbid = jQuery(this).find("img").attr("dbid");

    submitDict = {}
    submitDict["queueJob"] = 0;
    submitDict["imageId"] = dbid;
    submitDict["status"] = "pending";
    submitDict["jobTime"] = 0;

    $.post('../image',
    submitDict,
    function(response) {
      //no-op, probably
    }, 'json');
  });
}

$("#jobsApplyButton").click(function () {
  commitJobs();
  showMain();
});

$("#jobsDatesButton").click(function () {
  setupJobsPane();
});

function setupJobsPane()
{
  setupCalendar();
  populatePanes();

  var mylist = $('#jobQueued');
  var listitems = mylist.children('li').get();
  listitems.sort(function(a, b) {
    var aAttr = $(a).attr("jobTime");
    var bAttr = $(b).attr("jobTime");
    return parseInt(aAttr)>parseInt(bAttr);
  });
  $.each(listitems, function(idx, itm) { mylist.append(itm); });

  $( "#jobCandidates, #jobQueued" ).sortable({
    connectWith: ".connectedSortable",
    cancel: ".fixed"
  }).disableSelection();

}

$( "#jobListDateRangeShow" ).click(function() {
  $("#jobListDateRangeShow").hide("fast");
  $("#jobListDateRange").show("fast");
});

$( "#jobListDateRangeHide" ).click(function() {
  $("#jobListDateRange").hide("fast");
  $("#jobListDateRangeShow").show("fast");
});<|endoftext|>


<commit_before>'use strict';

const fs = require('fs');
const path = require('path');
const { SourceNode, SourceMapConsumer } = require('source-map');
const makeIdentitySourceMap = require('./makeIdentitySourceMap');

let tagCommonJSExportsSource = null;

function transform(source, map) {
  // This is a Webpack loader, but the user put it in the Babel config.
  if (source && source.types && source.types.IfStatement) {
    throw new Error(
      'React Hot Loader: You are erroneously trying to use a Webpack loader ' +
      'as a Babel plugin. Replace "react-hot-loader/webpack" with ' +
      '"react-hot-loader/babel" in the "plugins" section of your .babelrc file. ' +
      'While we recommend the above, if you prefer not to use Babel, ' +
      'you may remove "react-hot-loader/webpack" from the "plugins" section of ' +
      'your .babelrc file altogether, and instead add "react-hot-loader/webpack" ' +
      'to the "loaders" section of your Webpack configuration.'
    );
  }

  if (this.cacheable) {
    this.cacheable();
  }

  // Read the helper once.
  if (!tagCommonJSExportsSource) {
    tagCommonJSExportsSource = fs.readFileSync(
      path.join(__dirname, 'tagCommonJSExports.js'),
      'utf8'
    )
    // Babel inserts these.
    // Ideally we'd opt out for one file but this is simpler.
    .replace(/['"]use strict['"];/, '')
    // eslint comments don't need to end up in the output
    .replace(/\/\/ eslint-disable-line .*\n/g, '\n')
    .replace(/\/\* global.*\*\//, '')
    .split(/\n\s*/)
    .join(' ');
  }

  // Parameterize the helper with the current filename.
  const separator = '\n\n';
  const appendText = tagCommonJSExportsSource.replace(
    /__FILENAME__/g,
    JSON.stringify(path.basename(this.resourcePath))
  );

  if (this.sourceMap === false) {
    return this.callback(null, [
      source,
      appendText,
    ].join(separator));
  }

  if (!map) {
    map = makeIdentitySourceMap(source, this.resourcePath); // eslint-disable-line no-param-reassign
  }
  const node = new SourceNode(null, null, null, [
    SourceNode.fromStringWithSourceMap(source, new SourceMapConsumer(map)),
    new SourceNode(null, null, this.resourcePath, appendText),
  ]).join(separator);

  const result = node.toStringWithSourceMap();
  return this.callback(null, result.code, result.map.toString());
}

module.exports = transform;
<commit_msg>Fix the import of a component from a component with the same base name (#347)<commit_after>'use strict';

const fs = require('fs');
const path = require('path');
const { SourceNode, SourceMapConsumer } = require('source-map');
const makeIdentitySourceMap = require('./makeIdentitySourceMap');

let tagCommonJSExportsSource = null;

function transform(source, map) {
  // This is a Webpack loader, but the user put it in the Babel config.
  if (source && source.types && source.types.IfStatement) {
    throw new Error(
      'React Hot Loader: You are erroneously trying to use a Webpack loader ' +
      'as a Babel plugin. Replace "react-hot-loader/webpack" with ' +
      '"react-hot-loader/babel" in the "plugins" section of your .babelrc file. ' +
      'While we recommend the above, if you prefer not to use Babel, ' +
      'you may remove "react-hot-loader/webpack" from the "plugins" section of ' +
      'your .babelrc file altogether, and instead add "react-hot-loader/webpack" ' +
      'to the "loaders" section of your Webpack configuration.'
    );
  }

  if (this.cacheable) {
    this.cacheable();
  }

  // Read the helper once.
  if (!tagCommonJSExportsSource) {
    tagCommonJSExportsSource = fs.readFileSync(
      path.join(__dirname, 'tagCommonJSExports.js'),
      'utf8'
    )
    // Babel inserts these.
    // Ideally we'd opt out for one file but this is simpler.
    .replace(/['"]use strict['"];/, '')
    // eslint comments don't need to end up in the output
    .replace(/\/\/ eslint-disable-line .*\n/g, '\n')
    .replace(/\/\* global.*\*\//, '')
    .split(/\n\s*/)
    .join(' ');
  }

  // Parameterize the helper with the current filename.
  const separator = '\n\n';
  const appendText = tagCommonJSExportsSource.replace(
    /__FILENAME__/g,
    JSON.stringify(this.resourcePath)
  );

  if (this.sourceMap === false) {
    return this.callback(null, [
      source,
      appendText,
    ].join(separator));
  }

  if (!map) {
    map = makeIdentitySourceMap(source, this.resourcePath); // eslint-disable-line no-param-reassign
  }
  const node = new SourceNode(null, null, null, [
    SourceNode.fromStringWithSourceMap(source, new SourceMapConsumer(map)),
    new SourceNode(null, null, this.resourcePath, appendText),
  ]).join(separator);

  const result = node.toStringWithSourceMap();
  return this.callback(null, result.code, result.map.toString());
}

module.exports = transform;
<|endoftext|>


<commit_before>var navigate = (function () {

var exports = {};

function go_to_row(row) {
    current_msg_list.select_id(rows.id(row),
                               {then_scroll: true,
                                from_scroll: true});
}

exports.up = function () {
    message_viewport.last_movement_direction = -1;
    var next_row = rows.prev_visible(current_msg_list.selected_row());
    if (next_row.length !== 0) {
        go_to_row(next_row);
    }
};

exports.down = function (with_centering) {
    message_viewport.last_movement_direction = 1;
    var next_row = rows.next_visible(current_msg_list.selected_row());
    if (next_row.length !== 0) {
        go_to_row(next_row);
    }
    if (with_centering && (next_row.length === 0)) {
        // At the last message, scroll to the bottom so we have
        // lots of nice whitespace for new messages coming in.
        //
        // FIXME: this doesn't work for End because rows.last_visible()
        // always returns a message.
        var current_msg_table = rows.get_table(current_msg_list.table_name);
        message_viewport.scrollTop(current_msg_table.safeOuterHeight(true) -
                                   message_viewport.height() * 0.1);
        unread_ops.mark_current_list_as_read();
    }
};

exports.to_home = function () {
    message_viewport.last_movement_direction = -1;
    var next_row = rows.first_visible(current_msg_list.selected_row());
    if (next_row.length !== 0) {
        go_to_row(next_row);
    }
};

exports.to_end = function () {
    var next_id = current_msg_list.last().id;
    message_viewport.last_movement_direction = 1;
    current_msg_list.select_id(next_id, {then_scroll: true,
                                         from_scroll: true});
    unread_ops.mark_current_list_as_read();
};

function amount_to_paginate() {
    // Some day we might have separate versions of this function
    // for Page Up vs. Page Down, but for now it's the same
    // strategy in either direction.
    var info = message_viewport.message_viewport_info();
    var page_size = info.visible_height;

    // We don't want to page up a full page, because Zulip users
    // are especially worried about missing messages, so we want
    // a little bit of the old page to stay on the screen.  The
    // value chosen here is roughly 2 or 3 lines of text, but there
    // is nothing sacred about it, and somebody more anal than me
    // might wish to tie this to the size of some particular DOM
    // element.
    var overlap_amount = 55;

    var delta = page_size - overlap_amount;

    // If the user has shrunk their browser a whole lot, pagination
    // is not going to be very pleasant, but we can at least
    // ensure they go in the right direction.
    if (delta < 1) {
        delta = 1;
    }

    return delta;
}

exports.page_up_the_right_amount = function () {
    // This function's job is to scroll up the right amount,
    // after the user hits Page Up.  We do this ourselves
    // because we can't rely on the browser to account for certain
    // page elements, like the compose box, that sit in fixed
    // positions above the message pane.  For other scrolling
    // related adjustements, try to make those happen in the
    // scroll handlers, not here.
    var delta = amount_to_paginate();
    message_viewport.scrollTop(message_viewport.scrollTop() - delta);
};

exports.page_down_the_right_amount = function () {
    // see also: page_up_the_right_amount
    var delta = amount_to_paginate();
    message_viewport.scrollTop(message_viewport.scrollTop() + delta);
};

exports.page_up = function () {
    if (message_viewport.at_top() && !current_msg_list.empty()) {
        current_msg_list.select_id(current_msg_list.first().id, {then_scroll: false});
    } else {
        exports.page_up_the_right_amount();
    }
};

exports.page_down = function () {
    if (message_viewport.at_bottom() && !current_msg_list.empty()) {
        current_msg_list.select_id(current_msg_list.last().id, {then_scroll: false});
        unread_ops.mark_current_list_as_read();
    } else {
        exports.page_down_the_right_amount();
    }
};

exports.scroll_to_selected = function () {
    var selected_row = current_msg_list.selected_row();
    if (selected_row && (selected_row.length !== 0)) {
        message_viewport.recenter_view(selected_row);
    }
};

exports.maybe_scroll_to_selected = function () {
    // If we have been previously instructed to re-center to the
    // selected message, then do so
    if (pointer.recenter_pointer_on_display) {
        exports.scroll_to_selected();
        pointer.recenter_pointer_on_display = false;
    }
};

return exports;
}());

if (typeof module !== 'undefined') {
    module.exports = navigate;
}
<commit_msg>Have home key go to actual first message in the list.<commit_after>var navigate = (function () {

var exports = {};

function go_to_row(row) {
    current_msg_list.select_id(rows.id(row),
                               {then_scroll: true,
                                from_scroll: true});
}

exports.up = function () {
    message_viewport.last_movement_direction = -1;
    var next_row = rows.prev_visible(current_msg_list.selected_row());
    if (next_row.length !== 0) {
        go_to_row(next_row);
    }
};

exports.down = function (with_centering) {
    message_viewport.last_movement_direction = 1;
    var next_row = rows.next_visible(current_msg_list.selected_row());
    if (next_row.length !== 0) {
        go_to_row(next_row);
    }
    if (with_centering && (next_row.length === 0)) {
        // At the last message, scroll to the bottom so we have
        // lots of nice whitespace for new messages coming in.
        //
        // FIXME: this doesn't work for End because rows.last_visible()
        // always returns a message.
        var current_msg_table = rows.get_table(current_msg_list.table_name);
        message_viewport.scrollTop(current_msg_table.safeOuterHeight(true) -
                                   message_viewport.height() * 0.1);
        unread_ops.mark_current_list_as_read();
    }
};

exports.to_home = function () {
    message_viewport.last_movement_direction = -1;
    var first_id = current_msg_list.first().id;
    current_msg_list.select_id(first_id, {then_scroll: true,
                                          from_scroll: true});
};

exports.to_end = function () {
    var next_id = current_msg_list.last().id;
    message_viewport.last_movement_direction = 1;
    current_msg_list.select_id(next_id, {then_scroll: true,
                                         from_scroll: true});
    unread_ops.mark_current_list_as_read();
};

function amount_to_paginate() {
    // Some day we might have separate versions of this function
    // for Page Up vs. Page Down, but for now it's the same
    // strategy in either direction.
    var info = message_viewport.message_viewport_info();
    var page_size = info.visible_height;

    // We don't want to page up a full page, because Zulip users
    // are especially worried about missing messages, so we want
    // a little bit of the old page to stay on the screen.  The
    // value chosen here is roughly 2 or 3 lines of text, but there
    // is nothing sacred about it, and somebody more anal than me
    // might wish to tie this to the size of some particular DOM
    // element.
    var overlap_amount = 55;

    var delta = page_size - overlap_amount;

    // If the user has shrunk their browser a whole lot, pagination
    // is not going to be very pleasant, but we can at least
    // ensure they go in the right direction.
    if (delta < 1) {
        delta = 1;
    }

    return delta;
}

exports.page_up_the_right_amount = function () {
    // This function's job is to scroll up the right amount,
    // after the user hits Page Up.  We do this ourselves
    // because we can't rely on the browser to account for certain
    // page elements, like the compose box, that sit in fixed
    // positions above the message pane.  For other scrolling
    // related adjustements, try to make those happen in the
    // scroll handlers, not here.
    var delta = amount_to_paginate();
    message_viewport.scrollTop(message_viewport.scrollTop() - delta);
};

exports.page_down_the_right_amount = function () {
    // see also: page_up_the_right_amount
    var delta = amount_to_paginate();
    message_viewport.scrollTop(message_viewport.scrollTop() + delta);
};

exports.page_up = function () {
    if (message_viewport.at_top() && !current_msg_list.empty()) {
        current_msg_list.select_id(current_msg_list.first().id, {then_scroll: false});
    } else {
        exports.page_up_the_right_amount();
    }
};

exports.page_down = function () {
    if (message_viewport.at_bottom() && !current_msg_list.empty()) {
        current_msg_list.select_id(current_msg_list.last().id, {then_scroll: false});
        unread_ops.mark_current_list_as_read();
    } else {
        exports.page_down_the_right_amount();
    }
};

exports.scroll_to_selected = function () {
    var selected_row = current_msg_list.selected_row();
    if (selected_row && (selected_row.length !== 0)) {
        message_viewport.recenter_view(selected_row);
    }
};

exports.maybe_scroll_to_selected = function () {
    // If we have been previously instructed to re-center to the
    // selected message, then do so
    if (pointer.recenter_pointer_on_display) {
        exports.scroll_to_selected();
        pointer.recenter_pointer_on_display = false;
    }
};

return exports;
}());

if (typeof module !== 'undefined') {
    module.exports = navigate;
}
<|endoftext|>


<commit_before>var navigate = (function () {

var exports = {};

function go_to_row(row) {
    current_msg_list.select_id(rows.id(row),
                               {then_scroll: true,
                                from_scroll: true});
}

exports.up = function () {
    message_viewport.last_movement_direction = -1;
    var next_row = rows.prev_visible(current_msg_list.selected_row());
    if (next_row.length !== 0) {
        go_to_row(next_row);
    }
};

exports.down = function (with_centering) {
    message_viewport.last_movement_direction = 1;
    var next_row = rows.next_visible(current_msg_list.selected_row());
    if (next_row.length !== 0) {
        go_to_row(next_row);
    }
    if (with_centering && (next_row.length === 0)) {
        // At the last message, scroll to the bottom so we have
        // lots of nice whitespace for new messages coming in.
        //
        // FIXME: this doesn't work for End because rows.last_visible()
        // always returns a message.
        var current_msg_table = rows.get_table(current_msg_list.table_name);
        message_viewport.scrollTop(current_msg_table.safeOuterHeight(true) -
                                   message_viewport.height() * 0.1);
        unread_ops.mark_current_list_as_read();
    }
};

exports.to_home = function () {
    message_viewport.last_movement_direction = -1;
    var first_id = current_msg_list.first().id;
    current_msg_list.select_id(first_id, {then_scroll: true,
                                          from_scroll: true});
};

exports.to_end = function () {
    var next_id = current_msg_list.last().id;
    message_viewport.last_movement_direction = 1;
    current_msg_list.select_id(next_id, {then_scroll: true,
                                         from_scroll: true});
    unread_ops.mark_current_list_as_read();
};

function amount_to_paginate() {
    // Some day we might have separate versions of this function
    // for Page Up vs. Page Down, but for now it's the same
    // strategy in either direction.
    var info = message_viewport.message_viewport_info();
    var page_size = info.visible_height;

    // We don't want to page up a full page, because Zulip users
    // are especially worried about missing messages, so we want
    // a little bit of the old page to stay on the screen.  The
    // value chosen here is roughly 2 or 3 lines of text, but there
    // is nothing sacred about it, and somebody more anal than me
    // might wish to tie this to the size of some particular DOM
    // element.
    var overlap_amount = 55;

    var delta = page_size - overlap_amount;

    // If the user has shrunk their browser a whole lot, pagination
    // is not going to be very pleasant, but we can at least
    // ensure they go in the right direction.
    if (delta < 1) {
        delta = 1;
    }

    return delta;
}

exports.page_up_the_right_amount = function () {
    // This function's job is to scroll up the right amount,
    // after the user hits Page Up.  We do this ourselves
    // because we can't rely on the browser to account for certain
    // page elements, like the compose box, that sit in fixed
    // positions above the message pane.  For other scrolling
    // related adjustements, try to make those happen in the
    // scroll handlers, not here.
    var delta = amount_to_paginate();
    message_viewport.scrollTop(message_viewport.scrollTop() - delta);
};

exports.page_down_the_right_amount = function () {
    // see also: page_up_the_right_amount
    var delta = amount_to_paginate();
    message_viewport.scrollTop(message_viewport.scrollTop() + delta);
};

exports.page_up = function () {
    if (message_viewport.at_top() && !current_msg_list.empty()) {
        current_msg_list.select_id(current_msg_list.first().id, {then_scroll: false});
    } else {
        exports.page_up_the_right_amount();
    }
};

exports.page_down = function () {
    if (message_viewport.at_bottom() && !current_msg_list.empty()) {
        current_msg_list.select_id(current_msg_list.last().id, {then_scroll: false});
        unread_ops.mark_current_list_as_read();
    } else {
        exports.page_down_the_right_amount();
    }
};

exports.scroll_to_selected = function () {
    var selected_row = current_msg_list.selected_row();
    if (selected_row && (selected_row.length !== 0)) {
        message_viewport.recenter_view(selected_row);
    }
};

exports.maybe_scroll_to_selected = function () {
    // If we have been previously instructed to re-center to the
    // selected message, then do so
    if (pointer.recenter_pointer_on_display) {
        exports.scroll_to_selected();
        pointer.recenter_pointer_on_display = false;
    }
};

return exports;
}());

if (typeof module !== 'undefined') {
    module.exports = navigate;
}
<commit_msg>navigate: Use msg_list.prev/next for up/down methods.<commit_after>var navigate = (function () {

var exports = {};

function go_to_row(msg_id) {
    current_msg_list.select_id(msg_id,
                               {then_scroll: true,
                                from_scroll: true});
}

exports.up = function () {
    message_viewport.last_movement_direction = -1;
    var msg_id = current_msg_list.prev();
    if (msg_id === undefined) {
        return;
    }
    go_to_row(msg_id);
};

exports.down = function (with_centering) {
    message_viewport.last_movement_direction = 1;
    var msg_id = current_msg_list.next();
    if (msg_id === undefined) {
        return;
    }
    go_to_row(msg_id);

    if (with_centering) {
        // At the last message, scroll to the bottom so we have
        // lots of nice whitespace for new messages coming in.
        //
        // FIXME: this doesn't work for End because rows.last_visible()
        // always returns a message.
        var current_msg_table = rows.get_table(current_msg_list.table_name);
        message_viewport.scrollTop(current_msg_table.safeOuterHeight(true) -
                                   message_viewport.height() * 0.1);
        unread_ops.mark_current_list_as_read();
    }
};

exports.to_home = function () {
    message_viewport.last_movement_direction = -1;
    var first_id = current_msg_list.first().id;
    current_msg_list.select_id(first_id, {then_scroll: true,
                                          from_scroll: true});
};

exports.to_end = function () {
    var next_id = current_msg_list.last().id;
    message_viewport.last_movement_direction = 1;
    current_msg_list.select_id(next_id, {then_scroll: true,
                                         from_scroll: true});
    unread_ops.mark_current_list_as_read();
};

function amount_to_paginate() {
    // Some day we might have separate versions of this function
    // for Page Up vs. Page Down, but for now it's the same
    // strategy in either direction.
    var info = message_viewport.message_viewport_info();
    var page_size = info.visible_height;

    // We don't want to page up a full page, because Zulip users
    // are especially worried about missing messages, so we want
    // a little bit of the old page to stay on the screen.  The
    // value chosen here is roughly 2 or 3 lines of text, but there
    // is nothing sacred about it, and somebody more anal than me
    // might wish to tie this to the size of some particular DOM
    // element.
    var overlap_amount = 55;

    var delta = page_size - overlap_amount;

    // If the user has shrunk their browser a whole lot, pagination
    // is not going to be very pleasant, but we can at least
    // ensure they go in the right direction.
    if (delta < 1) {
        delta = 1;
    }

    return delta;
}

exports.page_up_the_right_amount = function () {
    // This function's job is to scroll up the right amount,
    // after the user hits Page Up.  We do this ourselves
    // because we can't rely on the browser to account for certain
    // page elements, like the compose box, that sit in fixed
    // positions above the message pane.  For other scrolling
    // related adjustements, try to make those happen in the
    // scroll handlers, not here.
    var delta = amount_to_paginate();
    message_viewport.scrollTop(message_viewport.scrollTop() - delta);
};

exports.page_down_the_right_amount = function () {
    // see also: page_up_the_right_amount
    var delta = amount_to_paginate();
    message_viewport.scrollTop(message_viewport.scrollTop() + delta);
};

exports.page_up = function () {
    if (message_viewport.at_top() && !current_msg_list.empty()) {
        current_msg_list.select_id(current_msg_list.first().id, {then_scroll: false});
    } else {
        exports.page_up_the_right_amount();
    }
};

exports.page_down = function () {
    if (message_viewport.at_bottom() && !current_msg_list.empty()) {
        current_msg_list.select_id(current_msg_list.last().id, {then_scroll: false});
        unread_ops.mark_current_list_as_read();
    } else {
        exports.page_down_the_right_amount();
    }
};

exports.scroll_to_selected = function () {
    var selected_row = current_msg_list.selected_row();
    if (selected_row && (selected_row.length !== 0)) {
        message_viewport.recenter_view(selected_row);
    }
};

exports.maybe_scroll_to_selected = function () {
    // If we have been previously instructed to re-center to the
    // selected message, then do so
    if (pointer.recenter_pointer_on_display) {
        exports.scroll_to_selected();
        pointer.recenter_pointer_on_display = false;
    }
};

return exports;
}());

if (typeof module !== 'undefined') {
    module.exports = navigate;
}
<|endoftext|>


<commit_before>var overlays = (function () {

var exports = {};

var active_overlay;
var close_handler;
var open_overlay_name;

function reset_state() {
    active_overlay = undefined;
    close_handler = undefined;
    open_overlay_name = undefined;
}

exports.is_active = function () {
    return !!open_overlay_name;
};

exports.is_modal_open = function () {
    return $(".modal").hasClass("in");
};

exports.info_overlay_open = function () {
    return open_overlay_name === 'informationalOverlays';
};

exports.settings_open = function () {
    return open_overlay_name === 'settings';
};

exports.streams_open = function () {
    return open_overlay_name === 'subscriptions';
};

exports.lightbox_open = function () {
    return open_overlay_name === 'lightbox';
};

exports.drafts_open = function () {
    return open_overlay_name === 'drafts';
};

exports.active_modal = function () {
    if (!exports.is_modal_open()) {
        blueslip.error("Programming error — Called active_modal when there is no modal open");
        return;
    }
    return $(".modal.in").attr("id");
};

exports.open_overlay = function (opts) {
    popovers.hide_all();

    if (!opts.name || !opts.overlay || !opts.on_close) {
        blueslip.error('Programming error in open_overlay');
        return;
    }

    if (active_overlay || open_overlay_name || close_handler) {
        blueslip.error('Programming error — trying to open ' + opts.name +
            ' before closing ' + open_overlay_name);
        return;
    }

    blueslip.debug('open overlay: ' + opts.name);

    // Our overlays are kind of crufty...we have an HTML id
    // attribute for them and then a data-overlay attribute for
    // them.  Make sure they match.
    if (opts.overlay.attr('data-overlay') !== opts.name) {
        blueslip.error('Bad overlay setup for ' + opts.name);
        return;
    }

    open_overlay_name = opts.name;
    active_overlay = opts.overlay;
    opts.overlay.addClass('show');

    opts.overlay.attr("aria-hidden", "false");
    $('.app').attr("aria-hidden", "true");
    $('.fixed-app').attr("aria-hidden", "true");
    $('.header').attr("aria-hidden", "true");

    close_handler = function () {
        opts.on_close();
        reset_state();
    };
};

exports.open_modal = function (name) {
    if (name === undefined) {
        blueslip.error('Undefined name was passed into open_modal');
        return;
    }

    if (exports.is_modal_open()) {
        blueslip.error('open_modal() was called while ' + exports.active_modal() +
            ' modal was open.');
        return;
    }

    blueslip.debug('open modal: ' + name);

    $("#" + name).modal("show").attr("aria-hidden", false);
};

exports.close_overlay = function (name) {
    if (name !== open_overlay_name) {
        blueslip.error("Trying to close " + name + " when " + open_overlay_name + " is open.");
        return;
    }

    if (name === undefined) {
        blueslip.error('Undefined name was passed into close_overlay');
        return;
    }

    blueslip.debug('close overlay: ' + name);

    active_overlay.removeClass("show");

    active_overlay.attr("aria-hidden", "true");
    $('.app').attr("aria-hidden", "false");
    $('.fixed-app').attr("aria-hidden", "false");
    $('.header').attr("aria-hidden", "false");

    if (!close_handler) {
        blueslip.error("Overlay close handler for " + name + " not properly setup.");
        return;
    }

    close_handler();
};

exports.close_active = function () {
    if (!open_overlay_name) {
        blueslip.warn('close_active() called without checking is_active()');
        return;
    }

    exports.close_overlay(open_overlay_name);
};

exports.close_modal = function (name) {
    if (name === undefined) {
        blueslip.error('Undefined name was passed into close_modal');
        return;
    }

    if (!exports.is_modal_open()) {
        blueslip.warn('close_active_modal() called without checking is_modal_open()');
        return;
    }

    if (exports.active_modal() !== name) {
        blueslip.error("Trying to close " + name +
            " modal when " + exports.active_modal() + " is open.");
        return;
    }

    blueslip.debug('close modal: ' + name);

    $("#" + name).modal("hide").attr("aria-hidden", true);
};

exports.close_active_modal = function () {
    if (!exports.is_modal_open()) {
        blueslip.warn('close_active_modal() called without checking is_modal_open()');
        return;
    }

    $(".modal.in").modal("hide").attr("aria-hidden", true);
};

exports.close_for_hash_change = function () {
    $(".overlay.show").removeClass("show");
    reset_state();
};

exports.open_settings = function () {
    overlays.open_overlay({
        name: 'settings',
        overlay: $("#settings_overlay_container"),
        on_close: function () {
            hashchange.exit_overlay();
        },
    });
};

$(function () {
    $("body").on("click", ".overlay, .overlay .exit", function (e) {
        var $target = $(e.target);

        // if the target is not the .overlay element, search up the node tree
        // until it is found.
        if ($target.is(".exit, .exit-sign, .overlay-content, .exit span")) {
            $target = $target.closest("[data-overlay]");
        } else if (!$target.is(".overlay")) {
            // not a valid click target then.
            return;
        }

        var target_name = $target.attr("data-overlay");

        exports.close_overlay(target_name);

        e.preventDefault();
        e.stopPropagation();
    });
});

return exports;

}());

if (typeof module !== 'undefined') {
    module.exports = overlays;
}
<commit_msg>settings: When overlay modal opens, remove previous alert messages.<commit_after>var overlays = (function () {

var exports = {};

var active_overlay;
var close_handler;
var open_overlay_name;

function reset_state() {
    active_overlay = undefined;
    close_handler = undefined;
    open_overlay_name = undefined;
}

exports.is_active = function () {
    return !!open_overlay_name;
};

exports.is_modal_open = function () {
    return $(".modal").hasClass("in");
};

exports.info_overlay_open = function () {
    return open_overlay_name === 'informationalOverlays';
};

exports.settings_open = function () {
    return open_overlay_name === 'settings';
};

exports.streams_open = function () {
    return open_overlay_name === 'subscriptions';
};

exports.lightbox_open = function () {
    return open_overlay_name === 'lightbox';
};

exports.drafts_open = function () {
    return open_overlay_name === 'drafts';
};

exports.active_modal = function () {
    if (!exports.is_modal_open()) {
        blueslip.error("Programming error — Called active_modal when there is no modal open");
        return;
    }
    return $(".modal.in").attr("id");
};

exports.open_overlay = function (opts) {
    popovers.hide_all();

    if (!opts.name || !opts.overlay || !opts.on_close) {
        blueslip.error('Programming error in open_overlay');
        return;
    }

    if (active_overlay || open_overlay_name || close_handler) {
        blueslip.error('Programming error — trying to open ' + opts.name +
            ' before closing ' + open_overlay_name);
        return;
    }

    blueslip.debug('open overlay: ' + opts.name);

    // Our overlays are kind of crufty...we have an HTML id
    // attribute for them and then a data-overlay attribute for
    // them.  Make sure they match.
    if (opts.overlay.attr('data-overlay') !== opts.name) {
        blueslip.error('Bad overlay setup for ' + opts.name);
        return;
    }

    open_overlay_name = opts.name;
    active_overlay = opts.overlay;
    opts.overlay.addClass('show');

    opts.overlay.attr("aria-hidden", "false");
    $('.app').attr("aria-hidden", "true");
    $('.fixed-app').attr("aria-hidden", "true");
    $('.header').attr("aria-hidden", "true");

    close_handler = function () {
        opts.on_close();
        reset_state();
    };
};

exports.open_modal = function (name) {
    if (name === undefined) {
        blueslip.error('Undefined name was passed into open_modal');
        return;
    }

    if (exports.is_modal_open()) {
        blueslip.error('open_modal() was called while ' + exports.active_modal() +
            ' modal was open.');
        return;
    }

    blueslip.debug('open modal: ' + name);

    $("#" + name).modal("show").attr("aria-hidden", false);
    // Remove previous alert messsages from modal, if exists.
    $("#" + name).find(".alert").hide();
};

exports.close_overlay = function (name) {
    if (name !== open_overlay_name) {
        blueslip.error("Trying to close " + name + " when " + open_overlay_name + " is open.");
        return;
    }

    if (name === undefined) {
        blueslip.error('Undefined name was passed into close_overlay');
        return;
    }

    blueslip.debug('close overlay: ' + name);

    active_overlay.removeClass("show");

    active_overlay.attr("aria-hidden", "true");
    $('.app').attr("aria-hidden", "false");
    $('.fixed-app').attr("aria-hidden", "false");
    $('.header').attr("aria-hidden", "false");

    if (!close_handler) {
        blueslip.error("Overlay close handler for " + name + " not properly setup.");
        return;
    }

    close_handler();
};

exports.close_active = function () {
    if (!open_overlay_name) {
        blueslip.warn('close_active() called without checking is_active()');
        return;
    }

    exports.close_overlay(open_overlay_name);
};

exports.close_modal = function (name) {
    if (name === undefined) {
        blueslip.error('Undefined name was passed into close_modal');
        return;
    }

    if (!exports.is_modal_open()) {
        blueslip.warn('close_active_modal() called without checking is_modal_open()');
        return;
    }

    if (exports.active_modal() !== name) {
        blueslip.error("Trying to close " + name +
            " modal when " + exports.active_modal() + " is open.");
        return;
    }

    blueslip.debug('close modal: ' + name);

    $("#" + name).modal("hide").attr("aria-hidden", true);
};

exports.close_active_modal = function () {
    if (!exports.is_modal_open()) {
        blueslip.warn('close_active_modal() called without checking is_modal_open()');
        return;
    }

    $(".modal.in").modal("hide").attr("aria-hidden", true);
};

exports.close_for_hash_change = function () {
    $(".overlay.show").removeClass("show");
    reset_state();
};

exports.open_settings = function () {
    overlays.open_overlay({
        name: 'settings',
        overlay: $("#settings_overlay_container"),
        on_close: function () {
            hashchange.exit_overlay();
        },
    });
};

$(function () {
    $("body").on("click", ".overlay, .overlay .exit", function (e) {
        var $target = $(e.target);

        // if the target is not the .overlay element, search up the node tree
        // until it is found.
        if ($target.is(".exit, .exit-sign, .overlay-content, .exit span")) {
            $target = $target.closest("[data-overlay]");
        } else if (!$target.is(".overlay")) {
            // not a valid click target then.
            return;
        }

        var target_name = $target.attr("data-overlay");

        exports.close_overlay(target_name);

        e.preventDefault();
        e.stopPropagation();
    });
});

return exports;

}());

if (typeof module !== 'undefined') {
    module.exports = overlays;
}
<|endoftext|>


<commit_before>/* Copyright 2012 The Go Authors.   All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 */
'use strict';

/* Services */

angular.module('tour.services', []).

// Google Analytics
factory('analytics', ['$window',
    function(win) {
        var track = win.trackPageview || (function() {});
        return {
            trackView: track
        };
    }
]).

// Internationalization
factory('i18n', ['translation',
    function(translation) {
        return {
            l: function(key) {
                if (translation[key]) return translation[key];
                return '(no translation for ' + key + ')';
            }
        };
    }
]).

// Running code
factory('run', ['$window', 'editor',
    function(win, editor) {
        var writeInterceptor = function(writer) {
            return function(write) {
                if (write.Kind == 'stderr') {
                    var lines = write.Body.split('\n');
                    for (var i in lines) {
                        var match = lines[i].match(/.*\.go:([0-9]+): ([^\n]*)/);
                        if (match !== null) {
                            editor.highlight(match[1], match[2]);
                        }
                    }
                }
                writer(write);
            };
        };
        return function(code, output, options) {
            // PlaygroundOutput is defined in playground.js which is prepended
            // to the generated script.js in gotour/tour.go.
            // The next line removes the jshint warning.
            // global PlaygroundOutput
            win.transport.Run(code, writeInterceptor(PlaygroundOutput(output)), options);
        };
    }
]).

// Formatting code
factory('fmt', ['$http',
    function($http) {
        return function(body) {
            var params = $.param({
                'body': body
            });
            var headers = {
                'Content-Type': 'application/x-www-form-urlencoded'
            };
            return $http.post('/fmt', params, {
                headers: headers
            });
        };
    }
]).

// Local storage, persistent to page refreshing.
factory('storage', ['$window',
    function(win) {
        if (win.localStorage) {
            return {
                get: function(key) {
                    return win.localStorage.getItem(key);
                },
                set: function(key, val) {
                    win.localStorage.setItem(key, val);
                }
            };
        }
        return {
            get: function() {
                return null;
            },
            set: function() {}
        };
    }
]).

// Editor context service, kept through the whole app.
factory('editor', ['$window', 'storage',
    function(win, storage) {
        var ctx = {
            syntax: storage.get('syntax') === 'true',
            toggleSyntax: function() {
                ctx.syntax = !ctx.syntax;
                storage.set('syntax', ctx.syntax);
                ctx.paint();
            },
            paint: function() {
                var mode = ctx.syntax && 'text/x-go' || 'text/x-go-comment';
                // Wait for codemirror to start.
                var set = function() {
                    if ($('.CodeMirror').length > 0) {
                        var cm = $('.CodeMirror')[0].CodeMirror;
                        if (cm.getOption('mode') == mode) {
                            cm.refresh();
                            return;
                        }
                        cm.setOption('mode', mode);
                    }
                    win.setTimeout(set, 10);
                };
                set();
            },
            highlight: function(line, message) {
                $('.CodeMirror-code > div:nth-child(' + line + ')')
                    .addClass('line-error').attr('title', message);
            },
            onChange: function() {
                $('.line-error').removeClass('line-error').attr('title', null);
            }
        };
        // Set in the window so the onChange function in the codemirror config
        // can call it.
        win.codeChanged = ctx.onChange;
        return ctx;
    }
]).

// Table of contents management and navigation
factory('toc', ['$http', '$q', '$log', 'tableOfContents', 'storage',
    function($http, $q, $log, tableOfContents, storage) {
        var modules = tableOfContents;

        var lessons = {};

        var prevLesson = function(id) {
            var mod = lessons[id].module;
            var idx = mod.lessons.indexOf(id);
            if (idx < 0) return '';
            if (idx > 0) return mod.lessons[idx - 1];

            idx = modules.indexOf(mod);
            if (idx <= 0) return '';
            mod = modules[idx - 1];
            return mod.lessons[mod.lessons.length - 1];
        };

        var nextLesson = function(id) {
            var mod = lessons[id].module;
            var idx = mod.lessons.indexOf(id);
            if (idx < 0) return '';
            if (idx + 1 < mod.lessons.length) return mod.lessons[idx + 1];

            idx = modules.indexOf(mod);
            if (idx < 0 || modules.length <= idx + 1) return '';
            mod = modules[idx + 1];
            return mod.lessons[0];
        };

        $http.get('/lesson/').then(
            function(data) {
                lessons = data.data;
                for (var m = 0; m < modules.length; m++) {
                    var module = modules[m];
                    module.lesson = {};
                    for (var l = 0; l < modules[m].lessons.length; l++) {
                        var lessonName = module.lessons[l];
                        var lesson = lessons[lessonName];
                        lesson.module = module;
                        module.lesson[lessonName] = lesson;

                        // replace file contents with locally stored copies.
                        for (var p = 0; p < lesson.Pages.length; p++) {
                            var page = lesson.Pages[p];
                            for (var f = 0; f < page.Files.length; f++) {
                                page.Files[f].OrigContent = page.Files[f].Content;
                                var val = storage.get(lessonName + '.' + p + '.' + f);
                                if (val !== null) {
                                    page.Files[f].Content = val;
                                }
                            }
                        }
                    }
                }
                moduleQ.resolve(modules);
                lessonQ.resolve(lessons);
            },
            function(error) {
                $log.error('error loading lessons : ', error);
                moduleQ.reject(error);
                lessonQ.reject(error);
            }
        );

        var moduleQ = $q.defer();
        var lessonQ = $q.defer();

        return {
            modules: moduleQ.promise,
            lessons: lessonQ.promise,
            prevLesson: prevLesson,
            nextLesson: nextLesson
        };
    }
]);
<commit_msg>go-tour: handle disabled cookies graciously<commit_after>/* Copyright 2012 The Go Authors.   All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 */
'use strict';

/* Services */

angular.module('tour.services', []).

// Google Analytics
factory('analytics', ['$window',
    function(win) {
        var track = win.trackPageview || (function() {});
        return {
            trackView: track
        };
    }
]).

// Internationalization
factory('i18n', ['translation',
    function(translation) {
        return {
            l: function(key) {
                if (translation[key]) return translation[key];
                return '(no translation for ' + key + ')';
            }
        };
    }
]).

// Running code
factory('run', ['$window', 'editor',
    function(win, editor) {
        var writeInterceptor = function(writer) {
            return function(write) {
                if (write.Kind == 'stderr') {
                    var lines = write.Body.split('\n');
                    for (var i in lines) {
                        var match = lines[i].match(/.*\.go:([0-9]+): ([^\n]*)/);
                        if (match !== null) {
                            editor.highlight(match[1], match[2]);
                        }
                    }
                }
                writer(write);
            };
        };
        return function(code, output, options) {
            // PlaygroundOutput is defined in playground.js which is prepended
            // to the generated script.js in gotour/tour.go.
            // The next line removes the jshint warning.
            // global PlaygroundOutput
            win.transport.Run(code, writeInterceptor(PlaygroundOutput(output)), options);
        };
    }
]).

// Formatting code
factory('fmt', ['$http',
    function($http) {
        return function(body) {
            var params = $.param({
                'body': body
            });
            var headers = {
                'Content-Type': 'application/x-www-form-urlencoded'
            };
            return $http.post('/fmt', params, {
                headers: headers
            });
        };
    }
]).

// Local storage, persistent to page refreshing.
factory('storage', ['$window',
    function(win) {
        try {
            // This will raise an exception if cookies are disabled.
            win.localStorage = win.localStorage;
            return {
                get: function(key) {
                    return win.localStorage.getItem(key);
                },
                set: function(key, val) {
                    win.localStorage.setItem(key, val);
                }
            };
        } catch (e) {
            return {
                get: function() {
                    return null;
                },
                set: function() {}
            };
        }
    }
]).

// Editor context service, kept through the whole app.
factory('editor', ['$window', 'storage',
    function(win, storage) {
        var ctx = {
            syntax: storage.get('syntax') === 'true',
            toggleSyntax: function() {
                ctx.syntax = !ctx.syntax;
                storage.set('syntax', ctx.syntax);
                ctx.paint();
            },
            paint: function() {
                var mode = ctx.syntax && 'text/x-go' || 'text/x-go-comment';
                // Wait for codemirror to start.
                var set = function() {
                    if ($('.CodeMirror').length > 0) {
                        var cm = $('.CodeMirror')[0].CodeMirror;
                        if (cm.getOption('mode') == mode) {
                            cm.refresh();
                            return;
                        }
                        cm.setOption('mode', mode);
                    }
                    win.setTimeout(set, 10);
                };
                set();
            },
            highlight: function(line, message) {
                $('.CodeMirror-code > div:nth-child(' + line + ')')
                    .addClass('line-error').attr('title', message);
            },
            onChange: function() {
                $('.line-error').removeClass('line-error').attr('title', null);
            }
        };
        // Set in the window so the onChange function in the codemirror config
        // can call it.
        win.codeChanged = ctx.onChange;
        return ctx;
    }
]).

// Table of contents management and navigation
factory('toc', ['$http', '$q', '$log', 'tableOfContents', 'storage',
    function($http, $q, $log, tableOfContents, storage) {
        var modules = tableOfContents;

        var lessons = {};

        var prevLesson = function(id) {
            var mod = lessons[id].module;
            var idx = mod.lessons.indexOf(id);
            if (idx < 0) return '';
            if (idx > 0) return mod.lessons[idx - 1];

            idx = modules.indexOf(mod);
            if (idx <= 0) return '';
            mod = modules[idx - 1];
            return mod.lessons[mod.lessons.length - 1];
        };

        var nextLesson = function(id) {
            var mod = lessons[id].module;
            var idx = mod.lessons.indexOf(id);
            if (idx < 0) return '';
            if (idx + 1 < mod.lessons.length) return mod.lessons[idx + 1];

            idx = modules.indexOf(mod);
            if (idx < 0 || modules.length <= idx + 1) return '';
            mod = modules[idx + 1];
            return mod.lessons[0];
        };

        $http.get('/lesson/').then(
            function(data) {
                lessons = data.data;
                for (var m = 0; m < modules.length; m++) {
                    var module = modules[m];
                    module.lesson = {};
                    for (var l = 0; l < modules[m].lessons.length; l++) {
                        var lessonName = module.lessons[l];
                        var lesson = lessons[lessonName];
                        lesson.module = module;
                        module.lesson[lessonName] = lesson;

                        // replace file contents with locally stored copies.
                        for (var p = 0; p < lesson.Pages.length; p++) {
                            var page = lesson.Pages[p];
                            for (var f = 0; f < page.Files.length; f++) {
                                page.Files[f].OrigContent = page.Files[f].Content;
                                var val = storage.get(lessonName + '.' + p + '.' + f);
                                if (val !== null) {
                                    page.Files[f].Content = val;
                                }
                            }
                        }
                    }
                }
                moduleQ.resolve(modules);
                lessonQ.resolve(lessons);
            },
            function(error) {
                $log.error('error loading lessons : ', error);
                moduleQ.reject(error);
                lessonQ.reject(error);
            }
        );

        var moduleQ = $q.defer();
        var lessonQ = $q.defer();

        return {
            modules: moduleQ.promise,
            lessons: lessonQ.promise,
            prevLesson: prevLesson,
            nextLesson: nextLesson
        };
    }
]);
<|endoftext|>