<commit_before>/* export Navigation */

import API from './API'
import services from './Services'
import Modal from './Modal/Instance';
import Search from './Navigation/Search';
import Section from './Navigation/Section';
import Sorting from './Navigation/Sorting';

class Navigation {

    /**
     * Construct Navigation
     * @return {Navigation}
     */
    constructor(adminController) {
        this.adminController = adminController;
        this.sections = [];
        this.init();
    }

    // --------------------------------------------------------------------------

    /**
     * Initialises admin navigation
     */
    init() {

        this
            .initBoxes()
            .initSorting()
            .initSearching()
            .initButtons()
            .enableAnimation();
    }

    // --------------------------------------------------------------------------

    /**
     * Initialises sidebar boxes
     * @returns {Navigation}
     */
    initBoxes() {
        document
            .querySelectorAll('.sidebar > ul.modules > li.module')
            .forEach((element) => {
                this.sections.push({
                    'element': element,
                    'instance': new Section(this, element)
                });
            });

        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Initialises sidebar sorting
     * @returns {Navigation}
     */
    initSorting() {
        this.sorting = new Sorting(this);
        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Initialises sidebar searching
     * @returns {Navigation}
     */
    initSearching() {
        this.search = new Search(
            this,
            document.querySelector('.sidebar > .nav-search > input')
        );
        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Initialises sidebar action buttons
     * @returns {Navigation}
     */
    initButtons() {

        let buttons = document.getElementById('admin-nav-reset-buttons');
        buttons.querySelector('a[data-action=reset]')
            .addEventListener('click', (e) => {
                e.preventDefault();
                this.resetNav();
            });

        buttons.querySelector('a[data-action=open]')
            .addEventListener('click', (e) => {
                e.preventDefault();
                this.openAll();
            });

        buttons.querySelector('a[data-action=close]')
            .addEventListener('click', (e) => {
                e.preventDefault();
                this.closeAll();
            });

        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Saves the sidebar's state
     * @returns {Navigation}
     */
    saveState() {
        clearTimeout(this.debounceSave);
        this.debounceSave = setTimeout(() => {
            this.adminController.log('🔄 Saving State...');

            let config = {};
            let order = 0;
            let sections = document.querySelectorAll('.sidebar > ul.modules > li.sortable');
            sections.forEach((element) => {
                this.sections.forEach((section) => {
                    if (section.element === element) {
                        config[section.element.dataset['grouping']] = {
                            open: section.instance.isOpen(),
                            order: order++,
                        }
                    }
                })
            });

            services
                .apiRequest({
                    method: 'post',
                    url: API.navigation.save,
                    data: {
                        preferences: config
                    }
                })
                .catch(() => {
                    this.adminController.error('😵 failed!');
                })
                .then(() => {
                    this.adminController.log('👍 done!');
                });

        }, 1000);

        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Resets the sidebar to its default state
     * @returns {Navigation}
     */
    resetNav() {

        services.apiRequest({
            method: 'post',
            url: API.navigation.reset,
        });

        let modal = (new Modal(this.adminController));
        let p1 = document.createElement('p');
        let p2 = document.createElement('p');
        let btnClose = document.createElement('button');
        let btnReload = document.createElement('button');

        p2.append(btnClose);
        p2.append(btnReload);

        p1.innerText = 'Your navigation has been reset, changes will take hold on the next page load.';

        btnClose.innerText = 'Close';
        btnClose.style.marginRight = '0.5em';
        btnClose.classList.add('btn', 'btn-primary');
        btnClose.addEventListener('click', (e) => {
            e.preventDefault();
            modal.hide();
            modal.container.remove();
        })

        btnReload.innerText = 'Reload';
        btnReload.classList.add('btn', 'btn-default');
        btnReload.addEventListener('click', (e) => {
            e.preventDefault();
            window.location.reload();
        });

        modal
            .setTitle('Reset complete')
            .setBody([p1, p2])
            .show();

        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Opens all the sidebar sections
     * @returns {Navigation}
     */
    openAll() {
        this.disableAnimation();
        this.sections
            .forEach((section) => {
                section.instance.open();
            });
        this.saveState();
        this.enableAnimation();

        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Closes all the sidebar sections
     * @returns {Navigation}
     */
    closeAll() {
        this.disableAnimation();
        this.sections
            .forEach((section) => {
                section.instance.close();
            });
        this.saveState();
        this.enableAnimation();

        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Enables sidebar animation
     * Uses a set timeout so that we don't animate things we think should not be animating
     * @returns {Navigation}
     */
    enableAnimation() {
        clearTimeout(this.enableAnimationTimeout);
        this.enableAnimationTimeout = setTimeout(() => {
            document.querySelector('.sidebar > ul.modules')
                .classList.add('animate');
        }, 1000);
        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Disables sidebar animations
     * @returns {Navigation}
     */
    disableAnimation() {
        clearTimeout(this.enableAnimationTimeout);
        document.querySelector('.sidebar > ul.modules')
            .classList.remove('animate');
        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Enable sidebar sorting
     * @returns {Navigation}
     */
    enableSorting() {
        document.querySelectorAll('.sidebar li.module .ui-sortable-handle')
            .forEach((element) => {
                element.classList.remove('hidden');
            });
        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Disables sidebar sorting
     * @returns {Navigation}
     */
    disableSorting() {
        document.querySelectorAll('.sidebar li.module .ui-sortable-handle')
            .forEach((element) => {
                element.classList.add('hidden');
            });
        return this;
    }
}

export default Navigation;
<commit_msg>Include all sidebar elements when saving navigation state<commit_after>/* export Navigation */

import API from './API'
import services from './Services'
import Modal from './Modal/Instance';
import Search from './Navigation/Search';
import Section from './Navigation/Section';
import Sorting from './Navigation/Sorting';

class Navigation {

    /**
     * Construct Navigation
     * @return {Navigation}
     */
    constructor(adminController) {
        this.adminController = adminController;
        this.sections = [];
        this.init();
    }

    // --------------------------------------------------------------------------

    /**
     * Initialises admin navigation
     */
    init() {

        this
            .initBoxes()
            .initSorting()
            .initSearching()
            .initButtons()
            .enableAnimation();
    }

    // --------------------------------------------------------------------------

    /**
     * Initialises sidebar boxes
     * @returns {Navigation}
     */
    initBoxes() {
        document
            .querySelectorAll('.sidebar > ul.modules > li.module')
            .forEach((element) => {
                this.sections.push({
                    'element': element,
                    'instance': new Section(this, element)
                });
            });

        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Initialises sidebar sorting
     * @returns {Navigation}
     */
    initSorting() {
        this.sorting = new Sorting(this);
        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Initialises sidebar searching
     * @returns {Navigation}
     */
    initSearching() {
        this.search = new Search(
            this,
            document.querySelector('.sidebar > .nav-search > input')
        );
        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Initialises sidebar action buttons
     * @returns {Navigation}
     */
    initButtons() {

        let buttons = document.getElementById('admin-nav-reset-buttons');
        buttons.querySelector('a[data-action=reset]')
            .addEventListener('click', (e) => {
                e.preventDefault();
                this.resetNav();
            });

        buttons.querySelector('a[data-action=open]')
            .addEventListener('click', (e) => {
                e.preventDefault();
                this.openAll();
            });

        buttons.querySelector('a[data-action=close]')
            .addEventListener('click', (e) => {
                e.preventDefault();
                this.closeAll();
            });

        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Saves the sidebar's state
     * @returns {Navigation}
     */
    saveState() {
        clearTimeout(this.debounceSave);
        this.debounceSave = setTimeout(() => {
            this.adminController.log('🔄 Saving State...');

            let config = {};
            let order = 0;
            let sections = document.querySelectorAll('.sidebar > ul.modules > li');
            sections.forEach((element) => {
                this.sections.forEach((section) => {
                    if (section.element === element) {
                        config[section.element.dataset['grouping']] = {
                            open: section.instance.isOpen(),
                            order: order++,
                        }
                    }
                })
            });

            services
                .apiRequest({
                    method: 'post',
                    url: API.navigation.save,
                    data: {
                        preferences: config
                    }
                })
                .catch(() => {
                    this.adminController.error('😵 failed!');
                })
                .then(() => {
                    this.adminController.log('👍 done!');
                });

        }, 1000);

        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Resets the sidebar to its default state
     * @returns {Navigation}
     */
    resetNav() {

        services.apiRequest({
            method: 'post',
            url: API.navigation.reset,
        });

        let modal = (new Modal(this.adminController));
        let p1 = document.createElement('p');
        let p2 = document.createElement('p');
        let btnClose = document.createElement('button');
        let btnReload = document.createElement('button');

        p2.append(btnClose);
        p2.append(btnReload);

        p1.innerText = 'Your navigation has been reset, changes will take hold on the next page load.';

        btnClose.innerText = 'Close';
        btnClose.style.marginRight = '0.5em';
        btnClose.classList.add('btn', 'btn-primary');
        btnClose.addEventListener('click', (e) => {
            e.preventDefault();
            modal.hide();
            modal.container.remove();
        })

        btnReload.innerText = 'Reload';
        btnReload.classList.add('btn', 'btn-default');
        btnReload.addEventListener('click', (e) => {
            e.preventDefault();
            window.location.reload();
        });

        modal
            .setTitle('Reset complete')
            .setBody([p1, p2])
            .show();

        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Opens all the sidebar sections
     * @returns {Navigation}
     */
    openAll() {
        this.disableAnimation();
        this.sections
            .forEach((section) => {
                section.instance.open();
            });
        this.saveState();
        this.enableAnimation();

        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Closes all the sidebar sections
     * @returns {Navigation}
     */
    closeAll() {
        this.disableAnimation();
        this.sections
            .forEach((section) => {
                section.instance.close();
            });
        this.saveState();
        this.enableAnimation();

        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Enables sidebar animation
     * Uses a set timeout so that we don't animate things we think should not be animating
     * @returns {Navigation}
     */
    enableAnimation() {
        clearTimeout(this.enableAnimationTimeout);
        this.enableAnimationTimeout = setTimeout(() => {
            document.querySelector('.sidebar > ul.modules')
                .classList.add('animate');
        }, 1000);
        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Disables sidebar animations
     * @returns {Navigation}
     */
    disableAnimation() {
        clearTimeout(this.enableAnimationTimeout);
        document.querySelector('.sidebar > ul.modules')
            .classList.remove('animate');
        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Enable sidebar sorting
     * @returns {Navigation}
     */
    enableSorting() {
        document.querySelectorAll('.sidebar li.module .ui-sortable-handle')
            .forEach((element) => {
                element.classList.remove('hidden');
            });
        return this;
    }

    // --------------------------------------------------------------------------

    /**
     * Disables sidebar sorting
     * @returns {Navigation}
     */
    disableSorting() {
        document.querySelectorAll('.sidebar li.module .ui-sortable-handle')
            .forEach((element) => {
                element.classList.add('hidden');
            });
        return this;
    }
}

export default Navigation;
<|endoftext|>


<commit_before>import { _ } from 'meteor/underscore';
import { UserRoles } from './userroles';
import { Minutes } from './minutes';

import {AttachmentsCollection} from './collections/attachments_private';

export class Attachment {
    constructor(attachmentID) {
        this._roles = new UserRoles(this.userId);
        if (!this._roles) {
            console.log('Could not retrieve roles for ', this.userId);
        }
        this._file = AttachmentsCollection.findOne(attachmentID);
        if (!this._file) {
            throw new Error('Attachment(): Could not retrieve attachment for ID '+attachmentID);
        }
    }

    // ********** static methods ****************
    static findForMinutes(minID) {
        return AttachmentsCollection.find({'meta.meetingminutes_id': minID});
    }

    static countAll() {
        return AttachmentsCollection.find().count();
    }

    static countForMinutes(minID) {
        return Attachment.findForMinutes(minID).count();
    }

    static countAllBytes() {
        let atts = AttachmentsCollection.find({}, {size: 1});
        let sumBytes = 0;
        atts.forEach((att) => {
            sumBytes += att.size;
        });
        return sumBytes;
    }

    static uploadFile(uploadFilename, minutesObj, callbacks = {}) {
        let doNothing = () => {};
        callbacks = _.extend({
            onStart: doNothing,
            onEnd: doNothing,
            onAbort: doNothing
        }, callbacks);

        let upload = AttachmentsCollection.insert({
            file: uploadFilename,
            streams: 'dynamic',
            chunkSize: 'dynamic',
            meta: {
                meetingminutes_id: minutesObj._id,
                parentseries_id: minutesObj.parentMeetingSeriesID()
            }
        }, false);

        upload.on('start', function () {
            callbacks.onStart(this);    // this == current upload object
        });
        upload.on('end', function (error, fileObj) {
            callbacks.onEnd(error, fileObj);
        });
        upload.on('abort', function (error, fileObj) {
            callbacks.onAbort(error, fileObj);
        });

        upload.start();
    }

    // ********** object methods ****************
    isUploaderAndFileOwner () {
        return this._roles.isUploaderFor(this._file.meta.parentseries_id)
            && (this._roles.getUserID() === this._file.userId);
    }

    isModerator () {
        return this._roles.isModeratorOf(this._file.meta.parentseries_id);
    }

    /**
     * Checks if:
     * - meeting is not finalized and
     * - user is either (moderator) or (uploader & file owner)
     * @returns {boolean}
     */
    mayRemove () {
        const min = new Minutes(this._file.meta.meetingminutes_id);
        if (min.isFinalized) {
            return false;
        }
        return (this.isUploaderAndFileOwner() || this.isModerator());
    }
}
<commit_msg>Fix: Try to fix #285<commit_after>import { _ } from 'meteor/underscore';
import { UserRoles } from './userroles';
import { Minutes } from './minutes';

import {AttachmentsCollection} from './collections/attachments_private';

export class Attachment {
    constructor(attachmentID) {
        this._roles = new UserRoles(this.userId);
        if (!this._roles) {
            console.log('Could not retrieve roles for ', this.userId);
        }
        this._file = AttachmentsCollection.findOne(attachmentID);
        if (!this._file) {
            throw new Error('Attachment(): Could not retrieve attachment for ID '+attachmentID);
        }
    }

    // ********** static methods ****************
    static findForMinutes(minID) {
        return AttachmentsCollection.find({'meta.meetingminutes_id': minID});
    }

    static countAll() {
        return AttachmentsCollection.find().count();
    }

    static countForMinutes(minID) {
        return Attachment.findForMinutes(minID).count();
    }

    static countAllBytes() {
        let atts = AttachmentsCollection.find({}, {size: 1});
        let sumBytes = 0;
        atts.forEach((att) => {
            sumBytes += att.size;
        });
        return sumBytes;
    }

    static uploadFile(uploadFilename, minutesObj, callbacks = {}) {
        let doNothing = () => {};
        callbacks = _.extend({
            onStart: doNothing,
            onEnd: doNothing,
            onAbort: doNothing
        }, callbacks);

        let upload = AttachmentsCollection.insert({
            file: uploadFilename,
            streams: 1,
            chunkSize: 'dynamic',
            meta: {
                meetingminutes_id: minutesObj._id,
                parentseries_id: minutesObj.parentMeetingSeriesID()
            }
        }, false);

        upload.on('start', function () {
            callbacks.onStart(this);    // this == current upload object
        });
        upload.on('end', function (error, fileObj) {
            callbacks.onEnd(error, fileObj);
        });
        upload.on('abort', function (error, fileObj) {
            callbacks.onAbort(error, fileObj);
        });

        upload.start();
    }

    // ********** object methods ****************
    isUploaderAndFileOwner () {
        return this._roles.isUploaderFor(this._file.meta.parentseries_id)
            && (this._roles.getUserID() === this._file.userId);
    }

    isModerator () {
        return this._roles.isModeratorOf(this._file.meta.parentseries_id);
    }

    /**
     * Checks if:
     * - meeting is not finalized and
     * - user is either (moderator) or (uploader & file owner)
     * @returns {boolean}
     */
    mayRemove () {
        const min = new Minutes(this._file.meta.meetingminutes_id);
        if (min.isFinalized) {
            return false;
        }
        return (this.isUploaderAndFileOwner() || this.isModerator());
    }
}
<|endoftext|>


<commit_before>
/* géolocalisation HTML5 */
var currentRoleLoc = "";
function initHTML5Localisation(role){
	if (navigator.geolocation)
	{
	  navigator.geolocation.getCurrentPosition(
		function(position){ //success
		    mapBg.panTo([position.coords.latitude, position.coords.longitude], {animate:false});
		    mapBg.setZoom(13, {animate:false});

		    toastr.info("Votre position géographique a été trouvée");
		    currentRoleLoc = role;
		    getCityInseeByGeoPos(position.coords);
		},
		function (error){	//error
			var info = "Erreur lors de la géolocalisation : ";
		    switch(error.code) {
			    case error.TIMEOUT:
			    	info += "Timeout !";
			    break;
			    case error.PERMISSION_DENIED:
			    info += "Vous n’avez pas donné la permission";
			    break;
			    case error.POSITION_UNAVAILABLE:
			    	info += "La position n’a pu être déterminée";
			    break;
			    case error.UNKNOWN_ERROR:
			    	info += "Erreur inconnue";
			    break;
			}
			toastr.error(info);
		});
	}
	else{
	  toastr.error("Votre navigateur ne prend pas en compte la géolocalisation HTML5");
	}
}

function getCityInseeByGeoPos(coords){
	toastr.info(" Recherche des données de votre commune");
	$.ajax({
		url: baseUrl + "/" + moduleId+"/sig/getinseebylatlng",
		type: 'POST',
		dataType: 'json',
		data:{"latitude" : coords.latitude, "longitude" : coords.longitude },
		complete: function () {},
		success: function (obj) {
			if (obj != null && obj.length > 0) {
				if(currentRoleLoc == "showCity" && typeof obj.insee != "undefined"){
					toastr.success("Vous allez être redirigé vers la page de votre commune ...");
					showAjaxPanel("/city/detail/insee/" + obj.insee + "?isNotSV=1", 'Details', 'university');
				}
				else if(currentRoleLoc == "prefill" && typeof obj.cp != "undefined"){
					toastr.success("Nous avons trouvé votre code postal : "+obj.cp);
					$(".form-group #cp").val(obj.cp);
					searchCity();
				}
			}else{
				getCityByLatLngNominatim(coords.latitude, coords.longitude);
			}
		},
		error: function (error) {
			console.dir(error);
			toastr.error(error.responseText);
		}
	});
}

//reverse geocoding
function getCityByLatLngNominatim(latitude, longitude){
	console.log(latitude, longitude);
	toastr.info(" Recherche approfondie");
	$.ajax({
		url: "//nominatim.openstreetmap.org/reverse?lat=" + latitude + "&lon=" + longitude + "&format=json&addressdetails=1",
		type: 'POST',
		dataType: 'json',
		complete: function () { },
		success: function (obj)
		{
			if(typeof obj.address.city != "undefined")		{ getInseeByCityName(obj.address.city);
			}else if(typeof obj.address.town != "undefined"){ getInseeByCityName(obj.address.town);
			}else{ toastr.error("Impossible de trouver le nom de votre commune"); }
		},
		error: function(error){
			console.dir("error", error);
		}
	});
}

function getInseeByCityName(cityName){
	toastr.info(" Merci de patienter ...");
	$.ajax({
		url: baseUrl + "/" + moduleId+"/sig/getcodeinseebycityname",
		type: 'POST',
		dataType: 'json',
		contentType: "application/x-www-form-urlencoded; charset=UTF-8",
		data:{ "cityName" : cityName },
		complete: function () { },
		success: function (obj)
		{
			console.log("getInseeByCityName ok");
			console.dir(obj);

			if (typeof obj != "undefined"){
				if (currentRoleLoc == "showCity"){
					if(typeof obj.insee != "undefined") {
						toastr.success(" Vous allez être redirigé vers la page de votre commune ... ");
						showAjaxPanel("/city/detail/insee/" + obj.insee + "?isNotSV=1", 'Details', 'university');
					}else{
						toastr.error("Impossible d'identifier votre commune ... ");
					}
				}
				else if (currentRoleLoc == "prefill"){
					if(typeof obj.cp != "undefined") {
						toastr.success("Nous avons trouvé votre code postal : "+obj.cp);
						$(".form-group #cp").val(obj.cp);
						searchCity();
					}else{
						toastr.error("Impossible d'identifier votre commune ... ");
					}
				}
			}
		},
		error: function(error){
			toastr.error("Erreur : Impossible d'identifier votre commune ... ");
		}
	});
}
/* géolocalisation HTML5 */<commit_msg>info localisationHtml5<commit_after>
/* géolocalisation HTML5 */
var currentRoleLoc = "";
function initHTML5Localisation(role){
	if (navigator.geolocation)
	{
	  navigator.geolocation.getCurrentPosition(
		function(position){ //success

			// var position = {
			// 		coords : {
			// 		 latitude : -20.9190923,
			// 		 longitude : 55.4859363
			// 		}
			// 	};
			// console.log(position.coords);
		    mapBg.panTo([position.coords.latitude, position.coords.longitude], {animate:false});
		    mapBg.setZoom(13, {animate:false});

		    toastr.info("Votre position géographique a été trouvée");
		    currentRoleLoc = role;
		    getCityInseeByGeoPos(position.coords);
		},
		function (error){	//error
			var info = "Erreur lors de la géolocalisation : ";
		    switch(error.code) {
			    case error.TIMEOUT:
			    	info += "Timeout !";
			    break;
			    case error.PERMISSION_DENIED:
			    info += "Vous n’avez pas donné la permission";
			    break;
			    case error.POSITION_UNAVAILABLE:
			    	info += "La position n’a pu être déterminée";
			    break;
			    case error.UNKNOWN_ERROR:
			    	info += "Erreur inconnue";
			    break;
			}
			toastr.error(info);
		});
	}
	else{
	  toastr.error("Votre navigateur ne prend pas en compte la géolocalisation HTML5");
	}
}

function getCityInseeByGeoPos(coords){
	toastr.info(" Recherche des données de votre commune");
	$.ajax({
		url: baseUrl + "/" + moduleId+"/sig/getinseebylatlng",
		type: 'POST',
		dataType: 'json',
		data:{"latitude" : coords.latitude, "longitude" : coords.longitude },
		complete: function () {},
		success: function (obj) {
			if (obj != null && obj.length > 0) {
				if(currentRoleLoc == "showCity" && typeof obj.insee != "undefined"){
					toastr.success("Vous allez être redirigé vers la page de votre commune ...");
					showAjaxPanel("/city/detail/insee/" + obj.insee + "?isNotSV=1", 'Details', 'university');
				}
				else if(currentRoleLoc == "prefill" && typeof obj.cp != "undefined"){
					toastr.success("Nous avons trouvé votre code postal : "+obj.cp);
					$(".form-group #cp").val(obj.cp);
					searchCity();
				}
			}else{
				toastr.info("Nous n'avons pas trouvé votre code postal : merci de vous localiser manuellement en remplissant le formulaire.");
				//getCityByLatLngNominatim(coords.latitude, coords.longitude);
			}
		},
		error: function (error) {
			console.dir(error);
			toastr.error(error.responseText);
		}
	});
}

//reverse geocoding
function getCityByLatLngNominatim(latitude, longitude){
	console.log(latitude, longitude);
	toastr.info(" Recherche approfondie");
	$.ajax({
		url: "//nominatim.openstreetmap.org/reverse?lat=" + latitude + "&lon=" + longitude + "&format=json&addressdetails=1",
		type: 'POST',
		dataType: 'json',
		complete: function () { },
		success: function (obj)
		{
			if(typeof obj.address.city != "undefined")		{ getInseeByCityName(obj.address.city);
			}else if(typeof obj.address.town != "undefined"){ getInseeByCityName(obj.address.town);
			}else{ toastr.error("Impossible de trouver le nom de votre commune"); }
		},
		error: function(error){
			console.dir("error", error);
		}
	});
}

function getInseeByCityName(cityName){
	toastr.info(" Merci de patienter ...");
	$.ajax({
		url: baseUrl + "/" + moduleId+"/sig/getcodeinseebycityname",
		type: 'POST',
		dataType: 'json',
		contentType: "application/x-www-form-urlencoded; charset=UTF-8",
		data:{ "cityName" : cityName },
		complete: function () { },
		success: function (obj)
		{
			console.log("getInseeByCityName ok");
			console.dir(obj);

			if (typeof obj != "undefined"){
				if (currentRoleLoc == "showCity"){
					if(typeof obj.insee != "undefined") {
						toastr.success(" Vous allez être redirigé vers la page de votre commune ... ");
						showAjaxPanel("/city/detail/insee/" + obj.insee + "?isNotSV=1", 'Details', 'university');
					}else{
						toastr.error("Impossible d'identifier votre commune ... ");
					}
				}
				else if (currentRoleLoc == "prefill"){
					if(typeof obj.cp != "undefined") {
						toastr.success("Nous avons trouvé votre code postal à partir de notre bdd+nominatim name (getcodeinseebycityname) : "+obj.cp);
						$(".form-group #cp").val(obj.cp);
						searchCity();
					}else{
						toastr.error("Impossible d'identifier votre commune ... ");
					}
				}
			}
		},
		error: function(error){
			toastr.error("Erreur : Impossible d'identifier votre commune ... ");
		}
	});
}
/* géolocalisation HTML5 */<|endoftext|>


<commit_before>'use strict';

var parse = require('../src/parse');
var filter = require('../src/filter').filter;

describe('filter filter', function () {

  beforeEach(function () {
    //runs before each spec
  });

  it('is available', function () {

    expect(filter('filter')).toBeDefined();
  });

  it('can filter an array with a predicate function', function () {

    var fn = parse('[1, 2, 3, 4] | filter:isOdd');

    var scope = {

      isOdd: function (n) {

        return n % 2 !== 0;
      }
    };

    expect(fn(scope)).toEqual([1, 3]);
  });

  it('can filter an array of string with a string', function () {

    var fn = parse('arr | filter:"a"');
    expect(fn({arr: ["a", "b", "a"]})).toEqual(['a', 'a']);
  });

  it('can filter an array of strings with substring matching', function () {

    var fn = parse('arr | filter:"o"');
    expect(fn({arr: ['quick', 'brown', 'fox']})).toEqual(['brown', 'fox']);
  });

  it('can filter an array of strings insensitive of case', function () {

    var fn = parse('arr | filter:"o"');
    expect(fn({arr: ['quick', 'BROWN', 'fox']})).toEqual(['BROWN', 'fox']);
  });

  it('filters an array of objects where any value matches', function () {
    var fn = parse('arr | filter:"o"');
    expect(fn({
      arr: [
        {firstName: 'John', lastName: 'Brown'},
        {firstName: 'Jane', lastName: 'Fox'},
        {firstName: 'Mary', lastName: 'Quick'}
      ]
    })).toEqual([
      {firstName: 'John', lastName: 'Brown'},
      {firstName: 'Jane', lastName: 'Fox'}
    ]);
  });

  it('filters an array of objects where a nested value matches', function () {

    var fn = parse('arr | filter: "o"');
    expect(fn({
      arr: [
        {name: {first: 'John', last: 'Brown'}},
        {name: {first: 'Jane', last: 'Fox'}},
        {name: {first: 'Mary', last: 'Quick'}},
      ]
    })).toEqual([
      {name: {first: 'John', last: 'Brown'}},
      {name: {first: 'Jane', last: 'Fox'}}
    ]);
  });

  it('filters an array of arrays where a nested value matches', function () {

    var fn = parse('arr | filter: "o"');
    expect(fn({
      arr: [
        [{name: 'John'}, {name: 'Mary'}],
        [{name: 'Jane'}],
      ]
    })).toEqual([
      [{name: 'John'}, {name: 'Mary'}],
    ]);
  });

  it('filters with a number', function () {

    var fn = parse('arr | filter:42');
    expect(fn({
      arr: [
        {name: 'Mary', age: 42},
        {name: 'John', age: 43},
        {name: 'Jane', age: 44},
      ]
    })).toEqual([{name: 'Mary', age: 42}]);
  });

  it('filters with a boolean', function () {

    var fn = parse('arr | filter:true');
    expect(fn({arr: [
      {name: 'Mary', admin: true},
      {name: 'John', admin: true},
      {name: 'Jane', admin: false}
    ]})).toEqual([
      {name: 'Mary', admin: true},
      {name: 'John', admin: true}
    ]);
  });
});<commit_msg>filters numeric values with a substring<commit_after>'use strict';

var parse = require('../src/parse');
var filter = require('../src/filter').filter;

describe('filter filter', function () {

  beforeEach(function () {
    //runs before each spec
  });

  it('is available', function () {

    expect(filter('filter')).toBeDefined();
  });

  it('can filter an array with a predicate function', function () {

    var fn = parse('[1, 2, 3, 4] | filter:isOdd');

    var scope = {

      isOdd: function (n) {

        return n % 2 !== 0;
      }
    };

    expect(fn(scope)).toEqual([1, 3]);
  });

  it('can filter an array of string with a string', function () {

    var fn = parse('arr | filter:"a"');
    expect(fn({arr: ["a", "b", "a"]})).toEqual(['a', 'a']);
  });

  it('can filter an array of strings with substring matching', function () {

    var fn = parse('arr | filter:"o"');
    expect(fn({arr: ['quick', 'brown', 'fox']})).toEqual(['brown', 'fox']);
  });

  it('can filter an array of strings insensitive of case', function () {

    var fn = parse('arr | filter:"o"');
    expect(fn({arr: ['quick', 'BROWN', 'fox']})).toEqual(['BROWN', 'fox']);
  });

  it('filters an array of objects where any value matches', function () {
    var fn = parse('arr | filter:"o"');
    expect(fn({
      arr: [
        {firstName: 'John', lastName: 'Brown'},
        {firstName: 'Jane', lastName: 'Fox'},
        {firstName: 'Mary', lastName: 'Quick'}
      ]
    })).toEqual([
      {firstName: 'John', lastName: 'Brown'},
      {firstName: 'Jane', lastName: 'Fox'}
    ]);
  });

  it('filters an array of objects where a nested value matches', function () {

    var fn = parse('arr | filter: "o"');
    expect(fn({
      arr: [
        {name: {first: 'John', last: 'Brown'}},
        {name: {first: 'Jane', last: 'Fox'}},
        {name: {first: 'Mary', last: 'Quick'}},
      ]
    })).toEqual([
      {name: {first: 'John', last: 'Brown'}},
      {name: {first: 'Jane', last: 'Fox'}}
    ]);
  });

  it('filters an array of arrays where a nested value matches', function () {

    var fn = parse('arr | filter: "o"');
    expect(fn({
      arr: [
        [{name: 'John'}, {name: 'Mary'}],
        [{name: 'Jane'}],
      ]
    })).toEqual([
      [{name: 'John'}, {name: 'Mary'}],
    ]);
  });

  it('filters with a number', function () {

    var fn = parse('arr | filter:42');
    expect(fn({
      arr: [
        {name: 'Mary', age: 42},
        {name: 'John', age: 43},
        {name: 'Jane', age: 44},
      ]
    })).toEqual([{name: 'Mary', age: 42}]);
  });

  it('filters with a boolean', function () {

    var fn = parse('arr | filter:true');
    expect(fn({
      arr: [
        {name: 'Mary', admin: true},
        {name: 'John', admin: true},
        {name: 'Jane', admin: false}
      ]
    })).toEqual([
      {name: 'Mary', admin: true},
      {name: 'John', admin: true}
    ]);
  });

  it('filters with a substring numeric value', function () {

    var fn = parse('arr | filter:42');
    expect(fn({arr: ['contains 42']})).toEqual(['contains 42']);
  });
});<|endoftext|>


<commit_before>class Overworld {
    constructor (game) {
        this.game = game
        this.player = null
        this.cursor = null
        this.map = null
        this.inputs = {}
        this.current = null
        this.statsMenu = null
    }

    init(mapDump, playerDump) {
        this.mapDump = mapDump
        this.playerDump = playerDump
    }
    preload() {
        // load images, sounds
        this.game.load.image('city', 'assets/sprites/city.png')
        this.game.load.image('stats-menu', 'assets/sprites/stats-menu.png')
        this.game.load.image('button', 'assets/sprites/stats-menu-button.png')
        this.game.load.spritesheet('horse', 'assets/sprites/horse.png', 183, 134)
    }
	storageAvailable() {
		try {
			var storage = window.localStorage, x = '__storage_test__';
			storage.setItem(x, x);
			storage.removeItem(x);
			return true;
		} catch(e) {
			return false;
		}
	}
    create() {
        this.game.stage.backgroundColor = '#D5B783'
        this.game.time.desiredFps = 30
        this.game.world.setBounds(0, 0, 2 * this.game.camera.width, 2* this.game.camera.height)
        this.game.camera.setPosition(
            this.game.world.centerX - this.game.camera.width / 2,
            this.game.world.centerY - this.game.camera.height / 2
        )

        this.game.input.keyboard.addKeyCapture([37, 38, 39, 40, 32]) // prevent arrow keys, spacebar from scrolling
        this.inputs.keys = this.game.input.keyboard.createCursorKeys()

        for(var key in this.inputs.keys)
            this.inputs.keys[key].onUp.add(this.keyHandler, this)

        if(typeof this.mapDump !== 'undefined' && this.mapDump !== null)
            this.map = new Map(this.game, this.mapDump)
        if(typeof this.playerDump !== 'undefined' && this.playerDump !== null)
            this.player = new Player(this.game, this.playerDump.city, this.playerDump)

        if(this.map === null) {
			var loadedMap = false;
			var savedMap = null;
			if ( this.storageAvailable() ) {
				savedMap = JSON.parse(localStorage.getItem('pex_map'));
				if ( savedMap != null ) {
					loadedMap = true;
					console.log("Map loaded from localStorage");
				}
			}

			if ( loadedMap ) {
				this.map = new Map(this.game, savedMap);
			} else {
				this.map = new Map(this.game);
			}
		}

        var loadedPlayer = false;
		var savedPlayer = null;
		if ( this.player === null ) {
			if ( this.storageAvailable() ) {
				savedPlayer = JSON.parse(localStorage.getItem('pex_player'));
				if ( savedPlayer != null ) {
					loadedPlayer = true;
					console.log("Player loaded from localStorage");
				}
			}
			if ( loadedPlayer ) {
				this.player = new Player(this.game, this.map.rootNode, savedPlayer);
			} else {
				this.player = new Player(this.game, this.map.rootNode);
			}
		}

        this.cursor = this.player.city
        this.adjacentCities = this.map.getConnectedCities(this.cursor)

        this.player.city.alpha = 1
        this.player.city.nameText.alpha = 1

        for(var c in this.adjacentCities){
            this.adjacentCities[c].alpha = 1
            this.adjacentCities[c].nameText.alpha = 1
        }

        this.game.camera.setPosition(this.player.x - this.game.camera.width / 2, this.player.y - this.game.camera.height / 2)

        this.graphics = this.game.add.graphics(0, 0)
        this.roads = this.createRoads(this.map.getRoads())

        this.statsMenu = new StatsMenu(this.game, this.player)

		//Save to disk
		if ( this.storageAvailable() ) {
			localStorage.setItem('pex_player', JSON.stringify(this.player.dumps()));
			localStorage.setItem('pex_map', JSON.stringify(this.map.dumps()));
			console.log("Game saved to localStorage");
		} else {
			console.log("Not saving to localStorage as it's not available");
		}

    }
    update() {
        // logical update

        // three cities we're ever looking at:
        // current city -- city the player is at
        // selected city -- city the cursor is at
        // clicked city -- city that has been most recently clicked OR keyed to
        // clicked city is always the "newest", if it exists

        if(this.hasPlayerGivenValidInput() && this.getClickedCity() !== null) {
            if(this.hasPlayerClickedADifferentCity())
                this.moveCursorToClickedCity()
            else if(this.hasPlayerClickedSelectedCity())
                if(this.isPlayerInSelectedCity()) {}
                else
                    this.movePlayerToClickedCity()
            else if(this.isPlayerInClickedCity()) {
                if(typeof this.selectedRoad !== 'undefined' && this.selectedRoad !== null) {
                    this.graphics.beginFill()
                    this.graphics.lineStyle(3, 0x82653C, 1)
                    this.graphics.moveTo(this.selectedRoad.co.x + 32, this.selectedRoad.co.y + 24)
                    this.graphics.lineTo(this.selectedRoad.cf.x + 32, this.selectedRoad.cf.y + 24)
                    this.graphics.endFill()
                }
                this.selectedRoad = null
                if(this.cursor !== null) this.cursor.tint = 0xffffff
                this.cursor = this.player.city
                this.game.add.tween(this.game.camera).to(
                    {
                        x: this.cursor.x - (this.game.camera.width / 2),
                        y: this.cursor.y - (this.game.camera.height / 2),
                    },
                    300,
                    Phaser.Easing.Quadratic.InOut,
                    true
                )
            }
            this.clickedCity = null
        }

        // thanks to @sanojian from http://www.html5gamedevs.com/topic/9814-move-camera-by-dragging-the-world-floor/
        if (this.game.input.activePointer.isDown) {
            if (this.game.origDragPoint) {
                // move the camera by the amount the mouse has moved since last update
                this.game.camera.x += this.game.origDragPoint.x - this.game.input.activePointer.position.x;
                this.game.camera.y += this.game.origDragPoint.y - this.game.input.activePointer.position.y;
            }
            // set new drag origin to current position
            this.game.origDragPoint = this.game.input.activePointer.position.clone();
        }
        else {
            this.game.origDragPoint = null;
        }
    }
    render() {

    }

    createRoads (roads) {
        var rs = []
        for(var r in roads) {
            var road = new Road(this.game, roads[r].v, roads[r].w)
            rs.push(road)
        }

        this.graphics.clear()
        this.graphics.beginFill('#4bd49c')
        for(var r in rs) {
            var road = rs[r]
            if(road.isConnectedTo(this.player.city))
                this.graphics.lineStyle(3, 0x82653C, 1) //darker color
            else this.graphics.lineStyle(3, 0xBB955F, 1) //lighter color
            this.graphics.moveTo(road.co.x + 32, road.co.y + 24)
            this.graphics.lineTo(road.cf.x + 32, road.cf.y + 24)

            if(road.isConnectedTo(this.player.city)) {

                var treacheryRating = ''

                for(var i = 1; i <= 5; i++)
                    if(i <= road.treachery)
                        treacheryRating += '\u2605'
                    else treacheryRating += '\u2606'

                //road.treacheryText = this.game.add.text(road.line.midPoint().x + (treacheryRating.length * 11) / 2, road.line.midPoint().y + 30, treacheryRating, { font: 'monospace', fill: '#615C45', stroke: '#615C45', fontSize: '22px' });
				//road.treacheryText.rotation = road.text.rotation;

				road.text = this.game.add.text(
						road.line.midPoint().x,
						road.line.midPoint().y,
						road.length + ' ' + (road.length>1 ? 'weeks' : 'week') + ' ' + treacheryRating,
						{ font: 'Amatic SC, serif', fill: '#615C45', stroke: '#615C45', fontSize: '18px', fontWeight: 'bold' }
					);
				var angle = this.map.getCityAngle(road.co, road.cf);
				if ( angle > Math.PI*0.5 && angle < Math.PI*1.5 ) {
					angle -= Math.PI;
				}
				//road.text.rotation = angle;

            }

        }
        this.graphics.endFill()

        return rs
    }
    keyHandler(e) {
        this.current = e
    }
    hasPlayerGivenValidInput() {
        try {
            if(typeof this.current !== 'undefined'
               && this.current !== null) {
                if(this.current instanceof Phaser.Sprite && this.current.key === 'city')
                    // TODO: check for city adjacency
                    return true
                else if(this.current instanceof Phaser.Key)
                    return this.isKeyTowardsCity()
            }
        }
        catch(e) {
            if(this.current !== null)
                console.log(e)
            this.current = null
        }
        return false
    }
    isClickingCity() {
        throw new Error('Unimplemented')
    }
    isKeyTowardsCity() {
        for(var c in this.adjacentCities) {
            var city = this.adjacentCities[c]

            switch(this.current.keyCode) {
                default:
                    console.log(this.current.keyCode)
            }
        }
        throw new Error('Unimplemented')
    }
    getClickedCity() {
        return this.clickedCity
    }
    hasPlayerClickedADifferentCity() {
        if(this.cursor === null) return true
        return this.cursor.name !== this.getClickedCity().name && this.player.city.name !== this.getClickedCity().name
    }
    moveCursorToClickedCity() {
        if(this.cursor !== null) this.cursor.tint = 0xffffff
        this.cursor = this.getClickedCity()
        this.game.add.tween(this.game.camera).to(
            {
                x: this.cursor.x - (this.game.camera.width / 2),
                y: this.cursor.y - (this.game.camera.height / 2),
            },
            300,
            Phaser.Easing.Quadratic.InOut,
            true
        )
        this.cursor.tint = 0x000000
        if(typeof this.selectedRoad !== 'undefined' && this.selectedRoad !== null) {
            this.graphics.beginFill()
            this.graphics.lineStyle(3, 0x82653C, 1)
            this.graphics.moveTo(this.selectedRoad.co.x + 32, this.selectedRoad.co.y + 24)
            this.graphics.lineTo(this.selectedRoad.cf.x + 32, this.selectedRoad.cf.y + 24)
            this.graphics.endFill()
        }

        if(this.adjacentCities.indexOf(this.cursor) !== -1) {

            for(var r in this.roads)
                if(this.roads[r].isConnectedTo(this.cursor) && this.roads[r].isConnectedTo(this.player.city))
                    this.selectedRoad = this.roads[r]

            if(typeof this.selectedRoad !== 'undefined') {
                this.graphics.beginFill()
                this.graphics.lineStyle(3, 0x000000, 1)
                this.graphics.moveTo(this.selectedRoad.co.x + 32, this.selectedRoad.co.y + 24)
                this.graphics.lineTo(this.selectedRoad.cf.x + 32, this.selectedRoad.cf.y + 24)
                this.graphics.endFill()
            }
        }

    }

    hasPlayerClickedSelectedCity() {
        return this.getClickedCity().name === this.cursor.name
    }
    isPlayerInSelectedCity() {
        return this.player.city.name === this.cursor.name
    }
    isPlayerInClickedCity() {
        if(this.getClickedCity() === null) return false
        return this.player.city.name === this.getClickedCity().name
    }
    movePlayerToClickedCity() {

        if(this.adjacentCities.indexOf(this.getClickedCity()) === -1)
           return

        this.game.input.keyboard.onUpCallback = function () {}
        this.game.input.mouse.mouseUpCallback = function () {}
        this.player.city = this.getClickedCity()
        this.game.state.start('travel', true, false, this.player, this.selectedRoad.treachery, this.map.dumps())
    }
}
<commit_msg>Fix the city UI after state swapping<commit_after>class Overworld {
    constructor (game) {
        this.game = game
        this.player = null
        this.cursor = null
        this.map = null
        this.inputs = {}
        this.current = null
        this.statsMenu = null
    }

    init(mapDump, playerDump) {
        this.mapDump = mapDump
        this.playerDump = playerDump
    }
    preload() {
        // load images, sounds
        this.game.load.image('city', 'assets/sprites/city.png')
        this.game.load.image('stats-menu', 'assets/sprites/stats-menu.png')
        this.game.load.image('button', 'assets/sprites/stats-menu-button.png')
        this.game.load.spritesheet('horse', 'assets/sprites/horse.png', 183, 134)
    }
	storageAvailable() {
		try {
			var storage = window.localStorage, x = '__storage_test__';
			storage.setItem(x, x);
			storage.removeItem(x);
			return true;
		} catch(e) {
			return false;
		}
	}
    create() {
        this.game.stage.backgroundColor = '#D5B783'
        this.game.time.desiredFps = 30
        this.game.world.setBounds(0, 0, 2 * this.game.camera.width, 2* this.game.camera.height)
        this.game.camera.setPosition(
            this.game.world.centerX - this.game.camera.width / 2,
            this.game.world.centerY - this.game.camera.height / 2
        )

        this.game.input.keyboard.addKeyCapture([37, 38, 39, 40, 32]) // prevent arrow keys, spacebar from scrolling
        this.inputs.keys = this.game.input.keyboard.createCursorKeys()

        for(var key in this.inputs.keys)
            this.inputs.keys[key].onUp.add(this.keyHandler, this)

        if(typeof this.mapDump !== 'undefined' && this.mapDump !== null)
            this.map = new Map(this.game, this.mapDump)
        if(typeof this.playerDump !== 'undefined' && this.playerDump !== null) {
            var cities = this.map.getCities(),
                playerCity = null
            for(var c in cities)
                if(cities[c].name === this.playerDump.city.name)
                    playerCity = cities[c]
            this.player = new Player(this.game, playerCity, this.playerDump)
        }

        if(this.map === null) {
			var loadedMap = false;
			var savedMap = null;
			if ( this.storageAvailable() ) {
				savedMap = JSON.parse(localStorage.getItem('pex_map'));
				if ( savedMap != null ) {
					loadedMap = true;
					console.log("Map loaded from localStorage");
				}
			}

			if ( loadedMap ) {
				this.map = new Map(this.game, savedMap);
			} else {
				this.map = new Map(this.game);
			}
		}

        var loadedPlayer = false;
		var savedPlayer = null;
		if ( this.player === null ) {
			if ( this.storageAvailable() ) {
				savedPlayer = JSON.parse(localStorage.getItem('pex_player'));
				if ( savedPlayer != null ) {
					loadedPlayer = true;
					console.log("Player loaded from localStorage");
				}
			}
			if ( loadedPlayer ) {
				this.player = new Player(this.game, this.map.rootNode, savedPlayer);
			} else {
				this.player = new Player(this.game, this.map.rootNode);
			}
		}

        this.cursor = this.player.city
        this.adjacentCities = this.map.getConnectedCities(this.cursor)

        this.player.city.alpha = 1
        this.player.city.nameText.alpha = 1

        for(var c in this.adjacentCities){
            this.adjacentCities[c].alpha = 1
            this.adjacentCities[c].nameText.alpha = 1
        }

        this.game.camera.setPosition(this.player.x - this.game.camera.width / 2, this.player.y - this.game.camera.height / 2)

        this.graphics = this.game.add.graphics(0, 0)
        this.roads = this.createRoads(this.map.getRoads())

        this.statsMenu = new StatsMenu(this.game, this.player)

		//Save to disk
		if ( this.storageAvailable() ) {
			localStorage.setItem('pex_player', JSON.stringify(this.player.dumps()));
			localStorage.setItem('pex_map', JSON.stringify(this.map.dumps()));
			console.log("Game saved to localStorage");
		} else {
			console.log("Not saving to localStorage as it's not available");
		}

    }
    update() {
        // logical update

        // three cities we're ever looking at:
        // current city -- city the player is at
        // selected city -- city the cursor is at
        // clicked city -- city that has been most recently clicked OR keyed to
        // clicked city is always the "newest", if it exists

        if(this.hasPlayerGivenValidInput() && this.getClickedCity() !== null) {
            if(this.hasPlayerClickedADifferentCity())
                this.moveCursorToClickedCity()
            else if(this.hasPlayerClickedSelectedCity())
                if(this.isPlayerInSelectedCity()) {}
                else
                    this.movePlayerToClickedCity()
            else if(this.isPlayerInClickedCity()) {
                if(typeof this.selectedRoad !== 'undefined' && this.selectedRoad !== null) {
                    this.graphics.beginFill()
                    this.graphics.lineStyle(3, 0x82653C, 1)
                    this.graphics.moveTo(this.selectedRoad.co.x + 32, this.selectedRoad.co.y + 24)
                    this.graphics.lineTo(this.selectedRoad.cf.x + 32, this.selectedRoad.cf.y + 24)
                    this.graphics.endFill()
                }
                this.selectedRoad = null
                if(this.cursor !== null) this.cursor.tint = 0xffffff
                this.cursor = this.player.city
                this.game.add.tween(this.game.camera).to(
                    {
                        x: this.cursor.x - (this.game.camera.width / 2),
                        y: this.cursor.y - (this.game.camera.height / 2),
                    },
                    300,
                    Phaser.Easing.Quadratic.InOut,
                    true
                )
            }
            this.clickedCity = null
        }

        // thanks to @sanojian from http://www.html5gamedevs.com/topic/9814-move-camera-by-dragging-the-world-floor/
        if (this.game.input.activePointer.isDown) {
            if (this.game.origDragPoint) {
                // move the camera by the amount the mouse has moved since last update
                this.game.camera.x += this.game.origDragPoint.x - this.game.input.activePointer.position.x;
                this.game.camera.y += this.game.origDragPoint.y - this.game.input.activePointer.position.y;
            }
            // set new drag origin to current position
            this.game.origDragPoint = this.game.input.activePointer.position.clone();
        }
        else {
            this.game.origDragPoint = null;
        }
    }
    render() {

    }

    createRoads (roads) {
        var rs = []
        for(var r in roads) {
            var road = new Road(this.game, roads[r].v, roads[r].w)
            rs.push(road)
        }

        this.graphics.clear()
        this.graphics.beginFill('#4bd49c')
        for(var r in rs) {
            var road = rs[r]
            if(road.isConnectedTo(this.player.city))
                this.graphics.lineStyle(3, 0x82653C, 1) //darker color
            else this.graphics.lineStyle(3, 0xBB955F, 1) //lighter color
            this.graphics.moveTo(road.co.x + 32, road.co.y + 24)
            this.graphics.lineTo(road.cf.x + 32, road.cf.y + 24)

            if(road.isConnectedTo(this.player.city)) {

                var treacheryRating = ''

                for(var i = 1; i <= 5; i++)
                    if(i <= road.treachery)
                        treacheryRating += '\u2605'
                    else treacheryRating += '\u2606'

                //road.treacheryText = this.game.add.text(road.line.midPoint().x + (treacheryRating.length * 11) / 2, road.line.midPoint().y + 30, treacheryRating, { font: 'monospace', fill: '#615C45', stroke: '#615C45', fontSize: '22px' });
				//road.treacheryText.rotation = road.text.rotation;

				road.text = this.game.add.text(
						road.line.midPoint().x,
						road.line.midPoint().y,
						road.length + ' ' + (road.length>1 ? 'weeks' : 'week') + ' ' + treacheryRating,
						{ font: 'Amatic SC, serif', fill: '#615C45', stroke: '#615C45', fontSize: '18px', fontWeight: 'bold' }
					);
				var angle = this.map.getCityAngle(road.co, road.cf);
				if ( angle > Math.PI*0.5 && angle < Math.PI*1.5 ) {
					angle -= Math.PI;
				}
				//road.text.rotation = angle;

            }

        }
        this.graphics.endFill()

        return rs
    }
    keyHandler(e) {
        this.current = e
    }
    hasPlayerGivenValidInput() {
        try {
            if(typeof this.current !== 'undefined'
               && this.current !== null) {
                if(this.current instanceof Phaser.Sprite && this.current.key === 'city')
                    // TODO: check for city adjacency
                    return true
                else if(this.current instanceof Phaser.Key)
                    return this.isKeyTowardsCity()
            }
        }
        catch(e) {
            if(this.current !== null)
                console.log(e)
            this.current = null
        }
        return false
    }
    isClickingCity() {
        throw new Error('Unimplemented')
    }
    isKeyTowardsCity() {
        for(var c in this.adjacentCities) {
            var city = this.adjacentCities[c]

            switch(this.current.keyCode) {
                default:
                    console.log(this.current.keyCode)
            }
        }
        throw new Error('Unimplemented')
    }
    getClickedCity() {
        return this.clickedCity
    }
    hasPlayerClickedADifferentCity() {
        if(this.cursor === null) return true
        return this.cursor.name !== this.getClickedCity().name && this.player.city.name !== this.getClickedCity().name
    }
    moveCursorToClickedCity() {
        if(this.cursor !== null) this.cursor.tint = 0xffffff
        this.cursor = this.getClickedCity()
        this.game.add.tween(this.game.camera).to(
            {
                x: this.cursor.x - (this.game.camera.width / 2),
                y: this.cursor.y - (this.game.camera.height / 2),
            },
            300,
            Phaser.Easing.Quadratic.InOut,
            true
        )
        this.cursor.tint = 0x000000
        if(typeof this.selectedRoad !== 'undefined' && this.selectedRoad !== null) {
            this.graphics.beginFill()
            this.graphics.lineStyle(3, 0x82653C, 1)
            this.graphics.moveTo(this.selectedRoad.co.x + 32, this.selectedRoad.co.y + 24)
            this.graphics.lineTo(this.selectedRoad.cf.x + 32, this.selectedRoad.cf.y + 24)
            this.graphics.endFill()
        }

        if(this.adjacentCities.indexOf(this.cursor) !== -1) {

            for(var r in this.roads)
                if(this.roads[r].isConnectedTo(this.cursor) && this.roads[r].isConnectedTo(this.player.city))
                    this.selectedRoad = this.roads[r]

            if(typeof this.selectedRoad !== 'undefined') {
                this.graphics.beginFill()
                this.graphics.lineStyle(3, 0x000000, 1)
                this.graphics.moveTo(this.selectedRoad.co.x + 32, this.selectedRoad.co.y + 24)
                this.graphics.lineTo(this.selectedRoad.cf.x + 32, this.selectedRoad.cf.y + 24)
                this.graphics.endFill()
            }
        }

    }

    hasPlayerClickedSelectedCity() {
        return this.getClickedCity().name === this.cursor.name
    }
    isPlayerInSelectedCity() {
        return this.player.city.name === this.cursor.name
    }
    isPlayerInClickedCity() {
        if(this.getClickedCity() === null) return false
        return this.player.city.name === this.getClickedCity().name
    }
    movePlayerToClickedCity() {

        if(this.adjacentCities.indexOf(this.getClickedCity()) === -1)
           return

        this.game.input.keyboard.onUpCallback = function () {}
        this.game.input.mouse.mouseUpCallback = function () {}
        this.player.city = this.getClickedCity()
        this.game.state.start('travel', true, false, this.player, this.selectedRoad.treachery, this.map.dumps())
    }
}
<|endoftext|>


<commit_before>/* jshint -W014 */

var hljs;
function highlightCode(code, lang) {
	if (!hljs) {
		hljs = require('highlight.js');
		hljs.configure({tabReplace: '    '}); // 4 spaces
		hljs.registerLanguage('typescript', require('./lib/highlight/typescript'));
	}
	if (lang) {
		return hljs.highlight(lang, code).value;
	}
	return hljs.highlightAuto(code).value;
}

var docpadConfig = {
	templateData: {
		site: {
			url: 'http://definitelytyped.github.io',
			github: 'https://github.com/borisyankov/DefinitelyTyped',
			ref: 'github.com/borisyankov/DefinitelyTyped',
			home: '/',
			gh: {
				user: 'borisyankov',
				repo: 'DefinitelyTyped'
			},
			oldUrls: [],
			title: 'DefinitelyTyped',
			description: 'The repository for high quality TypeScript type definitions.',
			tagline: 'The repository for high quality TypeScript type definitions.',
			keywords: 'typescript, type, definition, declaration, repository, typing',
			styles: [
				'/styles/semantic.min.css',
				'/styles/highlight.css',
				'/styles/style.css'
			],
			scripts: [
				'//ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js',
				'/scripts/semantic.min.js',
				'/scripts/script.js'
			],
			analytics: {
				id: 'UA-47495295-3',
				site: 'definitelytyped.github.io'
			}
		},
		link: {
			tsd: {
				web: 'http://www.tsdpm.com',
				npm: 'https://www.npmjs.org/package/tsd'
			}
		},
		getPreparedTitle: function() {
			if (this.document.title) {
				return '' + this.document.title + ' | ' + this.site.title;
			} else {
				return this.site.title;
			}
		},
		getPreparedDescription: function() {
			return this.document.description || this.site.description;
		},
		getPreparedKeywords: function() {
			return this.site.keywords.concat(this.document.keywords || []).join(', ');
		}
	},
	collections: {
		guides: function() {
			return this.getCollection('documents').findAllLive({
				relativeOutDirPath: 'guides'
			});
		}
	},
	environments: {
		development: {
			templateData: {
				site: {
					url: false
				}
			}
		}
	},
	plugins: {
		marked: {
			markedOptions: {
				gfm: true,
				highlight: highlightCode
			}
		}
	},
	events: {
		serverExtend: function(opts) {
			var server = opts.server;
			var docpad = this.docpad;
			var latestConfig = docpad.getConfig();
			var oldUrls = latestConfig.templateData.site.oldUrls || [];
			var newUrl = latestConfig.templateData.site.url;
			return server.use(function(req, res, next) {
				if (oldUrls.indexOf(req.headers.host) >= 0) {
					return res.redirect(newUrl + req.url, 301);
				} else {
					return next();
				}
			});
		}
	}
};

module.exports = docpadConfig;
<commit_msg>updated domain<commit_after>/* jshint -W014 */

var hljs;
function highlightCode(code, lang) {
	if (!hljs) {
		hljs = require('highlight.js');
		hljs.configure({tabReplace: '    '}); // 4 spaces
		hljs.registerLanguage('typescript', require('./lib/highlight/typescript'));
	}
	if (lang) {
		return hljs.highlight(lang, code).value;
	}
	return hljs.highlightAuto(code).value;
}

var docpadConfig = {
	templateData: {
		site: {
			url: 'http://definitelytyped.org',
			github: 'https://github.com/borisyankov/DefinitelyTyped',
			ref: 'github.com/borisyankov/DefinitelyTyped',
			home: '/',
			gh: {
				user: 'borisyankov',
				repo: 'DefinitelyTyped'
			},
			oldUrls: [],
			title: 'DefinitelyTyped',
			description: 'The repository for high quality TypeScript type definitions.',
			tagline: 'The repository for high quality TypeScript type definitions.',
			keywords: 'typescript, type, definition, declaration, repository, typing',
			styles: [
				'/styles/semantic.min.css',
				'/styles/highlight.css',
				'/styles/style.css'
			],
			scripts: [
				'//ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js',
				'/scripts/semantic.min.js',
				'/scripts/script.js'
			],
			analytics: {
				id: 'UA-47495295-3',
				site: 'definitelytyped.org'
			}
		},
		link: {
			tsd: {
				web: 'http://www.tsdpm.com',
				npm: 'https://www.npmjs.org/package/tsd'
			}
		},
		getPreparedTitle: function() {
			if (this.document.title) {
				return '' + this.document.title + ' | ' + this.site.title;
			} else {
				return this.site.title;
			}
		},
		getPreparedDescription: function() {
			return this.document.description || this.site.description;
		},
		getPreparedKeywords: function() {
			return this.site.keywords.concat(this.document.keywords || []).join(', ');
		}
	},
	collections: {
		guides: function() {
			return this.getCollection('documents').findAllLive({
				relativeOutDirPath: 'guides'
			});
		}
	},
	environments: {
		development: {
			templateData: {
				site: {
					url: false
				}
			}
		}
	},
	plugins: {
		marked: {
			markedOptions: {
				gfm: true,
				highlight: highlightCode
			}
		}
	},
	events: {
		serverExtend: function(opts) {
			var server = opts.server;
			var docpad = this.docpad;
			var latestConfig = docpad.getConfig();
			var oldUrls = latestConfig.templateData.site.oldUrls || [];
			var newUrl = latestConfig.templateData.site.url;
			return server.use(function(req, res, next) {
				if (oldUrls.indexOf(req.headers.host) >= 0) {
					return res.redirect(newUrl + req.url, 301);
				} else {
					return next();
				}
			});
		}
	}
};

module.exports = docpadConfig;
<|endoftext|>


<commit_before>import WMO from '../../pipeline/wmo';

class WMOManager {

  // Determines if regular or slow loading will be used to ingress WMO groups to the map. Used
  // to prevent very large WMOs from killing performance when the player navigates nearby.
  static LARGE_GROUP_THRESHOLD = 60;

  // Proportion of pending WMO roots to load or unload in a given tick.
  static ROOT_LOAD_FACTOR = 1 / 10;

  // Proportion of pending WMO groups to load in a given tick.
  static GROUP_LOAD_FACTOR = 1 / 20;

  // Same as above, but used for WMOs with more than LARGE_THRESHOLD groups.
  static LARGE_GROUP_LOAD_FACTOR = 1 / 30;

  // Proportion of pending WMO doodads to load in a given tick.
  static DOODAD_LOAD_FACTOR = 1 / 100;

  // Number of milliseconds to wait before loading or unloading another portion of WMO roots.
  static ROOT_LOAD_INTERVAL = (1 / 60) * 1000;

  // Number of milliseconds to wait before loading another portion of WMO groups.
  static GROUP_LOAD_INTERVAL = (1 / 60) * 1000;

  // Number of milliseconds to wait before loading another portion of WMO doodads.
  static DOODAD_LOAD_INTERVAL = (1 / 60) * 1000;

  // Number of milliseconds to wait before unloading a root WMO (and its groups). Used to prevent
  // rapid toggling of the loading and unloading of large WMOs when the last chunk reference is
  // removed.
  static ROOT_UNLOAD_DELAY = 30 * 1000;

  constructor(map) {
    this.map = map;
    this.chunkRefs = new Map();

    this.chunkX = null;
    this.chunkY = null;

    this.groupsPendingLoadCount = 0;
    this.groupCount = 0;
    this.doodadsPendingLoadCount = 0;
    this.doodadCount = 0;

    this.wmos = new Map();

    this.entriesPendingLoad = new Map();
    this.entriesPendingUnload = new Map();
    this.entriesDelayingUnload = new Map();

    this.groupsPendingLoad = new Map();
    this.groupsPendingUnload = new Map();
    this.largeGroupsPendingLoad = new Map();
    this.largeGroupsPendingUnload = new Map();

    this.doodadsPendingLoad = new Map();

    this.loadChunk = ::this.loadChunk;
    this.unloadChunk = ::this.unloadChunk;
    this.loadWMOs = ::this.loadWMOs;
    this.loadWMOGroups = ::this.loadWMOGroups;
    this.loadLargeWMOGroups = ::this.loadLargeWMOGroups;
    this.loadWMOGroup = ::this.loadWMOGroup;
    this.loadWMODoodads = ::this.loadWMODoodads;
    this.addPendingUnload = ::this.addPendingUnload;
    this.unloadWMOs = ::this.unloadWMOs;

    setInterval(this.loadWMOs, this.constructor.ROOT_LOAD_INTERVAL);
    setInterval(this.unloadWMOs, this.constructor.ROOT_LOAD_INTERVAL);
    setInterval(this.loadWMOGroups, this.constructor.GROUP_LOAD_INTERVAL);
    setInterval(this.loadLargeWMOGroups, this.constructor.GROUP_LOAD_INTERVAL);
    setInterval(this.loadWMODoodads, this.constructor.DOODAD_LOAD_INTERVAL);
  }

  // Process a set of WMO entries for a given chunk index of the world map.
  loadChunk(index, entries) {
    for (let i = 0, len = entries.length; i < len; ++i) {
      const entry = entries[i];

      let chunkRefs;

      // Fetch or create chunk references for entry.
      if (this.chunkRefs.has(entry.id)) {
        chunkRefs = this.chunkRefs.get(entry.id);
      } else {
        chunkRefs = new Set();
        this.chunkRefs.set(entry.id, chunkRefs);
      }

      // Add chunk reference to entry.
      chunkRefs.add(index);

      // If the WMO is pending unload, remove the pending unload.
      if (this.entriesPendingUnload.has(entry.id)) {
        this.entriesPendingUnload.delete(entry.id);
      }

      // If the WMO is delaying unload, remove the delaying unload.
      if (this.entriesDelayingUnload.has(entry.id)) {
        clearTimeout(this.entriesDelayingUnload.get(entry.id));
        this.entriesDelayingUnload.delete(entry.id);
      }

      // Already loaded, nothing more to be done.
      if (this.wmos.has(entry.id)) {
        continue;
      }

      // Add to pending loads. Actual loading is done by interval.
      this.entriesPendingLoad.set(entry.id, entry);
    }
  }

  unloadChunk(index, entries) {
    for (let i = 0, len = entries.length; i < len; ++i) {
      const entry = entries[i];

      const chunkRefs = this.chunkRefs.get(entry.id);

      // Remove chunk reference for entry.
      chunkRefs.delete(index);

      // If at least one chunk reference remains for entry, leave loaded. Typically happens in
      // cases where a doodad is shared across multiple chunks.
      if (chunkRefs.size > 0) {
        continue;
      }

      // No chunk references remain, so we should remove from pending loads if necessary.
      if (this.entriesPendingLoad.has(entry.id)) {
        this.entriesPendingLoad.delete(entry.id);
      }

      // Add to delaying unloads. Actual unloading is done by interval.
      this.entriesDelayingUnload.set(
        entry.id,
        setTimeout(this.addPendingUnload, this.constructor.ROOT_UNLOAD_DELAY, entry)
      );
    }
  }

  addPendingUnload(entry) {
    this.entriesPendingUnload.set(entry.id, entry);
    this.entriesDelayingUnload.delete(entry.id);
  }

  // Every tick of the load interval, load a portion of any WMOs pending load.
  loadWMOs() {
    let count = 0;

    for (const entry of this.entriesPendingLoad.values()) {
      if (this.wmos.has(entry.id)) {
        this.entriesPendingLoad.delete(entry.id);
        continue;
      }

      this.loadWMO(entry);

      this.entriesPendingLoad.delete(entry.id);

      ++count;

      if (count > this.entriesPendingLoad.size * this.constructor.ROOT_LOAD_FACTOR) {
        return;
      }
    }
  }

  loadWMO(entry) {
    WMO.load(entry.filename).then((wmo) => {
      if (this.wmos.has(entry.id)) {
        return;
      }

      wmo.requestedDoodadSet = entry.doodadSet;

      this.placeWMO(wmo, entry.position, entry.rotation);

      this.wmos.set(entry.id, wmo);

      this.groupsPendingLoadCount += wmo.groupCount;

      let groupsPendingLoad;

      if (wmo.groupCount > this.constructor.LARGE_GROUP_THRESHOLD) {
        if (!this.largeGroupsPendingLoad.has(entry.id)) {
          this.largeGroupsPendingLoad.set(entry.id, new Set());
        }

        groupsPendingLoad = this.largeGroupsPendingLoad.get(entry.id);
      } else {
        if (!this.groupsPendingLoad.has(entry.id)) {
          this.groupsPendingLoad.set(entry.id, new Set());
        }

        groupsPendingLoad = this.groupsPendingLoad.get(entry.id);
      }

      // Add outdoor groups to pending loads.
      for (let ogi = 0, oglen = wmo.outdoorGroupIndices.length; ogi < oglen; ++ogi) {
        groupsPendingLoad.add(wmo.outdoorGroupIndices[ogi]);
      }

      // Add indoor groups to pending loads.
      for (let igi = 0, iglen = wmo.indoorGroupIndices.length; igi < iglen; ++igi) {
        groupsPendingLoad.add(wmo.indoorGroupIndices[igi]);
      }
    });
  }

  // Place a WMO on the world map, adhereing to a provided position and rotation.
  placeWMO(wmo, position, rotation) {
    wmo.position.set(
      -(position.z - this.map.constructor.ZEROPOINT),
      -(position.x - this.map.constructor.ZEROPOINT),
      position.y
    );

    // Provided as (Z, X, -Y)
    wmo.rotation.set(
      rotation.z * Math.PI / 180,
      rotation.x * Math.PI / 180,
      -rotation.y * Math.PI / 180
    );

    // Adjust WMO rotation to match Wowser's axes.
    const quat = wmo.quaternion;
    quat.set(quat.x, quat.y, quat.z, -quat.w);

    this.map.add(wmo);
    wmo.updateMatrix();
  }

  // Every tick of the load interval, load a portion of any WMO groups pending load.
  loadWMOGroups() {
    this.loadWMOGroupsInternal(this.groupsPendingLoad, this.constructor.GROUP_LOAD_FACTOR);
  }

  loadLargeWMOGroups() {
    this.loadWMOGroupsInternal(this.largeGroupsPendingLoad, this.constructor.LARGE_GROUP_LOAD_FACTOR);
  }

  loadWMOGroupsInternal(groupsPendingLoad, loadFactor) {
    let count = 0;

    for (const entryID of groupsPendingLoad.keys()) {
      // An unload was triggered before we managed to load this group.
      if (!this.wmos.has(entryID) || this.entriesPendingUnload.has(entryID)) {
        groupsPendingLoad.delete(entryID);
        continue;
      }

      const wmo = this.wmos.get(entryID);

      const groupIndexes = groupsPendingLoad.get(entryID);

      for (const groupIndex of groupIndexes.values()) {
        this.loadWMOGroup(wmo, groupIndex);

        groupIndexes.delete(groupIndex);

        ++count;

        if (count > this.groupsPendingLoadCount * loadFactor) {
          return;
        }
      }

      // We've loaded all groups for this root WMO entry.
      if (groupIndexes.size === 0) {
        groupsPendingLoad.delete(entryID);

        // Now that groups are all accounted for, it's time to bring in the appropriate doodads.
        const doodadsPendingLoad = new Set(wmo.doodadSetEntries(wmo.requestedDoodadSet));
        this.doodadsPendingLoadCount += doodadsPendingLoad.size;
        this.doodadsPendingLoad.set(entryID, doodadsPendingLoad);
      }
    }
  }

  loadWMOGroup(wmo, groupIndex) {
    --this.groupsPendingLoadCount;
    ++this.groupCount;

    wmo.loadGroup(groupIndex);
  }

  loadWMODoodads() {
    let count = 0;

    for (const entryID of this.doodadsPendingLoad.keys()) {
      const wmo = this.wmos.get(entryID);

      if (!wmo) {
        continue;
      }

      const doodadEntries = this.doodadsPendingLoad.get(entryID);

      for (const doodadEntry of doodadEntries.values()) {
        this.loadWMODoodad(wmo, doodadEntry);

        doodadEntries.delete(doodadEntry);

        ++count;

        if (count > this.doodadsPendingLoadCount * this.constructor.DOODAD_LOAD_FACTOR) {
          return;
        }
      }

      // We've loaded all doodads for this root WMO entry.
      if (doodadEntries.size === 0) {
        this.doodadsPendingLoad.delete(entryID);
      }
    }
  }

  loadWMODoodad(wmo, entry) {
    --this.doodadsPendingLoadCount;
    ++this.doodadCount;

    wmo.renderDoodad(entry);
  }

  // Every tick of the load interval, unload a portion of any root WMOs pending unload.
  unloadWMOs() {
    let count = 0;

    for (const entry of this.entriesPendingUnload.values()) {
      // If the root WMO was already unloaded, remove it from the pending unloads.
      if (!this.wmos.has(entry.id)) {
        this.entriesPendingUnload.delete(entry.id);
        continue;
      }

      this.unloadWMO(entry);

      this.entriesPendingUnload.delete(entry.id);

      ++count;

      if (count > this.entriesPendingUnload.size * this.constructor.ROOT_LOAD_FACTOR) {
        return;
      }
    }
  }

  unloadWMO(entry) {
    const wmo = this.wmos.get(entry.id);
    this.wmos.delete(entry.id);

    this.groupCount -= wmo.loadedGroupCount;
    this.doodadCount -= wmo.loadedDoodadCount;

    if (this.groupsPendingLoad.has(entry.id)) {
      this.groupsPendingLoadCount -= this.groupsPendingLoad.get(entry.id).size;
      this.groupsPendingLoad.delete(entry.id);
    }

    if (this.largeGroupsPendingLoad.has(entry.id)) {
      this.groupsPendingLoadCount -= this.largeGroupsPendingLoad.get(entry.id).size;
      this.largeGroupsPendingLoad.delete(entry.id);
    }

    if (this.doodadsPendingLoad.has(entry.id)) {
      this.doodadsPendingLoadCount -= this.doodadsPendingLoad.get(entry.id).size;
      this.doodadsPendingLoad.delete(entry.id);
    }

    this.map.remove(wmo);
  }

  animate(delta, camera, cameraRotated) {
  }

}

export default WMOManager;
<commit_msg>Removed forgotten remnant of visibility logic<commit_after>import WMO from '../../pipeline/wmo';

class WMOManager {

  // Determines if regular or slow loading will be used to ingress WMO groups to the map. Used
  // to prevent very large WMOs from killing performance when the player navigates nearby.
  static LARGE_GROUP_THRESHOLD = 60;

  // Proportion of pending WMO roots to load or unload in a given tick.
  static ROOT_LOAD_FACTOR = 1 / 10;

  // Proportion of pending WMO groups to load in a given tick.
  static GROUP_LOAD_FACTOR = 1 / 20;

  // Same as above, but used for WMOs with more than LARGE_THRESHOLD groups.
  static LARGE_GROUP_LOAD_FACTOR = 1 / 30;

  // Proportion of pending WMO doodads to load in a given tick.
  static DOODAD_LOAD_FACTOR = 1 / 100;

  // Number of milliseconds to wait before loading or unloading another portion of WMO roots.
  static ROOT_LOAD_INTERVAL = (1 / 60) * 1000;

  // Number of milliseconds to wait before loading another portion of WMO groups.
  static GROUP_LOAD_INTERVAL = (1 / 60) * 1000;

  // Number of milliseconds to wait before loading another portion of WMO doodads.
  static DOODAD_LOAD_INTERVAL = (1 / 60) * 1000;

  // Number of milliseconds to wait before unloading a root WMO (and its groups). Used to prevent
  // rapid toggling of the loading and unloading of large WMOs when the last chunk reference is
  // removed.
  static ROOT_UNLOAD_DELAY = 30 * 1000;

  constructor(map) {
    this.map = map;
    this.chunkRefs = new Map();

    this.groupsPendingLoadCount = 0;
    this.groupCount = 0;
    this.doodadsPendingLoadCount = 0;
    this.doodadCount = 0;

    this.wmos = new Map();

    this.entriesPendingLoad = new Map();
    this.entriesPendingUnload = new Map();
    this.entriesDelayingUnload = new Map();

    this.groupsPendingLoad = new Map();
    this.groupsPendingUnload = new Map();
    this.largeGroupsPendingLoad = new Map();
    this.largeGroupsPendingUnload = new Map();

    this.doodadsPendingLoad = new Map();

    this.loadChunk = ::this.loadChunk;
    this.unloadChunk = ::this.unloadChunk;
    this.loadWMOs = ::this.loadWMOs;
    this.loadWMOGroups = ::this.loadWMOGroups;
    this.loadLargeWMOGroups = ::this.loadLargeWMOGroups;
    this.loadWMOGroup = ::this.loadWMOGroup;
    this.loadWMODoodads = ::this.loadWMODoodads;
    this.addPendingUnload = ::this.addPendingUnload;
    this.unloadWMOs = ::this.unloadWMOs;

    setInterval(this.loadWMOs, this.constructor.ROOT_LOAD_INTERVAL);
    setInterval(this.unloadWMOs, this.constructor.ROOT_LOAD_INTERVAL);
    setInterval(this.loadWMOGroups, this.constructor.GROUP_LOAD_INTERVAL);
    setInterval(this.loadLargeWMOGroups, this.constructor.GROUP_LOAD_INTERVAL);
    setInterval(this.loadWMODoodads, this.constructor.DOODAD_LOAD_INTERVAL);
  }

  // Process a set of WMO entries for a given chunk index of the world map.
  loadChunk(index, entries) {
    for (let i = 0, len = entries.length; i < len; ++i) {
      const entry = entries[i];

      let chunkRefs;

      // Fetch or create chunk references for entry.
      if (this.chunkRefs.has(entry.id)) {
        chunkRefs = this.chunkRefs.get(entry.id);
      } else {
        chunkRefs = new Set();
        this.chunkRefs.set(entry.id, chunkRefs);
      }

      // Add chunk reference to entry.
      chunkRefs.add(index);

      // If the WMO is pending unload, remove the pending unload.
      if (this.entriesPendingUnload.has(entry.id)) {
        this.entriesPendingUnload.delete(entry.id);
      }

      // If the WMO is delaying unload, remove the delaying unload.
      if (this.entriesDelayingUnload.has(entry.id)) {
        clearTimeout(this.entriesDelayingUnload.get(entry.id));
        this.entriesDelayingUnload.delete(entry.id);
      }

      // Already loaded, nothing more to be done.
      if (this.wmos.has(entry.id)) {
        continue;
      }

      // Add to pending loads. Actual loading is done by interval.
      this.entriesPendingLoad.set(entry.id, entry);
    }
  }

  unloadChunk(index, entries) {
    for (let i = 0, len = entries.length; i < len; ++i) {
      const entry = entries[i];

      const chunkRefs = this.chunkRefs.get(entry.id);

      // Remove chunk reference for entry.
      chunkRefs.delete(index);

      // If at least one chunk reference remains for entry, leave loaded. Typically happens in
      // cases where a doodad is shared across multiple chunks.
      if (chunkRefs.size > 0) {
        continue;
      }

      // No chunk references remain, so we should remove from pending loads if necessary.
      if (this.entriesPendingLoad.has(entry.id)) {
        this.entriesPendingLoad.delete(entry.id);
      }

      // Add to delaying unloads. Actual unloading is done by interval.
      this.entriesDelayingUnload.set(
        entry.id,
        setTimeout(this.addPendingUnload, this.constructor.ROOT_UNLOAD_DELAY, entry)
      );
    }
  }

  addPendingUnload(entry) {
    this.entriesPendingUnload.set(entry.id, entry);
    this.entriesDelayingUnload.delete(entry.id);
  }

  // Every tick of the load interval, load a portion of any WMOs pending load.
  loadWMOs() {
    let count = 0;

    for (const entry of this.entriesPendingLoad.values()) {
      if (this.wmos.has(entry.id)) {
        this.entriesPendingLoad.delete(entry.id);
        continue;
      }

      this.loadWMO(entry);

      this.entriesPendingLoad.delete(entry.id);

      ++count;

      if (count > this.entriesPendingLoad.size * this.constructor.ROOT_LOAD_FACTOR) {
        return;
      }
    }
  }

  loadWMO(entry) {
    WMO.load(entry.filename).then((wmo) => {
      if (this.wmos.has(entry.id)) {
        return;
      }

      wmo.requestedDoodadSet = entry.doodadSet;

      this.placeWMO(wmo, entry.position, entry.rotation);

      this.wmos.set(entry.id, wmo);

      this.groupsPendingLoadCount += wmo.groupCount;

      let groupsPendingLoad;

      if (wmo.groupCount > this.constructor.LARGE_GROUP_THRESHOLD) {
        if (!this.largeGroupsPendingLoad.has(entry.id)) {
          this.largeGroupsPendingLoad.set(entry.id, new Set());
        }

        groupsPendingLoad = this.largeGroupsPendingLoad.get(entry.id);
      } else {
        if (!this.groupsPendingLoad.has(entry.id)) {
          this.groupsPendingLoad.set(entry.id, new Set());
        }

        groupsPendingLoad = this.groupsPendingLoad.get(entry.id);
      }

      // Add outdoor groups to pending loads.
      for (let ogi = 0, oglen = wmo.outdoorGroupIndices.length; ogi < oglen; ++ogi) {
        groupsPendingLoad.add(wmo.outdoorGroupIndices[ogi]);
      }

      // Add indoor groups to pending loads.
      for (let igi = 0, iglen = wmo.indoorGroupIndices.length; igi < iglen; ++igi) {
        groupsPendingLoad.add(wmo.indoorGroupIndices[igi]);
      }
    });
  }

  // Place a WMO on the world map, adhereing to a provided position and rotation.
  placeWMO(wmo, position, rotation) {
    wmo.position.set(
      -(position.z - this.map.constructor.ZEROPOINT),
      -(position.x - this.map.constructor.ZEROPOINT),
      position.y
    );

    // Provided as (Z, X, -Y)
    wmo.rotation.set(
      rotation.z * Math.PI / 180,
      rotation.x * Math.PI / 180,
      -rotation.y * Math.PI / 180
    );

    // Adjust WMO rotation to match Wowser's axes.
    const quat = wmo.quaternion;
    quat.set(quat.x, quat.y, quat.z, -quat.w);

    this.map.add(wmo);
    wmo.updateMatrix();
  }

  // Every tick of the load interval, load a portion of any WMO groups pending load.
  loadWMOGroups() {
    this.loadWMOGroupsInternal(this.groupsPendingLoad, this.constructor.GROUP_LOAD_FACTOR);
  }

  loadLargeWMOGroups() {
    this.loadWMOGroupsInternal(this.largeGroupsPendingLoad, this.constructor.LARGE_GROUP_LOAD_FACTOR);
  }

  loadWMOGroupsInternal(groupsPendingLoad, loadFactor) {
    let count = 0;

    for (const entryID of groupsPendingLoad.keys()) {
      // An unload was triggered before we managed to load this group.
      if (!this.wmos.has(entryID) || this.entriesPendingUnload.has(entryID)) {
        groupsPendingLoad.delete(entryID);
        continue;
      }

      const wmo = this.wmos.get(entryID);

      const groupIndexes = groupsPendingLoad.get(entryID);

      for (const groupIndex of groupIndexes.values()) {
        this.loadWMOGroup(wmo, groupIndex);

        groupIndexes.delete(groupIndex);

        ++count;

        if (count > this.groupsPendingLoadCount * loadFactor) {
          return;
        }
      }

      // We've loaded all groups for this root WMO entry.
      if (groupIndexes.size === 0) {
        groupsPendingLoad.delete(entryID);

        // Now that groups are all accounted for, it's time to bring in the appropriate doodads.
        const doodadsPendingLoad = new Set(wmo.doodadSetEntries(wmo.requestedDoodadSet));
        this.doodadsPendingLoadCount += doodadsPendingLoad.size;
        this.doodadsPendingLoad.set(entryID, doodadsPendingLoad);
      }
    }
  }

  loadWMOGroup(wmo, groupIndex) {
    --this.groupsPendingLoadCount;
    ++this.groupCount;

    wmo.loadGroup(groupIndex);
  }

  loadWMODoodads() {
    let count = 0;

    for (const entryID of this.doodadsPendingLoad.keys()) {
      const wmo = this.wmos.get(entryID);

      if (!wmo) {
        continue;
      }

      const doodadEntries = this.doodadsPendingLoad.get(entryID);

      for (const doodadEntry of doodadEntries.values()) {
        this.loadWMODoodad(wmo, doodadEntry);

        doodadEntries.delete(doodadEntry);

        ++count;

        if (count > this.doodadsPendingLoadCount * this.constructor.DOODAD_LOAD_FACTOR) {
          return;
        }
      }

      // We've loaded all doodads for this root WMO entry.
      if (doodadEntries.size === 0) {
        this.doodadsPendingLoad.delete(entryID);
      }
    }
  }

  loadWMODoodad(wmo, entry) {
    --this.doodadsPendingLoadCount;
    ++this.doodadCount;

    wmo.renderDoodad(entry);
  }

  // Every tick of the load interval, unload a portion of any root WMOs pending unload.
  unloadWMOs() {
    let count = 0;

    for (const entry of this.entriesPendingUnload.values()) {
      // If the root WMO was already unloaded, remove it from the pending unloads.
      if (!this.wmos.has(entry.id)) {
        this.entriesPendingUnload.delete(entry.id);
        continue;
      }

      this.unloadWMO(entry);

      this.entriesPendingUnload.delete(entry.id);

      ++count;

      if (count > this.entriesPendingUnload.size * this.constructor.ROOT_LOAD_FACTOR) {
        return;
      }
    }
  }

  unloadWMO(entry) {
    const wmo = this.wmos.get(entry.id);
    this.wmos.delete(entry.id);

    this.groupCount -= wmo.loadedGroupCount;
    this.doodadCount -= wmo.loadedDoodadCount;

    if (this.groupsPendingLoad.has(entry.id)) {
      this.groupsPendingLoadCount -= this.groupsPendingLoad.get(entry.id).size;
      this.groupsPendingLoad.delete(entry.id);
    }

    if (this.largeGroupsPendingLoad.has(entry.id)) {
      this.groupsPendingLoadCount -= this.largeGroupsPendingLoad.get(entry.id).size;
      this.largeGroupsPendingLoad.delete(entry.id);
    }

    if (this.doodadsPendingLoad.has(entry.id)) {
      this.doodadsPendingLoadCount -= this.doodadsPendingLoad.get(entry.id).size;
      this.doodadsPendingLoad.delete(entry.id);
    }

    this.map.remove(wmo);
  }

  animate(delta, camera, cameraRotated) {
  }

}

export default WMOManager;
<|endoftext|>


<commit_before>/// <binding AfterBuild='uglify:serviceHuis' />
/*
This file in the main entry point for defining grunt tasks and using grunt plugins.
Click here to learn more. http://go.microsoft.com/fwlink/?LinkID=513275&clcid=0x409
*/
module.exports = function (grunt) {
    grunt.loadNpmTasks("grunt-typedoc");
    grunt.loadNpmTasks("grunt-contrib-uglify");
    grunt.loadNpmTasks("grunt-contrib-copy");
    grunt.loadNpmTasks("grunt-git-selective-deploy");

    grunt.initConfig({
        typedoc: {
            build: {
                options: {
                    module: 'commonjs',
                    target: 'es5',
                    out: 'docs/',
                    name: 'ServiceHuis'
                },
                src: 'serviceHuis.ts'
            }
        },

        copy: {
            nojekyll: {
                src: ".nojekyll", dest: "docs/.nojekyll"
            }
        },

        uglify: {
            serviceHuis: {
                files: {
                    'dist/serviceHuis.min.js': ['dist/serviceHuis.js']
                }
            }
        },

        git_deploy: {
            ghPages: {
                options: {
                    url: 'https://github.com/sboulema/ServiceHuis.git',
                    pretend: false,
                    buildIgnore: false,
                    remoteBranch: "gh-pages"
                },
                src: 'docs',
                dst: './docs-temp/'
            }
        }
    });

    grunt.registerTask("Docs: Generate + Publish", ["typedoc:build", "copy:nojekyll", "git_deploy:ghPages"]);
};<commit_msg>Fix Gruntfile<commit_after>/// <binding AfterBuild='uglify:serviceHuis' />
/*
This file in the main entry point for defining grunt tasks and using grunt plugins.
Click here to learn more. http://go.microsoft.com/fwlink/?LinkID=513275&clcid=0x409
*/
module.exports = function (grunt) {
    grunt.loadNpmTasks("grunt-typedoc");
    grunt.loadNpmTasks("grunt-contrib-uglify");
    grunt.loadNpmTasks("grunt-contrib-copy");
    grunt.loadNpmTasks("grunt-git-selective-deploy");

    grunt.initConfig({
        typedoc: {
            build: {
                options: {
                    module: 'commonjs',
                    target: 'es5',
                    out: 'docs/',
                    name: 'ServiceHuis'
                },
                src: 'serviceHuis.ts'
            }
        },

        copy: {
            nojekyll: {
                src: ".nojekyll", dest: "docs/.nojekyll"
            }
        },

        uglify: {
            serviceHuis: {
                files: {
                    'dist/serviceHuis.min.js': ['dist/serviceHuis.js']
                }
            }
        },

        git_deploy: {
            ghPages: {
                options: {
                    url: 'https://github.com/sboulema/ServiceHuis.git',
                    pretend: false,
                    buildIgnore: false,
                    remoteBranch: "gh-pages"
                },
                src: 'docs',
                dst: './docs-temp/'
            }
        }
    });

    grunt.registerTask("Docs_Generate_Publish", ["typedoc:build", "copy:nojekyll", "git_deploy:ghPages"]);
};<|endoftext|>


<commit_before>import Component from '@ember/component';
import calculatePosition from 'ember-basic-dropdown/utils/calculate-position';
import {computed} from '@ember/object';
import {htmlSafe} from '@ember/string';
import {inject as injectService} from '@ember/service';

export default Component.extend({
    config: injectService(),
    feature: injectService(),
    ghostPaths: injectService(),
    router: injectService('router'),
    session: injectService(),
    ui: injectService(),

    tagName: 'nav',
    classNames: ['gh-nav'],
    classNameBindings: ['open'],

    open: false,
    iconStyle: '',

    // the menu has a rendering issue (#8307) when the the world is reloaded
    // during an import which we have worked around by not binding the icon
    // style directly. However we still need to keep track of changing icons
    // so that we can refresh when a new icon is uploaded
    didReceiveAttrs() {
        this._setIconStyle();
    },

    mouseEnter() {
        this.sendAction('onMouseEnter');
    },

    showMenuExtension: computed('config.clientExtensions.menu', 'session.user.isOwner', function() {
        return this.get('config.clientExtensions.menu') && this.get('session.user.isOwner');
    }),

    showDropdownExtension: computed('config.clientExtensions.dropdown', 'session.user.isOwner', function() {
        return this.get('config.clientExtensions.dropdown') && this.get('session.user.isOwner');
    }),

    showScriptExtension: computed('config.clientExtensions.script', 'session.user.isOwner', function() {
        return this.get('config.clientExtensions.script') && this.get('session.user.isOwner');
    }),

    // equivalent to "left: auto; right: -20px"
    userDropdownPosition(trigger, dropdown) {
        let {horizontalPosition, verticalPosition, style} = calculatePosition(...arguments);
        let {width: dropdownWidth} = dropdown.firstElementChild.getBoundingClientRect();

        style.right += (dropdownWidth - 20);
        style['z-index'] = 1100;

        return {horizontalPosition, verticalPosition, style};
    },

    _setIconStyle() {
        let icon = this.get('icon');

        if (icon === this._icon) {
            return;
        }

        let subdirRegExp = new RegExp(`^${this.get('ghostPaths.subdir')}`);
        let blogIcon = icon ? icon : 'favicon.ico';
        let iconUrl;

        blogIcon = blogIcon.replace(subdirRegExp, '');

        iconUrl = this.get('ghostPaths.url').join(this.get('config.blogUrl'), blogIcon).replace(/\/$/, '');
        iconUrl += `?t=${(new Date()).valueOf()}`;

        this.set('iconStyle', htmlSafe(`background-image: url(${iconUrl})`));
        this._icon = icon;
    },

    actions: {
        showMarkdownHelp() {
            this.sendAction('showMarkdownHelp');
        }
    }
});
<commit_msg>🐛 Fixed blog icon display in admin menu when using a storage adapter (#831)<commit_after>import Component from '@ember/component';
import calculatePosition from 'ember-basic-dropdown/utils/calculate-position';
import {computed} from '@ember/object';
import {htmlSafe} from '@ember/string';
import {inject as injectService} from '@ember/service';

export default Component.extend({
    config: injectService(),
    feature: injectService(),
    ghostPaths: injectService(),
    router: injectService('router'),
    session: injectService(),
    ui: injectService(),

    tagName: 'nav',
    classNames: ['gh-nav'],
    classNameBindings: ['open'],

    open: false,
    iconStyle: '',

    // the menu has a rendering issue (#8307) when the the world is reloaded
    // during an import which we have worked around by not binding the icon
    // style directly. However we still need to keep track of changing icons
    // so that we can refresh when a new icon is uploaded
    didReceiveAttrs() {
        this._setIconStyle();
    },

    mouseEnter() {
        this.sendAction('onMouseEnter');
    },

    showMenuExtension: computed('config.clientExtensions.menu', 'session.user.isOwner', function() {
        return this.get('config.clientExtensions.menu') && this.get('session.user.isOwner');
    }),

    showDropdownExtension: computed('config.clientExtensions.dropdown', 'session.user.isOwner', function() {
        return this.get('config.clientExtensions.dropdown') && this.get('session.user.isOwner');
    }),

    showScriptExtension: computed('config.clientExtensions.script', 'session.user.isOwner', function() {
        return this.get('config.clientExtensions.script') && this.get('session.user.isOwner');
    }),

    // equivalent to "left: auto; right: -20px"
    userDropdownPosition(trigger, dropdown) {
        let {horizontalPosition, verticalPosition, style} = calculatePosition(...arguments);
        let {width: dropdownWidth} = dropdown.firstElementChild.getBoundingClientRect();

        style.right += (dropdownWidth - 20);
        style['z-index'] = 1100;

        return {horizontalPosition, verticalPosition, style};
    },

    _setIconStyle() {
        let icon = this.get('icon');

        if (icon === this._icon) {
            return;
        }

        this._icon = icon;

        if (icon && icon.match(/^https?:\/\//i)) {
            this.set('iconStyle', htmlSafe(`background-image: url(${icon})`));
            return;
        }

        let subdirRegExp = new RegExp(`^${this.get('ghostPaths.subdir')}`);
        let blogIcon = icon ? icon : 'favicon.ico';
        let iconUrl;

        blogIcon = blogIcon.replace(subdirRegExp, '');

        iconUrl = this.get('ghostPaths.url').join(this.get('config.blogUrl'), blogIcon).replace(/\/$/, '');
        iconUrl += `?t=${(new Date()).valueOf()}`;

        this.set('iconStyle', htmlSafe(`background-image: url(${iconUrl})`));
    },

    actions: {
        showMarkdownHelp() {
            this.sendAction('showMarkdownHelp');
        }
    }
});
<|endoftext|>


<commit_before>import Ember from 'ember'; // eslint-disable-line
import fetch from 'fetch'; // eslint-disable-line

export default Ember.Component.extend({
  district: null,
  projects: Ember.computed('district', function() {
    const boro = this.get('district.boro').toLowerCase();
    const cd = this.get('district.cd');
    const URL = `https://lucats.planninglabs.nyc/urlurp/cd/${boro}/${cd}.json`;

    return fetch(URL)
      .then(data => data.json())
      .then((data) => {
        data.forEach((d) => {
          d.projectName = d.projectName !== '' ? d.projectName : 'Unnamed Project'; // eslint-disable-line
        });

        return data;
      });
  }),
  active: Ember.computed('projects', function() {
    const projects = this.get('projects');
    return projects.then(data => data.filter(d => d.status === 'active'));
  }),

  completed: Ember.computed('projects', function() {
    const projects = this.get('projects');
    return projects.then(data => data.filter(d => d.status === 'completed'));
  }),
});
<commit_msg>HOTFIX remove space for staten island URL building<commit_after>import Ember from 'ember'; // eslint-disable-line
import fetch from 'fetch'; // eslint-disable-line

export default Ember.Component.extend({
  district: null,
  projects: Ember.computed('district', function() {
    // remove space in 'staten island'
    const boro = this.get('district.boro').replace(/\s+/g, '').toLowerCase();
    const cd = this.get('district.cd');
    const URL = `https://lucats.planninglabs.nyc/urlurp/cd/${boro}/${cd}.json`;

    return fetch(URL)
      .then(data => data.json())
      .then((data) => {
        data.forEach((d) => {
          d.projectName = d.projectName !== '' ? d.projectName : 'Unnamed Project'; // eslint-disable-line
        });

        return data;
      });
  }),
  active: Ember.computed('projects', function() {
    const projects = this.get('projects');
    return projects.then(data => data.filter(d => d.status === 'active'));
  }),

  completed: Ember.computed('projects', function() {
    const projects = this.get('projects');
    return projects.then(data => data.filter(d => d.status === 'completed'));
  }),
});
<|endoftext|>