<commit_before>(function () {

    /* global angular */
    angular.module('angular-semantic-admin')
        .controller('AsadminController', Controller);

    function Controller($scope, $window, $timeout, Asadmin) {

        var that = this;
        var scope = $scope;
        var window = angular.element($window);
        var resizeWatchers = ['Asadmin.sidebar.open', 'Asadmin.sidebar.visible', 'Asadmin.sidebar.compact'];
        var resizeDelay = 400;

        scope.Asadmin = Asadmin;

        this.switchSidebar = function () {
            var behavior = Asadmin.getSidebar().getSwitchBehavior();

            if (behavior == 'visible') {
                Asadmin.getSidebar().toggleVisible();
            } else if (behavior == 'compact') {
                Asadmin.getSidebar().toggleCompact();
            }

            Asadmin.getSidebar().setOpen(false);
            $scope.$broadcast('switch-sidebar');
        };

        scope.$watchGroup(resizeWatchers, function() {
            $timeout(function() {
                window.trigger('resize');
            }, resizeDelay);
        });
    }

})();<commit_msg>update<commit_after>(function () {

    /* global angular */
    angular.module('angular-semantic-admin')
        .controller('AsadminController', Controller);

    function Controller($scope, $window, $timeout, Asadmin) {

        var that = this;
        var scope = $scope;
        var window = angular.element($window);
        var resizeWatchers = ['Asadmin.sidebar.open', 'Asadmin.sidebar.visible', 'Asadmin.sidebar.compact'];
        var resizeDelay = 400;
        var sidebar = Asadmin.getSidebar();

        scope.Asadmin = Asadmin;

        that.switchSidebar = function () {
            var behavior = sidebar.getSwitchBehavior();

            if (behavior == 'visible') {
                sidebar.toggleVisible();
            } else if (behavior == 'compact') {
                sidebar.toggleCompact();
            }

            sidebar.setOpen(false);
            scope.$broadcast('switch-sidebar');
        };

        scope.$watchGroup(resizeWatchers, function() {
            $timeout(function() {
                window.trigger('resize');
            }, resizeDelay);
        });
    }

})();<|endoftext|>


<commit_before>import React, {Component} from 'react';
import {render} from 'react-dom';
import PropTypes from 'prop-types';
import {Meteor} from 'meteor/meteor';
import {createContainer} from 'meteor/react-meteor-data';
import styled, {injectGlobal} from 'styled-components';
import {grey} from '@quarterto/colours';
import {Session} from 'meteor/session';
import _ from 'lodash';

import {Cards} from '../src/collections';

injectGlobal`
	body {
		margin: 0;
		font-family: system-ui;
	}
`;

const distances = (graph, start, visited = {[start]: 0}, depth = 1) => {
	const next = graph[start];
	const nextDepth = depth + 1;

	next &&
		next
			.filter(node => {
				if (node in visited) return false;
				visited[node] = depth;
				return true;
			})
			.forEach(node => {
				distances(graph, node, visited, nextDepth);
			});

	return visited;
};

const buildGraph = cards =>
	cards.reduce(
		(graph, card) => Object.assign(graph, {[card._id]: card.related}),
		{}
	);

const getValue = el =>
	el[
		{
			number: 'valueAsNumber',
			range: 'valueAsNumber',
			date: 'valueAsDate',
		}[el.type] || 'value'
	];

class Field extends Component {
	static get contextTypes() {
		return {
			state: PropTypes.object,
			setState: PropTypes.func,
		};
	}

	render() {
		const {name} = this.props;
		return (
			<input
				type="text"
				{...this.props}
				value={this.context.state[name] || ''}
				onChange={ev =>
					this.context.setState({[name]: getValue(ev.target)})}
			/>
		);
	}
}

class Form extends Component {
	constructor(props, ...args) {
		super(props, ...args);

		this.state = props.initialData;

		this.setState = this.setState.bind(this);
		this.onSubmit = this.onSubmit.bind(this);
	}

	getChildContext() {
		return {
			state: this.state,
			setState: this.setState,
		};
	}

	static get childContextTypes() {
		return {
			state: PropTypes.object,
			setState: PropTypes.func,
		};
	}

	static get defaultProps() {
		return {initialData: {}};
	}

	onSubmit(ev) {
		ev.preventDefault();
		Promise.resolve(this.props.onSubmit(this.state)).then(() => {
			this.state = this.props.initialData;
			this.forceUpdate();
		});
	}

	render() {
		return (
			<form onSubmit={this.onSubmit}>
				{this.props.children}
			</form>
		);
	}
}

const CardPrimitive = styled.div`
	border: 1px solid ${grey[5]};
	padding: 1em;
	border-radius: 2px;
`;

class Toggler extends Component {
	constructor(...args) {
		super(...args);
		this.state = {on: false};
		this.toggle = this.toggle.bind(this);
	}

	toggle() {
		this.setState(({on}) => ({on: !on}));
	}

	render() {
		return this.state.on
			? <this.props.active toggle={this.toggle} {...this.props} />
			: <this.props.inactive toggle={this.toggle} {...this.props} />;
	}
}

const preventingDefault = fn => ev => {
	ev.preventDefault();
	fn(ev);
};

// TODO: related cards
// array of card ids
// fetch relatedcards by thing
// on delete find cards that had this as related and update

const selectValue = el => el.options[el.selectedIndex].value;

const CardSelect = ({cardsById, onSelect}) =>
	<select
		value=""
		onChange={ev => onSelect(cardsById[selectValue(ev.target)])}
	>
		<option disabled value="" />
		{_.map(cardsById, card =>
			<option key={card._id} value={card._id}>{card.title}</option>
		)}
	</select>;

const CardSelectContainer = createContainer(
	({skip}) => ({
		cardsById: _.keyBy(Cards.find({_id: {$nin: skip}}).fetch(), '_id'),
	}),
	CardSelect
);

const EditCard = ({card, saveCard, toggle, deleteCard}) =>
	<Form
		onSubmit={data => {
			saveCard(data);
			if (toggle) toggle();
		}}
		initialData={card}
	>
		<Field name="title" />
		<Field name="text" />
		<button>{toggle ? '✓' : '+'}</button>
		{toggle && <button onClick={preventingDefault(toggle)}>×</button>}
		{deleteCard &&
			<button onClick={preventingDefault(() => deleteCard(card))}>
				🗑
			</button>}
	</Form>;

const ShowCard = ({card, relatedCards, toggle, addRelated, selectCard}) =>

		{toggle && <button onClick={toggle}>Edit</button>}

<a href={`#${card._id}`} onClick={selectCard}>{card.title}

{card.text}

			{relatedCards.map(related =>

{related.title}

			)}

				<CardSelectContainer
					onSelect={addRelated}
					skip={[card._id].concat(card.related || [])}
				/>

;

const ShowCardContainer = createContainer(
	({card}) => ({
		relatedCards: Cards.find({_id: {$in: card.related || []}}).fetch(),
		addRelated(related) {
			Cards.update(card._id, {
				$addToSet: {related: related._id},
			});
		},
		selectCard() {
			Session.set('selectedCard', card._id);
		},
	}),
	ShowCard
);

const Card = props =>
	<CardPrimitive>
		<Toggler active={EditCard} inactive={ShowCardContainer} {...props} />
	</CardPrimitive>;

const List = styled.div`
	display: grid;
	padding: 1em;
	grid-gap: 1em;
	grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
`;

const CardList = ({cards, saveCard, deleteCard}) =>
	<List>
		{cards.map(card =>
			<Card
				key={card._id}
				card={card}
				saveCard={saveCard}
				deleteCard={deleteCard}
			/>
		)}

		<CardPrimitive>
			<EditCard card={{}} saveCard={saveCard} />
		</CardPrimitive>
	</List>;

const CardListContainer = createContainer(() => {
	const selectedCard = Session.get('selectedCard');
	let cards = Cards.find({}).fetch();

	if (selectedCard) {
		const graph = buildGraph(cards);
		const d = distances(graph, selectedCard);

		cards.forEach(card => (card.sortedIndex = d[card._id]));
	}

	return {
		cards: _.sortBy(cards, 'sortedIndex'),

		saveCard(card) {
			if (card._id) {
				Cards.update(card._id, card);
			} else {
				Cards.insert(card);
			}
		},

		deleteCard(card) {
			Cards.remove(card._id);

			const relatedCards = Cards.find({related: card._id}).fetch();
			relatedCards.forEach(related => {
				Cards.update(related._id, {
					$pull: {related: card._id},
				});
			});
		},
	};
}, CardList);

const App = () => <CardListContainer />;

Meteor.startup(() => {
	render(<App />, document.querySelector('main'));
});
<commit_msg>sort by name also<commit_after>import React, {Component} from 'react';
import {render} from 'react-dom';
import PropTypes from 'prop-types';
import {Meteor} from 'meteor/meteor';
import {createContainer} from 'meteor/react-meteor-data';
import styled, {injectGlobal} from 'styled-components';
import {grey} from '@quarterto/colours';
import {Session} from 'meteor/session';
import _ from 'lodash';

import {Cards} from '../src/collections';

injectGlobal`
	body {
		margin: 0;
		font-family: system-ui;
	}
`;

const distances = (graph, start, visited = {[start]: 0}, depth = 1) => {
	const next = graph[start];
	const nextDepth = depth + 1;

	next &&
		next
			.filter(node => {
				if (node in visited) return false;
				visited[node] = depth;
				return true;
			})
			.forEach(node => {
				distances(graph, node, visited, nextDepth);
			});

	return visited;
};

const buildGraph = cards =>
	cards.reduce(
		(graph, card) => Object.assign(graph, {[card._id]: card.related}),
		{}
	);

const getValue = el =>
	el[
		{
			number: 'valueAsNumber',
			range: 'valueAsNumber',
			date: 'valueAsDate',
		}[el.type] || 'value'
	];

class Field extends Component {
	static get contextTypes() {
		return {
			state: PropTypes.object,
			setState: PropTypes.func,
		};
	}

	render() {
		const {name} = this.props;
		return (
			<input
				type="text"
				{...this.props}
				value={this.context.state[name] || ''}
				onChange={ev =>
					this.context.setState({[name]: getValue(ev.target)})}
			/>
		);
	}
}

class Form extends Component {
	constructor(props, ...args) {
		super(props, ...args);

		this.state = props.initialData;

		this.setState = this.setState.bind(this);
		this.onSubmit = this.onSubmit.bind(this);
	}

	getChildContext() {
		return {
			state: this.state,
			setState: this.setState,
		};
	}

	static get childContextTypes() {
		return {
			state: PropTypes.object,
			setState: PropTypes.func,
		};
	}

	static get defaultProps() {
		return {initialData: {}};
	}

	onSubmit(ev) {
		ev.preventDefault();
		Promise.resolve(this.props.onSubmit(this.state)).then(() => {
			this.state = this.props.initialData;
			this.forceUpdate();
		});
	}

	render() {
		return (
			<form onSubmit={this.onSubmit}>
				{this.props.children}
			</form>
		);
	}
}

const CardPrimitive = styled.div`
	border: 1px solid ${grey[5]};
	padding: 1em;
	border-radius: 2px;
`;

class Toggler extends Component {
	constructor(...args) {
		super(...args);
		this.state = {on: false};
		this.toggle = this.toggle.bind(this);
	}

	toggle() {
		this.setState(({on}) => ({on: !on}));
	}

	render() {
		return this.state.on
			? <this.props.active toggle={this.toggle} {...this.props} />
			: <this.props.inactive toggle={this.toggle} {...this.props} />;
	}
}

const preventingDefault = fn => ev => {
	ev.preventDefault();
	fn(ev);
};

// TODO: related cards
// array of card ids
// fetch relatedcards by thing
// on delete find cards that had this as related and update

const selectValue = el => el.options[el.selectedIndex].value;

const CardSelect = ({cardsById, onSelect}) =>
	<select
		value=""
		onChange={ev => onSelect(cardsById[selectValue(ev.target)])}
	>
		<option disabled value="" />
		{_.map(cardsById, card =>
			<option key={card._id} value={card._id}>{card.title}</option>
		)}
	</select>;

const CardSelectContainer = createContainer(
	({skip}) => ({
		cardsById: _.keyBy(Cards.find({_id: {$nin: skip}}).fetch(), '_id'),
	}),
	CardSelect
);

const EditCard = ({card, saveCard, toggle, deleteCard}) =>
	<Form
		onSubmit={data => {
			saveCard(data);
			if (toggle) toggle();
		}}
		initialData={card}
	>
		<Field name="title" />
		<Field name="text" />
		<button>{toggle ? '✓' : '+'}</button>
		{toggle && <button onClick={preventingDefault(toggle)}>×</button>}
		{deleteCard &&
			<button onClick={preventingDefault(() => deleteCard(card))}>
				🗑
			</button>}
	</Form>;

const ShowCard = ({card, relatedCards, toggle, addRelated, selectCard}) =>

		{toggle && <button onClick={toggle}>Edit</button>}

<a href={`#${card._id}`} onClick={selectCard}>{card.title}

{card.text}

			{relatedCards.map(related =>

{related.title}

			)}

				<CardSelectContainer
					onSelect={addRelated}
					skip={[card._id].concat(card.related || [])}
				/>

;

const ShowCardContainer = createContainer(
	({card}) => ({
		relatedCards: Cards.find({_id: {$in: card.related || []}}).fetch(),
		addRelated(related) {
			Cards.update(card._id, {
				$addToSet: {related: related._id},
			});
		},
		selectCard() {
			Session.set('selectedCard', card._id);
		},
	}),
	ShowCard
);

const Card = props =>
	<CardPrimitive>
		<Toggler active={EditCard} inactive={ShowCardContainer} {...props} />
	</CardPrimitive>;

const List = styled.div`
	display: grid;
	padding: 1em;
	grid-gap: 1em;
	grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
`;

const CardList = ({cards, saveCard, deleteCard}) =>
	<List>
		{cards.map(card =>
			<Card
				key={card._id}
				card={card}
				saveCard={saveCard}
				deleteCard={deleteCard}
			/>
		)}

		<CardPrimitive>
			<EditCard card={{}} saveCard={saveCard} />
		</CardPrimitive>
	</List>;

const CardListContainer = createContainer(() => {
	const selectedCard = Session.get('selectedCard');
	let cards = Cards.find({}).fetch();

	if (selectedCard) {
		const graph = buildGraph(cards);
		const d = distances(graph, selectedCard);

		cards.forEach(card => (card.sortedIndex = d[card._id]));
	}

	return {
		cards: _.orderBy(cards, ['sortedIndex', 'title']),

		saveCard(card) {
			if (card._id) {
				Cards.update(card._id, card);
			} else {
				Cards.insert(card);
			}
		},

		deleteCard(card) {
			Cards.remove(card._id);

			const relatedCards = Cards.find({related: card._id}).fetch();
			relatedCards.forEach(related => {
				Cards.update(related._id, {
					$pull: {related: card._id},
				});
			});
		},
	};
}, CardList);

const App = () => <CardListContainer />;

Meteor.startup(() => {
	render(<App />, document.querySelector('main'));
});
<|endoftext|>


<commit_before>/**
 * Created by Jameshwart Villarmea Lopez on 4/7/2015.
 */

var x = document.getElementById("map_holder");
var map;
var infowindow;
var latlng;
var request;
var selected;
var sortyby ="PROMINENCE";
var place_details_sortbyprominence=[];
var place_details_sorbydistance = [];
$(document).ready(function () {

    $(".navbar-brand").click(function(){
        var p_id = "ChIJZz1DaxqZqTMRYZcdlmHube0";
        $.post("public/userAction/getPlaceReview.php",{placeid:p_id},function(data){
            if(data){
                user_place_review = data;
                var user_review = JSON.parse(data);
                console.log(JSON.stringify(user_review));
            }
        });
    });

    $(document).on("click",".add_review",function(){
        $("#frm_reviews").attr('andid','james');
    });
    $("#selecta").select2({
        placeholder: "Select Places...",
        allowClear: true,
        maximumSelectionLength: 3
    });

    $(document).on("change","#selecta",function(){
        selected = $("#selecta").select2("val");
        request = {
            location: latlng,
            radius:800,
            rankBy: google.maps.places.RankBy.PROMINENCE,
            types: selected
        };

    });

    $('#cmdSubmit').click(function () {
        $("#mnu_1,#your").css("display","block");
        place_details_sortbyprominence =[];
        place_details_sorbydistance = [];
        localStorage.removeItem("leloo_by_prominence");
        localStorage.removeItem("leloo_by_distance");
        if ($("#selecta").select2("val")) {
            $(this).hide();
            $("#noSubmit").show();

            getLocation();

            setTimeout(function () {
                $("#noSubmit").hide();
                $("#cmdSubmit").fadeIn();
            }, 2000)
        } else {
            $('#alert-msg').html("
 <button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×</button>Ops! Please select place/s.
");

        }
    });

    $(".sortby").click(function(){
        $(".sortby").removeClass("active");
        $(this).addClass("active");

            if($(this).text() ==='Distance'){

                if("leloo_by_distance" in localStorage){
                    display_sorted_results(localStorage.getItem("leloo_by_distance"))
                }else{

                    if($("#selecta").select2("val")){
                        request.types=selected;
                        request.radius=null;
                        request.rankBy =google.maps.places.RankBy.DISTANCE;
                        getLocation();
                    }

                }

            }else if($(this).text() ==='Popularity'){

                if("leloo_by_prominence" in localStorage){

                    display_sorted_results(localStorage.getItem("leloo_by_prominence"))
                }else{
                    if($("#selecta").select2("val")){
                        request.types=selected;
                        request.radius=800;
                        request.rankBy =google.maps.places.RankBy.PROMINENCE;
                        getLocation();
                    }

                }
            }

    });
});

function getLocation() {
    //get current position
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(showPosition, showError);
    } else {
        x.innerHTML = "Geolocation is not supported by this browser.";
    }
}

function showPosition(position) {

    document.querySelector("#mapcanvas").style.height = '300px';
    latlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);

    var myOptions = {
        zoom: 15,
        center: latlng,
        mapTypeControl: false,
        navigationControlOptions: {style: google.maps.NavigationControlStyle.SMALL} ,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    map = new google.maps.Map(document.getElementById("mapcanvas"), myOptions);

    var infowindowmain = new google.maps.InfoWindow({
        map: map,
        position: latlng,
        content: "You are here! (at least within a " + position.coords.accuracy + " meter radius)"
    });

    var marker = new google.maps.Marker({
        position: latlng,
        map: map,
        title: "You are here! (at least within a " + position.coords.accuracy + " meter radius)"
    });
    google.maps.event.addListener(marker, 'click', function () {
        infowindow.setContent("You are here! (at least within a " + position.coords.accuracy + " meter radius)");
        infowindow.open(map, this);
    });

    request.location = latlng;

    selected = $("#selecta").select2("val");
    infowindow = new google.maps.InfoWindow();
    var service = new google.maps.places.PlacesService(map);
    service.nearbySearch(request, callback);

    findhim(latlng);

}

function findhim(point) {
    var geocoder = new google.maps.Geocoder();
    geocoder.geocode({latLng: point}, function (results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            if (results[0]) {

                var p_name = (results[0].name) ? "Place name: " + results[0].name + "
" : '';
                var p_address = (results[0].formatted_address) ? "
" + results[0].formatted_address + "
" : '';

                document.getElementById("location_container").innerHTML = p_name + p_address;
            }
        }
    });

}

function callback(results, status) {
    if (status == google.maps.places.PlacesServiceStatus.OK) {
        for (var i = 0; i < results.length; i++) {
            if(checkRadiusDistance(results[i],latlng,825)){
                createMarker(results[i]);
            }
        }

        $('#alert-msg').html("
 <button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×</button>Returned " + results.length + " results
");

        $("#mnu_2,#about,#h_place,#btn-group-places").css("display","block");
        $("#btn-group-places").css("display","inline-block");
    }
    else
    {
        $('#alert-msg').html("
 <button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×</button>Returned " + results.length + " results
");
        $("#mnu_2,#about,#h_place,#btn-group-places").css("display","none");

    }
}

function checkRadiusDistance(place,latlng,radius) {
    return google.maps.geometry.spherical.computeDistanceBetween(place.geometry.location, latlng) <= radius;
}

function createMarker(place) {

    var placeLoc = place.geometry.location;

    var marker = new google.maps.Marker({
        map: map,
        position: place.geometry.location
    });

    var requestdata = {
        placeId: place.place_id
    };

    document.getElementById("placeres").innerHTML="";
    var service = new google.maps.places.PlacesService(map);
    service.getDetails(requestdata, function(placedata, status) {

        if (status == google.maps.places.PlacesServiceStatus.OK)
        {

            if(request.rankBy === google.maps.places.RankBy.PROMINENCE){
                place_details_sortbyprominence.push((placedata));
                localStorage.setItem("leloo_by_prominence",JSON.stringify(place_details_sortbyprominence));
                display_sorted_results(localStorage.getItem("leloo_by_prominence"));

            }else if(request.rankBy === google.maps.places.RankBy.DISTANCE){
                place_details_sorbydistance.push((placedata));
                localStorage.setItem("leloo_by_distance",JSON.stringify(place_details_sorbydistance));
                display_sorted_results(localStorage.getItem("leloo_by_distance"));

            }

        }
    });

    google.maps.event.addListener(marker, 'click', function() {
        infowindow.setContent(getPlace_contenet(place));
        infowindow.open(map, this);
    });

}
function display_sorted_results(localstorage_data){

    var data = localstorage_data.replace(/"\\"/g,"'").replace(/\\""/g,"'");

    data = JSON.parse(data);
    document.getElementById("places").innerHTML="";
    document.getElementById("p_user_review").innerHTML="";
    var str_container = "";
    var u_review = "";
    for(var i = 0 ; i < data.length ; i++){

        var placedata= data[i];

        var place_name = "
"+placedata.name+"
";
        var place_address = "
"+placedata.formatted_address+"
";
        var place_img_representation = "";
        var place_internationa_phonenuber =(typeof placedata.international_phone_number !=='undefined')?"
"+placedata.international_phone_number +"
":"";

        var place_rating =(typeof placedata.rating !=='undefined')? "
Rating based on aggregated user reviews:"+rating_display(placedata.rating)+"
":"";
        var place_website =(typeof placedata.website !== 'undefined')? "
VISIT WEBSITE":"";

        var user_reviews = "";
        if(typeof placedata.reviews !=='undefined'){
            for(var j = 0 ; j < placedata.reviews.length; j ++){

                var place_reviews = placedata.reviews[j];
                var review_author = "
"+place_reviews.author_name+"
";
                var review_authorlink = (typeof place_reviews.author_url !=='undefined')? ""+review_author+"":""+review_author+"";
                var review_rating ="
Rating:"+ rating_display(place_reviews.rating)+"
";
                var review_text = "
"+place_reviews.text+"
";

                 user_reviews +="
"+review_authorlink+review_rating+review_text+"
";
            }
        }

        u_review +=(getUser_Review(placedata.place_id,place_name,place_address));
        var final_users_review = "
"+user_reviews+"
";

        str_container += "
 <button class='btn btn-primary btn-sm add_review'  data-place_id= '"+placedata.place_id+"'> Add reviews</button></button>"+place_name+place_address+place_img_representation+place_internationa_phonenuber+place_rating+place_website + final_users_review +"
";
    }
    document.getElementById("p_user_review").innerHTML=u_review;

    document.getElementById("placeres").innerHTML=str_container;
}

function getUser_Review(placeid,place_name,place_address){
    var p_id = placeid;
    var u_review = "";

    $.ajax({
        method:"POST",
        url:"public/userAction/getPlaceReview.php",
        data:"placeid="+p_id,
        success:function(data){
                if(data){
                    $("#p_user_review").html("");
                    var db_user_review = JSON.parse(data);
                    for(i = 0 ;i < db_user_review.length; i++ ){
                        var db_author_review =  "
"+db_user_review[i].full_name+"
";
                        var db_rating_review =  "
Rating:"+ rating_display(db_user_review[i].rating)+"
";
                        var db_text_review   =  "
"+db_user_review[i].reviewtext+"
";

                        u_review +="
"+db_author_review+db_rating_review+db_text_review+"
";

                    }
                   var db_review = "
"+place_name+place_address+"
"+u_review+"

";

                    u_review = db_review;
                }
        },
        async:false
    });

    return u_review;

}

function getPlace_contenet(place) {
    var content = '';
    content += '
';
    content += '
';
    content += '	';
    var url=(typeof place.url !=='undefined')?place.url:'#';

    content += '' + place.name + '
';
    content += '
Address:	' + place.vicinity + '
';
    if (place.formatted_phone_number) {
        content += '
Telephone:	' + place.formatted_phone_number + '
';
    }

    if (place.rating) {
        rating_display(place.rating);
        content += '
Rating:	' +  rating_display(place.rating); + '
';

    }
    if (place.website) {
        var fullUrl = place.website;
        var website = hostnameRegexp.exec(place.website);
        if (website == null) {
            website = 'http://' + place.website + '/';
            fullUrl = website;
        }
        content += '
Website:	' + website + '
';
    }
    content += '
';
    return content;
}

function showError(error) {
    switch (error.code) {
        case error.PERMISSION_DENIED:
            x.innerHTML = "User denied the request for Geolocation."
            break;
        case error.POSITION_UNAVAILABLE:
            x.innerHTML = "Location information is unavailable."
            break;
        case error.TIMEOUT:
            x.innerHTML = "The request to get user location timed out."
            break;
        case error.UNKNOWN_ERROR:
            x.innerHTML = "An unknown error occurred."
            break;
    }
}

function ucfirst(str) {
    var firstLetter = str.substr(0, 1);
    return firstLetter.toUpperCase() + str.substr(1);
}

function rating_display(rating){
    var html_rating="";
    for (var i = 0; i < 5; i++) {
        if (rating < (i + 0.5)) {
            html_rating += '✩';
        } else {
            html_rating += '✭';
        }
    }

    return html_rating;
}

<commit_msg>modify request to asynchronous, create fallback function for it<commit_after>/**
 * Created by Jameshwart Villarmea Lopez on 4/7/2015.
 */

var x = document.getElementById("map_holder");
var map;
var infowindow;
var latlng;
var request;
var selected;
var sortyby ="PROMINENCE";
var place_details_sortbyprominence=[];
var place_details_sorbydistance = [];
$(document).ready(function () {

    $(".navbar-brand").click(function(){
        var p_id = "ChIJZz1DaxqZqTMRYZcdlmHube0";
        $.post("public/userAction/getPlaceReview.php",{placeid:p_id},function(data){
            if(data){
                user_place_review = data;
                var user_review = JSON.parse(data);
                console.log(JSON.stringify(user_review));
            }
        });
    });

    $(document).on("click",".add_review",function(){
        $("#frm_reviews").attr('andid','james');
    });
    $("#selecta").select2({
        placeholder: "Select Places...",
        allowClear: true,
        maximumSelectionLength: 3
    });

    $(document).on("change","#selecta",function(){
        selected = $("#selecta").select2("val");
        request = {
            location: latlng,
            radius:800,
            rankBy: google.maps.places.RankBy.PROMINENCE,
            types: selected
        };

    });

    $('#cmdSubmit').click(function () {
        $("#mnu_1,#your").css("display","block");
        place_details_sortbyprominence =[];
        place_details_sorbydistance = [];
        localStorage.removeItem("leloo_by_prominence");
        localStorage.removeItem("leloo_by_distance");
        if ($("#selecta").select2("val")) {
            $(this).hide();
            $("#noSubmit").show();

            getLocation();

            setTimeout(function () {
                $("#noSubmit").hide();
                $("#cmdSubmit").fadeIn();
            }, 2000)
        } else {
            $('#alert-msg').html("
 <button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×</button>Ops! Please select place/s.
");

        }
    });

    $(".sortby").click(function(){
        $(".sortby").removeClass("active");
        $(this).addClass("active");

            if($(this).text() ==='Distance'){

                if("leloo_by_distance" in localStorage){
                    display_sorted_results(localStorage.getItem("leloo_by_distance"))
                }else{

                    if($("#selecta").select2("val")){
                        request.types=selected;
                        request.radius=null;
                        request.rankBy =google.maps.places.RankBy.DISTANCE;
                        getLocation();
                    }

                }

            }else if($(this).text() ==='Popularity'){

                if("leloo_by_prominence" in localStorage){

                    display_sorted_results(localStorage.getItem("leloo_by_prominence"))
                }else{
                    if($("#selecta").select2("val")){
                        request.types=selected;
                        request.radius=800;
                        request.rankBy =google.maps.places.RankBy.PROMINENCE;
                        getLocation();
                    }

                }
            }

    });
});

function getLocation() {
    //get current position
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(showPosition, showError);
    } else {
        x.innerHTML = "Geolocation is not supported by this browser.";
    }
}

function showPosition(position) {

    document.querySelector("#mapcanvas").style.height = '300px';
    latlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);

    var myOptions = {
        zoom: 15,
        center: latlng,
        mapTypeControl: false,
        navigationControlOptions: {style: google.maps.NavigationControlStyle.SMALL} ,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    map = new google.maps.Map(document.getElementById("mapcanvas"), myOptions);

    var infowindowmain = new google.maps.InfoWindow({
        map: map,
        position: latlng,
        content: "You are here! (at least within a " + position.coords.accuracy + " meter radius)"
    });

    var marker = new google.maps.Marker({
        position: latlng,
        map: map,
        title: "You are here! (at least within a " + position.coords.accuracy + " meter radius)"
    });
    google.maps.event.addListener(marker, 'click', function () {
        infowindow.setContent("You are here! (at least within a " + position.coords.accuracy + " meter radius)");
        infowindow.open(map, this);
    });

    request.location = latlng;

    selected = $("#selecta").select2("val");
    infowindow = new google.maps.InfoWindow();
    var service = new google.maps.places.PlacesService(map);
    service.nearbySearch(request, callback);

    findhim(latlng);

}

function findhim(point) {
    var geocoder = new google.maps.Geocoder();
    geocoder.geocode({latLng: point}, function (results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            if (results[0]) {

                var p_name = (results[0].name) ? "Place name: " + results[0].name + "
" : '';
                var p_address = (results[0].formatted_address) ? "
" + results[0].formatted_address + "
" : '';

                document.getElementById("location_container").innerHTML = p_name + p_address;
            }
        }
    });

}

function callback(results, status) {
    if (status == google.maps.places.PlacesServiceStatus.OK) {
        for (var i = 0; i < results.length; i++) {
            if(checkRadiusDistance(results[i],latlng,825)){
                createMarker(results[i]);
            }
        }

        $('#alert-msg').html("
 <button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×</button>Returned " + results.length + " results
");

        $("#mnu_2,#about,#h_place,#btn-group-places").css("display","block");
        $("#btn-group-places").css("display","inline-block");
    }
    else
    {
        $('#alert-msg').html("
 <button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×</button>Returned " + results.length + " results
");
        $("#mnu_2,#about,#h_place,#btn-group-places").css("display","none");

    }
}

function checkRadiusDistance(place,latlng,radius) {
    return google.maps.geometry.spherical.computeDistanceBetween(place.geometry.location, latlng) <= radius;
}

function createMarker(place) {

    var placeLoc = place.geometry.location;

    var marker = new google.maps.Marker({
        map: map,
        position: place.geometry.location
    });

    var requestdata = {
        placeId: place.place_id
    };

    document.getElementById("placeres").innerHTML="";
    var service = new google.maps.places.PlacesService(map);
    service.getDetails(requestdata, function(placedata, status) {

        if (status == google.maps.places.PlacesServiceStatus.OK)
        {

            if(request.rankBy === google.maps.places.RankBy.PROMINENCE){
                place_details_sortbyprominence.push((placedata));
                localStorage.setItem("leloo_by_prominence",JSON.stringify(place_details_sortbyprominence));
                display_sorted_results(localStorage.getItem("leloo_by_prominence"));

            }else if(request.rankBy === google.maps.places.RankBy.DISTANCE){
                place_details_sorbydistance.push((placedata));
                localStorage.setItem("leloo_by_distance",JSON.stringify(place_details_sorbydistance));
                display_sorted_results(localStorage.getItem("leloo_by_distance"));

            }

        }
    });

    google.maps.event.addListener(marker, 'click', function() {
        infowindow.setContent(getPlace_contenet(place));
        infowindow.open(map, this);
    });

}
function display_sorted_results(localstorage_data){

    var data = localstorage_data.replace(/"\\"/g,"'").replace(/\\""/g,"'");

    data = JSON.parse(data);
    document.getElementById("places").innerHTML="";
    document.getElementById("p_user_review").innerHTML="";
    var str_container = "";
    var u_review = "";
    for(var i = 0 ; i < data.length ; i++){

        var placedata= data[i];

        var place_name = "
"+placedata.name+"
";
        var place_address = "
"+placedata.formatted_address+"
";
        var place_img_representation = "";
        var place_internationa_phonenuber =(typeof placedata.international_phone_number !=='undefined')?"
"+placedata.international_phone_number +"
":"";

        var place_rating =(typeof placedata.rating !=='undefined')? "
Rating based on aggregated user reviews:"+rating_display(placedata.rating)+"
":"";
        var place_website =(typeof placedata.website !== 'undefined')? "
VISIT WEBSITE":"";

        var user_reviews = "";
        if(typeof placedata.reviews !=='undefined'){
            for(var j = 0 ; j < placedata.reviews.length; j ++){

                var place_reviews = placedata.reviews[j];
                var review_author = "
"+place_reviews.author_name+"
";
                var review_authorlink = (typeof place_reviews.author_url !=='undefined')? ""+review_author+"":""+review_author+"";
                var review_rating ="
Rating:"+ rating_display(place_reviews.rating)+"
";
                var review_text = "
"+place_reviews.text+"
";

                 user_reviews +="
"+review_authorlink+review_rating+review_text+"
";
            }
        }

        getUser_Review(placedata.place_id,place_name,place_address,function(data){
            u_review +=data;
            document.getElementById("p_user_review").innerHTML =u_review;
        });

        var final_users_review = "
"+user_reviews+"
";

        str_container += "
 <button class='btn btn-primary btn-sm add_review'  data-place_id= '"+placedata.place_id+"'> Add reviews</button></button>"+place_name+place_address+place_img_representation+place_internationa_phonenuber+place_rating+place_website + final_users_review +"
";
    }
    document.getElementById("placeres").innerHTML=str_container;
}

function getUser_Review(placeid,place_name,place_address,callback){
    var p_id = placeid;
    var u_review = "";

    $.ajax({
        method:"POST",
        url:"public/userAction/getPlaceReview.php",
        data:"placeid="+p_id,
        success:function(data){
                if(data){
                    $("#p_user_review").html("");
                    var db_user_review = JSON.parse(data);
                    for(i = 0 ;i < db_user_review.length; i++ ){
                        var db_author_review =  "
"+db_user_review[i].full_name+"
";
                        var db_rating_review =  "
Rating:"+ rating_display(db_user_review[i].rating)+"
";
                        var db_text_review   =  "
"+db_user_review[i].reviewtext+"
";

                        u_review +="
"+db_author_review+db_rating_review+db_text_review+"
";

                    }
                   var db_review = "
"+place_name+place_address+"
"+u_review+"

";

                    callback(db_review);
                }
        }
    });

}

function getPlace_contenet(place) {
    var content = '';
    content += '
';
    content += '
';
    content += '	';
    var url=(typeof place.url !=='undefined')?place.url:'#';

    content += '' + place.name + '
';
    content += '
Address:	' + place.vicinity + '
';
    if (place.formatted_phone_number) {
        content += '
Telephone:	' + place.formatted_phone_number + '
';
    }

    if (place.rating) {
        rating_display(place.rating);
        content += '
Rating:	' +  rating_display(place.rating); + '
';

    }
    if (place.website) {
        var fullUrl = place.website;
        var website = hostnameRegexp.exec(place.website);
        if (website == null) {
            website = 'http://' + place.website + '/';
            fullUrl = website;
        }
        content += '
Website:	' + website + '
';
    }
    content += '
';
    return content;
}

function showError(error) {
    switch (error.code) {
        case error.PERMISSION_DENIED:
            x.innerHTML = "User denied the request for Geolocation."
            break;
        case error.POSITION_UNAVAILABLE:
            x.innerHTML = "Location information is unavailable."
            break;
        case error.TIMEOUT:
            x.innerHTML = "The request to get user location timed out."
            break;
        case error.UNKNOWN_ERROR:
            x.innerHTML = "An unknown error occurred."
            break;
    }
}

function ucfirst(str) {
    var firstLetter = str.substr(0, 1);
    return firstLetter.toUpperCase() + str.substr(1);
}

function rating_display(rating){
    var html_rating="";
    for (var i = 0; i < 5; i++) {
        if (rating < (i + 0.5)) {
            html_rating += '✩';
        } else {
            html_rating += '✭';
        }
    }

    return html_rating;
}

<|endoftext|>


<commit_before>require('normalize.css');
require('styles/App.css');

import React from 'react';

class HeroList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: props.data
    };
  }
  onSelect(id) {
    this.props.onSelect(id)
  }
  render() {
    var heroList = this.state.data.map(function(hero) {
      return (

{hero.name}

      );
    }.bind(this));
    return (

        {heroList}

    );
  }
}

class HeroForm extends React.Component {
  handleChange(e) {
    var name = this.refs.name.value.trim();
    this.props.onChange(name);
    return;
  }
  render() {
    return (
      <input type="text" ref="name" onChange={this.handleChange} />
    );
  }
}
var HEROES = [
    { "id": 11, "name": "Mr. Nice" },
    { "id": 12, "name": "Narco" },
    { "id": 13, "name": "Bombasto" },
    { "id": 14, "name": "Celeritas" },
    { "id": 15, "name": "Magneta" },
    { "id": 16, "name": "RubberMan" },
    { "id": 17, "name": "Dynama" },
    { "id": 18, "name": "Dr IQ" },
    { "id": 19, "name": "Magma" },
    { "id": 20, "name": "Tornado" }
];

class AppComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {data: HEROES, selectedHero: HEROES[0] };
  }
  onSelectedHeroNameChange(newName) {
    //this.state.selectedHero.name = newName;
  }
  handleHeroSelect = (selectedHeroId) => {
    this.state.selectedHero = this.state.data.find(function(e) { e.id === selectedHeroId; })
  }
  render() {
    var title = 'Tour of Heroes'; // FIXME, this should be a property
    return (

{title}

My Heroes

Selected: {this.state.selectedHero.name}

        <HeroList data={this.state.data} onSelect={this.handleHeroSelect} />
        <HeroForm onChange={this.onSelectedHeroNameChange}/>

    );
  }
}

AppComponent.defaultProps = {
};

export default AppComponent;
<commit_msg>some debugging<commit_after>require('normalize.css');
require('styles/App.css');

import React from 'react';

class HeroList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: props.data
    };
  }
  onSelect(id) {
    this.props.onSelect(id)
  }
  render() {
    var heroList = this.state.data.map(function(hero) {
      return (

{hero.name}

      );
    }.bind(this));
    return (

        {heroList}

    );
  }
}

class HeroForm extends React.Component {
  handleChange(e) {
    var name = this.refs.name.value.trim();
    this.props.onChange(name);
    return;
  }
  render() {
    return (
      <input type="text" ref="name" onChange={this.handleChange} />
    );
  }
}
var HEROES = [
    { "id": 11, "name": "Mr. Nice" },
    { "id": 12, "name": "Narco" },
    { "id": 13, "name": "Bombasto" },
    { "id": 14, "name": "Celeritas" },
    { "id": 15, "name": "Magneta" },
    { "id": 16, "name": "RubberMan" },
    { "id": 17, "name": "Dynama" },
    { "id": 18, "name": "Dr IQ" },
    { "id": 19, "name": "Magma" },
    { "id": 20, "name": "Tornado" }
];

class AppComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {data: HEROES, selectedHero: HEROES[0] };
  }
  onSelectedHeroNameChange(newName) {
    //this.state.selectedHero.name = newName;
  }
  handleHeroSelect = (selectedHeroId) => {
    console.log("selected hero id", selectedHeroId);
    this.state.selectedHero = this.state.data.find(function(e) { e.id === selectedHeroId; })
    console.log("changed selected hero to", this.state.selectedHero);
  }
  render() {
    var title = 'Tour of Heroes'; // FIXME, this should be a property
    return (

{title}

My Heroes

Selected: {this.state.selectedHero.name}

        <HeroList data={this.state.data} onSelect={this.handleHeroSelect} />
        <HeroForm onChange={this.onSelectedHeroNameChange}/>

    );
  }
}

AppComponent.defaultProps = {
};

export default AppComponent;
<|endoftext|>


<commit_before>import $ from 'dom7';
import Utils from '../../utils/utils';
import Framework7Class from '../../utils/class';
import SwipePanel from './swipe-panel';

class Panel extends Framework7Class {
  constructor(app, params = {}) {
    super(params, [app]);
    const panel = this;

    let el = params.el;

    if (!el && params.content) {
      el = params.content;
    }

    const $el = $(el);
    if ($el.length === 0) return panel;
    if ($el[0].f7Panel) return $el[0].f7Panel;

    $el[0].f7Panel = panel;

    let { opened, side, effect } = params;
    if (typeof opened === 'undefined') opened = $el.hasClass('panel-active');
    if (typeof side === 'undefined') side = $el.hasClass('panel-left') ? 'left' : 'right';
    if (typeof effect === 'undefined') effect = $el.hasClass('panel-cover') ? 'cover' : 'reveal';

    if (!app.panel[side]) {
      Utils.extend(app.panel, {
        [side]: panel,
      });
    } else {
      throw new Error(`Framework7: Can't create panel; app already has a ${side} panel!`);
    }

    let $backdropEl = $('.panel-backdrop');

    if ($backdropEl.length === 0) {
      $backdropEl = $('

');
      $backdropEl.insertBefore($el);
    }

    Utils.extend(panel, {
      app,
      side,
      effect,
      $el,
      el: $el[0],
      opened,
      $backdropEl,
      backdropEl: $backdropEl[0],
    });

    // Install Modules
    panel.useModules();

    // Init
    panel.init();

    return panel;
  }

  init() {
    const panel = this;
    const app = panel.app;
    if (app.params.panel[`${panel.side}Breakpoint`]) {
      panel.initBreakpoints();
    }
    if (process.env.TARGET !== 'desktop') {
      if (
        (app.params.panel.swipe === panel.side)
        || (app.params.panel.swipe === 'both')
        || (app.params.panel.swipe && app.params.panel.swipe !== panel.side && app.params.panel.swipeCloseOpposite)
      ) {
        panel.initSwipePanel();
      }
    }
  }

  getViewEl() {
    const panel = this;
    const app = panel.app;
    let viewEl;
    if (app.root.children('.views').length > 0) {
      viewEl = app.root.children('.views')[0];
    } else {
      viewEl = app.root.children('.view')[0];
    }
    return viewEl;
  }

  setBreakpoint() {
    const panel = this;
    const app = panel.app;
    const { side, $el } = panel;
    const $viewEl = $(panel.getViewEl());
    const breakpoint = app.params.panel[`${side}Breakpoint`];
    const wasVisible = $el.hasClass('panel-visible-by-breakpoint');

    if (app.width >= breakpoint) {
      if (!wasVisible) {
        $('html').removeClass(`with-panel-${side}-reveal with-panel-${side}-cover with-panel`);
        $el.css('display', '').addClass('panel-visible-by-breakpoint').removeClass('panel-active');
        panel.onOpen();
        panel.onOpened();
        $viewEl.css({
          [`margin-${side}`]: `${$el.width()}px`,
        });
        app.allowPanelOpen = true;
        app.emit('local::breakpoint panelBreakpoint');
        panel.$el.trigger('panel:breakpoint', panel);
      }
    } else if (wasVisible) {
      $el.css('display', '').removeClass('panel-visible-by-breakpoint panel-active');
      panel.onClose();
      panel.onClosed();
      $viewEl.css({
        [`margin-${side}`]: '',
      });
      app.emit('local::breakpoint panelBreakpoint');
      panel.$el.trigger('panel:breakpoint', panel);
    }
  }

  initBreakpoints() {
    const panel = this;
    const app = panel.app;
    panel.resizeHandler = function resizeHandler() {
      panel.setBreakpoint();
    };
    if (app.params.panel[`${panel.side}Breakpoint`]) {
      app.on('resize', panel.resizeHandler);
    }
    panel.setBreakpoint();
    return panel;
  }

  initSwipePanel() {
    if (process.env.TARGET !== 'desktop') {
      SwipePanel(this);
    }
  }

  destroy() {
    let panel = this;
    const app = panel.app;

    if (!panel.$el) {
      // Panel already destroyed
      return;
    }

    panel.emit('local::beforeDestroy panelBeforeDestroy', panel);
    panel.$el.trigger('panel:beforedestroy', panel);

    if (panel.resizeHandler) {
      app.off('resize', panel.resizeHandler);
    }
    panel.$el.trigger('panel:destroy', panel);
    panel.emit('local::destroy panelDestroy');
    delete app.panel[panel.side];
    if (panel.el) {
      panel.el.f7Panel = null;
      delete panel.el.f7Panel;
    }
    Utils.deleteProps(panel);
    panel = null;
  }

  open(animate = true) {
    const panel = this;
    const app = panel.app;
    if (!app.panel.allowOpen) return false;

    const { side, effect, $el, $backdropEl, opened } = panel;

    const $panelParentEl = $el.parent();
    const wasInDom = $el.parents(document).length > 0;

    if (!$panelParentEl.is(app.root) || $el.prevAll('.views, .view').length) {
      const $insertBeforeEl = app.root.children('.panel, .views, .view').eq(0);
      const $insertAfterEl = app.root.children('.statusbar').eq(0);

      if ($insertBeforeEl.length) {
        $el.insertBefore($insertBeforeEl);
      } else if ($insertAfterEl.length) {
        $el.insertAfter($insertBeforeEl);
      } else {
        app.root.prepend($el);
      }

      if ($backdropEl
        && $backdropEl.length
        && (
          (
            !$backdropEl.parent().is(app.root)
            && $backdropEl.nextAll('.panel').length === 0
          )
          || (
            $backdropEl.parent().is(app.root)
            && $backdropEl.nextAll('.panel').length === 0
          )
        )
      ) {
        $backdropEl.insertBefore($el);
      }

      panel.once('panelClosed', () => {
        if (wasInDom) {
          $panelParentEl.append($el);
        } else {
          $el.remove();
        }
      });
    }

    // Ignore if opened
    if (opened || $el.hasClass('panel-visible-by-breakpoint') || $el.hasClass('panel-active')) return false;

    // Close if some panel is opened
    app.panel.close(side === 'left' ? 'right' : 'left', animate);

    app.panel.allowOpen = false;

    $el[animate ? 'removeClass' : 'addClass']('not-animated');
    $el
      .css({ display: 'block' })
      .addClass('panel-active');

    $backdropEl[animate ? 'removeClass' : 'addClass']('not-animated');
    $backdropEl.show();

    /* eslint no-underscore-dangle: ["error", { "allow": ["_clientLeft"] }] */
    panel._clientLeft = $el[0].clientLeft;

    $('html').addClass(`with-panel with-panel-${side}-${effect}`);
    panel.onOpen();

    // Transition End;
    const transitionEndTarget = effect === 'reveal' ? $el.nextAll('.view, .views').eq(0) : $el;

    function panelTransitionEnd() {
      transitionEndTarget.transitionEnd((e) => {
        if ($(e.target).is(transitionEndTarget)) {
          if ($el.hasClass('panel-active')) {
            panel.onOpened();
            $backdropEl.css({ display: '' });
          } else {
            panel.onClosed();
            $backdropEl.css({ display: '' });
          }
        } else panelTransitionEnd();
      });
    }
    if (animate) {
      panelTransitionEnd();
    } else {
      panel.onOpened();
      $backdropEl.css({ display: '' });
    }

    return true;
  }

  close(animate = true) {
    const panel = this;
    const app = panel.app;

    const { side, effect, $el, $backdropEl, opened } = panel;

    if (!opened || $el.hasClass('panel-visible-by-breakpoint') || !$el.hasClass('panel-active')) return false;

    $el[animate ? 'removeClass' : 'addClass']('not-animated');
    $el.removeClass('panel-active');

    $backdropEl[animate ? 'removeClass' : 'addClass']('not-animated');

    const transitionEndTarget = effect === 'reveal' ? $el.nextAll('.view, .views').eq(0) : $el;

    panel.onClose();
    app.panel.allowOpen = false;

    if (animate) {
      transitionEndTarget.transitionEnd(() => {
        if ($el.hasClass('panel-active')) return;
        $el.css({ display: '' });
        $('html').removeClass('with-panel-transitioning');
        panel.onClosed();
      });
      $('html')
        .removeClass(`with-panel with-panel-${side}-${effect}`)
        .addClass('with-panel-transitioning');
    } else {
      $el.css({ display: '' });
      $el.removeClass('not-animated');
      $('html').removeClass(`with-panel with-panel-transitioning with-panel-${side}-${effect}`);
      panel.onClosed();
    }
    return true;
  }

  onOpen() {
    const panel = this;
    panel.opened = true;
    panel.$el.trigger('panel:open', panel);
    panel.emit('local::open panelOpen', panel);
  }

  onOpened() {
    const panel = this;
    const app = panel.app;
    app.panel.allowOpen = true;

    panel.$el.trigger('panel:opened', panel);
    panel.emit('local::opened panelOpened', panel);
  }

  onClose() {
    const panel = this;
    panel.opened = false;
    panel.$el.addClass('panel-closing');
    panel.$el.trigger('panel:close', panel);
    panel.emit('local::close panelClose', panel);
  }

  onClosed() {
    const panel = this;
    const app = panel.app;
    app.panel.allowOpen = true;
    panel.$el.removeClass('panel-closing');
    panel.$el.trigger('panel:closed', panel);
    panel.emit('local::closed panelClosed', panel);
  }
}

export default Panel;
<commit_msg>Core: Panel: unset panel breakpoint on destroy<commit_after>import $ from 'dom7';
import Utils from '../../utils/utils';
import Framework7Class from '../../utils/class';
import SwipePanel from './swipe-panel';

class Panel extends Framework7Class {
  constructor(app, params = {}) {
    super(params, [app]);
    const panel = this;

    let el = params.el;

    if (!el && params.content) {
      el = params.content;
    }

    const $el = $(el);
    if ($el.length === 0) return panel;
    if ($el[0].f7Panel) return $el[0].f7Panel;

    $el[0].f7Panel = panel;

    let { opened, side, effect } = params;
    if (typeof opened === 'undefined') opened = $el.hasClass('panel-active');
    if (typeof side === 'undefined') side = $el.hasClass('panel-left') ? 'left' : 'right';
    if (typeof effect === 'undefined') effect = $el.hasClass('panel-cover') ? 'cover' : 'reveal';

    if (!app.panel[side]) {
      Utils.extend(app.panel, {
        [side]: panel,
      });
    } else {
      throw new Error(`Framework7: Can't create panel; app already has a ${side} panel!`);
    }

    let $backdropEl = $('.panel-backdrop');

    if ($backdropEl.length === 0) {
      $backdropEl = $('

');
      $backdropEl.insertBefore($el);
    }

    Utils.extend(panel, {
      app,
      side,
      effect,
      $el,
      el: $el[0],
      opened,
      $backdropEl,
      backdropEl: $backdropEl[0],
    });

    // Install Modules
    panel.useModules();

    // Init
    panel.init();

    return panel;
  }

  init() {
    const panel = this;
    const app = panel.app;
    if (app.params.panel[`${panel.side}Breakpoint`]) {
      panel.initBreakpoints();
    }
    if (process.env.TARGET !== 'desktop') {
      if (
        (app.params.panel.swipe === panel.side)
        || (app.params.panel.swipe === 'both')
        || (app.params.panel.swipe && app.params.panel.swipe !== panel.side && app.params.panel.swipeCloseOpposite)
      ) {
        panel.initSwipePanel();
      }
    }
  }

  getViewEl() {
    const panel = this;
    const app = panel.app;
    let viewEl;
    if (app.root.children('.views').length > 0) {
      viewEl = app.root.children('.views')[0];
    } else {
      viewEl = app.root.children('.view')[0];
    }
    return viewEl;
  }

  setBreakpoint() {
    const panel = this;
    const app = panel.app;
    const { side, $el } = panel;
    const $viewEl = $(panel.getViewEl());
    const breakpoint = app.params.panel[`${side}Breakpoint`];
    const wasVisible = $el.hasClass('panel-visible-by-breakpoint');

    if (app.width >= breakpoint) {
      if (!wasVisible) {
        $('html').removeClass(`with-panel-${side}-reveal with-panel-${side}-cover with-panel`);
        $el.css('display', '').addClass('panel-visible-by-breakpoint').removeClass('panel-active');
        panel.onOpen();
        panel.onOpened();
        $viewEl.css({
          [`margin-${side}`]: `${$el.width()}px`,
        });
        app.allowPanelOpen = true;
        app.emit('local::breakpoint panelBreakpoint');
        panel.$el.trigger('panel:breakpoint', panel);
      }
    } else if (wasVisible) {
      $el.css('display', '').removeClass('panel-visible-by-breakpoint panel-active');
      panel.onClose();
      panel.onClosed();
      $viewEl.css({
        [`margin-${side}`]: '',
      });
      app.emit('local::breakpoint panelBreakpoint');
      panel.$el.trigger('panel:breakpoint', panel);
    }
  }

  initBreakpoints() {
    const panel = this;
    const app = panel.app;
    panel.resizeHandler = function resizeHandler() {
      panel.setBreakpoint();
    };
    if (app.params.panel[`${panel.side}Breakpoint`]) {
      app.on('resize', panel.resizeHandler);
    }
    panel.setBreakpoint();
    return panel;
  }

  initSwipePanel() {
    if (process.env.TARGET !== 'desktop') {
      SwipePanel(this);
    }
  }

  destroy() {
    let panel = this;
    const app = panel.app;

    if (!panel.$el) {
      // Panel already destroyed
      return;
    }

    panel.emit('local::beforeDestroy panelBeforeDestroy', panel);
    panel.$el.trigger('panel:beforedestroy', panel);

    if (panel.resizeHandler) {
      app.off('resize', panel.resizeHandler);
    }

    if (panel.$el.hasClass('panel-visible-by-breakpoint')) {
      const $viewEl = $(panel.getViewEl());
      panel.$el.css('display', '').removeClass('panel-visible-by-breakpoint panel-active');
      $viewEl.css({
        [`margin-${panel.side}`]: '',
      });
      app.emit('local::breakpoint panelBreakpoint');
      panel.$el.trigger('panel:breakpoint', panel);
    }

    panel.$el.trigger('panel:destroy', panel);
    panel.emit('local::destroy panelDestroy');
    delete app.panel[panel.side];
    if (panel.el) {
      panel.el.f7Panel = null;
      delete panel.el.f7Panel;
    }
    Utils.deleteProps(panel);
    panel = null;
  }

  open(animate = true) {
    const panel = this;
    const app = panel.app;
    if (!app.panel.allowOpen) return false;

    const { side, effect, $el, $backdropEl, opened } = panel;

    const $panelParentEl = $el.parent();
    const wasInDom = $el.parents(document).length > 0;

    if (!$panelParentEl.is(app.root) || $el.prevAll('.views, .view').length) {
      const $insertBeforeEl = app.root.children('.panel, .views, .view').eq(0);
      const $insertAfterEl = app.root.children('.statusbar').eq(0);

      if ($insertBeforeEl.length) {
        $el.insertBefore($insertBeforeEl);
      } else if ($insertAfterEl.length) {
        $el.insertAfter($insertBeforeEl);
      } else {
        app.root.prepend($el);
      }

      if ($backdropEl
        && $backdropEl.length
        && (
          (
            !$backdropEl.parent().is(app.root)
            && $backdropEl.nextAll('.panel').length === 0
          )
          || (
            $backdropEl.parent().is(app.root)
            && $backdropEl.nextAll('.panel').length === 0
          )
        )
      ) {
        $backdropEl.insertBefore($el);
      }

      panel.once('panelClosed', () => {
        if (wasInDom) {
          $panelParentEl.append($el);
        } else {
          $el.remove();
        }
      });
    }

    // Ignore if opened
    if (opened || $el.hasClass('panel-visible-by-breakpoint') || $el.hasClass('panel-active')) return false;

    // Close if some panel is opened
    app.panel.close(side === 'left' ? 'right' : 'left', animate);

    app.panel.allowOpen = false;

    $el[animate ? 'removeClass' : 'addClass']('not-animated');
    $el
      .css({ display: 'block' })
      .addClass('panel-active');

    $backdropEl[animate ? 'removeClass' : 'addClass']('not-animated');
    $backdropEl.show();

    /* eslint no-underscore-dangle: ["error", { "allow": ["_clientLeft"] }] */
    panel._clientLeft = $el[0].clientLeft;

    $('html').addClass(`with-panel with-panel-${side}-${effect}`);
    panel.onOpen();

    // Transition End;
    const transitionEndTarget = effect === 'reveal' ? $el.nextAll('.view, .views').eq(0) : $el;

    function panelTransitionEnd() {
      transitionEndTarget.transitionEnd((e) => {
        if ($(e.target).is(transitionEndTarget)) {
          if ($el.hasClass('panel-active')) {
            panel.onOpened();
            $backdropEl.css({ display: '' });
          } else {
            panel.onClosed();
            $backdropEl.css({ display: '' });
          }
        } else panelTransitionEnd();
      });
    }
    if (animate) {
      panelTransitionEnd();
    } else {
      panel.onOpened();
      $backdropEl.css({ display: '' });
    }

    return true;
  }

  close(animate = true) {
    const panel = this;
    const app = panel.app;

    const { side, effect, $el, $backdropEl, opened } = panel;

    if (!opened || $el.hasClass('panel-visible-by-breakpoint') || !$el.hasClass('panel-active')) return false;

    $el[animate ? 'removeClass' : 'addClass']('not-animated');
    $el.removeClass('panel-active');

    $backdropEl[animate ? 'removeClass' : 'addClass']('not-animated');

    const transitionEndTarget = effect === 'reveal' ? $el.nextAll('.view, .views').eq(0) : $el;

    panel.onClose();
    app.panel.allowOpen = false;

    if (animate) {
      transitionEndTarget.transitionEnd(() => {
        if ($el.hasClass('panel-active')) return;
        $el.css({ display: '' });
        $('html').removeClass('with-panel-transitioning');
        panel.onClosed();
      });
      $('html')
        .removeClass(`with-panel with-panel-${side}-${effect}`)
        .addClass('with-panel-transitioning');
    } else {
      $el.css({ display: '' });
      $el.removeClass('not-animated');
      $('html').removeClass(`with-panel with-panel-transitioning with-panel-${side}-${effect}`);
      panel.onClosed();
    }
    return true;
  }

  onOpen() {
    const panel = this;
    panel.opened = true;
    panel.$el.trigger('panel:open', panel);
    panel.emit('local::open panelOpen', panel);
  }

  onOpened() {
    const panel = this;
    const app = panel.app;
    app.panel.allowOpen = true;

    panel.$el.trigger('panel:opened', panel);
    panel.emit('local::opened panelOpened', panel);
  }

  onClose() {
    const panel = this;
    panel.opened = false;
    panel.$el.addClass('panel-closing');
    panel.$el.trigger('panel:close', panel);
    panel.emit('local::close panelClose', panel);
  }

  onClosed() {
    const panel = this;
    const app = panel.app;
    app.panel.allowOpen = true;
    panel.$el.removeClass('panel-closing');
    panel.$el.trigger('panel:closed', panel);
    panel.emit('local::closed panelClosed', panel);
  }
}

export default Panel;
<|endoftext|>


<commit_before>import React from 'react'
import { filter, find, first, get, isEmpty, map, pick, some, without, includes } from 'lodash'
const { array, bool, func, object } = React.PropTypes
import cx from 'classnames'
import { humanDate, nonbreaking, present, sanitize, timeRange, timeRangeFull, appendInP } from '../util/text'
import truncate from 'html-truncate'
import A from './A'
import Avatar from './Avatar'
import Dropdown from './Dropdown'
import ClickCatchingDiv from './ClickCatchingDiv'
import Comment from './Comment'
import CommentForm from './CommentForm'
import RSVPControl from './RSVPControl'
import PersonDropdownItem from './PersonDropdownItem'
import { connect } from 'react-redux'
import { compose } from 'redux'
import {
  changeEventResponse,
  followPost,
  removePost,
  startPostEdit,
  voteOnPost
} from '../actions'
import { same } from '../models'
import decode from 'ent/decode'

const spacer =   •

class Post extends React.Component {
  static propTypes = {
    post: object,
    onExpand: func,
    communities: array,
    comments: array,
    commentsLoaded: bool,
    dispatch: func,
    commentingDisabled: bool,
    currentUser: object
  }

  static contextTypes = {
    community: object
  }

  static childContextTypes = {
    currentUser: object,
    dispatch: func,
    post: object
  }

  constructor (props) {
    super(props)
    this.state = {}
  }

  getChildContext () {
    return pick(this.props, 'currentUser', 'dispatch', 'post')
  }

  componentDidMount () {
    // TODO this is a hack because prefetch isn't doing what I want yet
    // let { dispatch, post: {id} } = this.props
    // dispatch(fetchComments(id))
  }

  render () {
    let { post, communities, comments, commentingDisabled } = this.props
    let community
    if (this.context.community) {
      community = this.context.community
    } else {
      community = communities[0]
    }

    let image = find(post.media, m => m.type === 'image')
    var classes = cx('post', post.type, 'expanded', {image: !!image})

    const createdAt = new Date(post.created_at)

    let title = decode(post.name || '')
    let person = post.type === 'welcome'
      ? post.relatedUsers[0]
      : post.user

    let isEvent = post.type === 'event'
    if (isEvent) {
      let start = new Date(post.start_time)
      let end = post.end_time && new Date(post.end_time)
      var eventTime = timeRange(start, end)
      var eventTimeFull = timeRangeFull(start, end)
    }

    return

        <PostMenu/>
        <Avatar person={person}/>
        {post.type === 'welcome'
          ? <WelcomePostHeader communities={communities}/>
          :

              <A className='name' to={`/u/${person.id}`}>{person.name}
              {spacer}

                <A to={`/p/${post.id}`}>{nonbreaking(humanDate(createdAt))}
                 in {community.name}

}

{title}

      {isEvent &&

        {eventTime}

}

      {post.location &&

        {post.location}

}

      <PostDetails
        {...{comments, communities, commentingDisabled}}/>

  }
}

export default compose(
  connect((state, { post }) => {
    let { comments, commentsByPost, people, communities } = state
    let commentIds = get(commentsByPost, post.id)
    return {
      commentsLoaded: !!commentIds,
      comments: map(commentIds, id => comments[id]),
      currentUser: get(people, 'current'),
      communities: map(post.communities, id => find(communities, same('id', {id})))
    }
  })
)(Post)

export const UndecoratedPost = Post // for testing

const WelcomePostHeader = ({ communities }, { post }) => {
  let person = post.relatedUsers[0]
  let community = communities[0]
  return

    <A to={`/u/${person.id}`}>{person.name} joined

    {community
      ?
          <A to={`/c/${community.slug}`}>{community.name}.

            Welcome them!

      :
          a community that is no longer active.
        }

}

WelcomePostHeader.contextTypes = {post: object}

const PostMenu = (props, { dispatch, post, currentUser }) => {
  let canEdit = same('id', currentUser, post.user)
  let following = some(post.followers, same('id', currentUser))

  const edit = () => dispatch(startPostEdit(post))
  const remove = () => window.confirm('Are you sure? This cannot be undone.') &&
    dispatch(removePost(post.id))

  return <Dropdown className='post-menu' alignRight={true}
    toggleChildren={}>
    {canEdit &&
Edit
}
    {canEdit &&
Remove
}

       dispatch(followPost(post.id, currentUser))}>
        Turn {following ? 'off' : 'on'} notifications for this post

       window.alert('TODO')}>Report objectionable content

  </Dropdown>
}

PostMenu.contextTypes = {dispatch: func, post: object, currentUser: object}

const PostDetails = (props, { post, currentUser, dispatch }) => {
  const { comments, commentingDisabled, voters } = props
  const image = find(post.media, m => m.type === 'image')
  const typeLabel = `#${post.type === 'chat' ? 'all-topics' : post.type}`
  const description = present(appendInP(
    sanitize(post.description), ` <a class='hashtag'>${typeLabel}</a>`))
  const attachments = filter(post.media, m => m.type !== 'image')

  return

    {description && <ClickCatchingDiv className='details post-section'
      dangerouslySetInnerHTML={{__html: description}}/>}

    {image &&

}

    {post.type === 'event' && <EventRSVP postId={post.id} responders={post.responders}/>}

      <VoteButton /><Voters voters={voters} />

    {!isEmpty(attachments) &&

      {attachments.map((file, i) =>

          {truncate(file.name, 40)}
        )}

}

    <CommentSection
      {...{post, comments, commentingDisabled}}/>

}

PostDetails.contextTypes = Post.childContextTypes

class CommentSection extends React.Component {
  static propTypes = {
    comments: array,
    commentingDisabled: bool
  }

  static contextTypes = {post: object}

  constructor (props) {
    super(props)
    this.state = {expanded: false}
  }

  toggleExpanded = () => {
    this.setState({expanded: !this.state.expanded})
  }

  render () {
    let { comments, commentingDisabled } = this.props
    let { post } = this.context
    let { expanded } = this.state
    if (!comments) comments = []
    let displayedComments = expanded ? comments : comments.slice(0, 3)
    return

      <a name={`post-${post.id}-comments`}>
        {displayedComments.map(c =>
          <Comment comment={{...c, post_id: post.id}} key={c.id}/>)}
      {comments.length > 3 && !expanded &&

          Show all

}
      {!commentingDisabled && <CommentForm postId={post.id}/>}

  }
}

const EventRSVP = ({ postId, responders }, { currentUser, dispatch }) => {
  let isCurrentUser = r => r.id === get(currentUser, 'id')
  let currentResponse = get(find(responders, isCurrentUser), 'response') || ''
  let onPickResponse = currentUser &&
    (choice => dispatch(changeEventResponse(postId, choice, currentUser)))

  return <RSVPControl {...{responders, currentResponse, onPickResponse}}/>
}

EventRSVP.contextTypes = {currentUser: object, dispatch: func}

export const VoteButton = (props, { post, currentUser, dispatch }) => {
  let vote = () => dispatch(voteOnPost(post, currentUser))
  let myVote = includes(map(post.voters, 'id'), currentUser.id)
  return
    <i className={`icon-heart-new${myVote ? '-selected' : ''}`}>
    {myVote ? 'Liked' : 'Like'}

}

VoteButton.contextTypes = {post: object, currentUser: object, dispatch: func}

export const Voters = (props, { post, currentUser }) => {
  let { voters } = post
  if (!voters) voters = []

  let onlyAuthorIsVoting = voters.length === 1 && same('id', first(voters), post.user)
  let meInVoters = find(voters, same('id', currentUser))
  let otherVoters = meInVoters ? without(voters, meInVoters) : voters

  let numShown = 2
  let num = otherVoters.length
  let hasHidden = num > numShown
  let separator = threshold =>
    num > threshold
      ? ', '
      : num === threshold
        ? `${voters.length === 2 ? '' : ','} and `
        : ''

  if (voters.length > 0 && !onlyAuthorIsVoting) {
    return
      {meInVoters && You}
      {meInVoters && separator(1)}
      {otherVoters.slice(0, numShown).map((person, index) =>

          <a href={`/u/${person.id}`}>{person.name}
          {index !== numShown - 1 && separator(2)}
        )}
      {hasHidden && ', and '}
      {hasHidden && <Dropdown className='inline'
        toggleChildren={
          {num - numShown} other{num - numShown > 1 ? 's' : ''}
        }>
        {otherVoters.slice(numShown).map(p =>
          <PersonDropdownItem key={p.id} person={p}/>)}
      </Dropdown>}
       liked this.

  } else {
    return
  }
}

Voters.contextTypes = {post: object, currentUser: object}
<commit_msg>fix test<commit_after>import React from 'react'
import { filter, find, first, get, isEmpty, map, pick, some, without, includes } from 'lodash'
const { array, bool, func, object } = React.PropTypes
import cx from 'classnames'
import { humanDate, nonbreaking, present, sanitize, timeRange, timeRangeFull, appendInP } from '../util/text'
import truncate from 'html-truncate'
import A from './A'
import Avatar from './Avatar'
import Dropdown from './Dropdown'
import ClickCatchingDiv from './ClickCatchingDiv'
import Comment from './Comment'
import CommentForm from './CommentForm'
import RSVPControl from './RSVPControl'
import PersonDropdownItem from './PersonDropdownItem'
import { connect } from 'react-redux'
import { compose } from 'redux'
import {
  changeEventResponse,
  followPost,
  removePost,
  startPostEdit,
  voteOnPost
} from '../actions'
import { same } from '../models'
import decode from 'ent/decode'

const spacer =   •

class Post extends React.Component {
  static propTypes = {
    post: object,
    onExpand: func,
    communities: array,
    comments: array,
    commentsLoaded: bool,
    dispatch: func,
    commentingDisabled: bool,
    currentUser: object
  }

  static contextTypes = {
    community: object
  }

  static childContextTypes = {
    currentUser: object,
    dispatch: func,
    post: object
  }

  constructor (props) {
    super(props)
    this.state = {}
  }

  getChildContext () {
    return pick(this.props, 'currentUser', 'dispatch', 'post')
  }

  componentDidMount () {
    // TODO this is a hack because prefetch isn't doing what I want yet
    // let { dispatch, post: {id} } = this.props
    // dispatch(fetchComments(id))
  }

  render () {
    let { post, communities, comments, commentingDisabled } = this.props
    let community
    if (this.context.community) {
      community = this.context.community
    } else {
      community = communities[0]
    }

    let image = find(post.media, m => m.type === 'image')
    var classes = cx('post', post.type, 'expanded', {image: !!image})

    const createdAt = new Date(post.created_at)

    let title = decode(post.name || '')
    let person = post.type === 'welcome'
      ? post.relatedUsers[0]
      : post.user

    let isEvent = post.type === 'event'
    if (isEvent) {
      let start = new Date(post.start_time)
      let end = post.end_time && new Date(post.end_time)
      var eventTime = timeRange(start, end)
      var eventTimeFull = timeRangeFull(start, end)
    }

    return

        <PostMenu/>
        <Avatar person={person}/>
        {post.type === 'welcome'
          ? <WelcomePostHeader communities={communities}/>
          :

              <A className='name' to={`/u/${person.id}`}>{person.name}
              {spacer}

                <A to={`/p/${post.id}`}>{nonbreaking(humanDate(createdAt))}
                 in {community.name}

}

{title}

      {isEvent &&

        {eventTime}

}

      {post.location &&

        {post.location}

}

      <PostDetails
        {...{comments, communities, commentingDisabled}}/>

  }
}

export default compose(
  connect((state, { post }) => {
    let { comments, commentsByPost, people, communities } = state
    let commentIds = get(commentsByPost, post.id)
    return {
      commentsLoaded: !!commentIds,
      comments: map(commentIds, id => comments[id]),
      currentUser: get(people, 'current'),
      communities: map(post.communities, id => find(communities, same('id', {id})))
    }
  })
)(Post)

export const UndecoratedPost = Post // for testing

const WelcomePostHeader = ({ communities }, { post }) => {
  let person = post.relatedUsers[0]
  let community = communities[0]
  return

    <A to={`/u/${person.id}`}>{person.name} joined

    {community
      ?
          <A to={`/c/${community.slug}`}>{community.name}.

            Welcome them!

      :
          a community that is no longer active.
        }

}

WelcomePostHeader.contextTypes = {post: object}

const PostMenu = (props, { dispatch, post, currentUser }) => {
  let canEdit = same('id', currentUser, post.user)
  let following = some(post.followers, same('id', currentUser))

  const edit = () => dispatch(startPostEdit(post))
  const remove = () => window.confirm('Are you sure? This cannot be undone.') &&
    dispatch(removePost(post.id))

  return <Dropdown className='post-menu' alignRight={true}
    toggleChildren={}>
    {canEdit &&
Edit
}
    {canEdit &&
Remove
}

       dispatch(followPost(post.id, currentUser))}>
        Turn {following ? 'off' : 'on'} notifications for this post

       window.alert('TODO')}>Report objectionable content

  </Dropdown>
}

PostMenu.contextTypes = {dispatch: func, post: object, currentUser: object}

const PostDetails = (props, { post, currentUser, dispatch }) => {
  const { comments, commentingDisabled, voters } = props
  const image = find(post.media, m => m.type === 'image')
  const typeLabel = `#${post.type === 'chat' ? 'all-topics' : post.type}`
  const description = present(appendInP(
    sanitize(post.description), ` <a class='hashtag'>${typeLabel}</a>`))
  const attachments = filter(post.media, m => m.type !== 'image')

  return

    {description && <ClickCatchingDiv className='details post-section'
      dangerouslySetInnerHTML={{__html: description}}/>}

    {image &&

}

    {post.type === 'event' && <EventRSVP postId={post.id} responders={post.responders}/>}

      <VoteButton /><Voters voters={voters} />

    {!isEmpty(attachments) &&

      {attachments.map((file, i) =>

          {truncate(file.name, 40)}
        )}

}

    <CommentSection
      {...{post, comments, commentingDisabled}}/>

}

PostDetails.contextTypes = Post.childContextTypes

class CommentSection extends React.Component {
  static propTypes = {
    comments: array,
    commentingDisabled: bool
  }

  static contextTypes = {post: object}

  constructor (props) {
    super(props)
    this.state = {expanded: false}
  }

  toggleExpanded = () => {
    this.setState({expanded: !this.state.expanded})
  }

  render () {
    let { comments, commentingDisabled } = this.props
    let { post } = this.context
    let { expanded } = this.state
    if (!comments) comments = []
    let displayedComments = expanded ? comments : comments.slice(0, 3)
    return

      <a name={`post-${post.id}-comments`}>
        {displayedComments.map(c =>
          <Comment comment={{...c, post_id: post.id}} key={c.id}/>)}
      {comments.length > 3 && !expanded &&

          Show all

}
      {!commentingDisabled && <CommentForm postId={post.id}/>}

  }
}

const EventRSVP = ({ postId, responders }, { currentUser, dispatch }) => {
  let isCurrentUser = r => r.id === get(currentUser, 'id')
  let currentResponse = get(find(responders, isCurrentUser), 'response') || ''
  let onPickResponse = currentUser &&
    (choice => dispatch(changeEventResponse(postId, choice, currentUser)))

  return <RSVPControl {...{responders, currentResponse, onPickResponse}}/>
}

EventRSVP.contextTypes = {currentUser: object, dispatch: func}

export const VoteButton = ({ post, currentUser, dispatch }) => {
  let vote = () => dispatch(voteOnPost(post, currentUser))
  let myVote = includes(map((post || {}).voters, 'id'), (currentUser || {}).id)
  return
    <i className={`icon-heart-new${myVote ? '-selected' : ''}`}>
    {myVote ? 'Liked' : 'Like'}

}

VoteButton.contextTypes = {post: object, currentUser: object, dispatch: func}

export const Voters = (props, { post, currentUser }) => {
  let { voters } = post
  if (!voters) voters = []

  let onlyAuthorIsVoting = voters.length === 1 && same('id', first(voters), post.user)
  let meInVoters = find(voters, same('id', currentUser))
  let otherVoters = meInVoters ? without(voters, meInVoters) : voters

  let numShown = 2
  let num = otherVoters.length
  let hasHidden = num > numShown
  let separator = threshold =>
    num > threshold
      ? ', '
      : num === threshold
        ? `${voters.length === 2 ? '' : ','} and `
        : ''

  if (voters.length > 0 && !onlyAuthorIsVoting) {
    return
      {meInVoters && You}
      {meInVoters && separator(1)}
      {otherVoters.slice(0, numShown).map((person, index) =>

          <a href={`/u/${person.id}`}>{person.name}
          {index !== numShown - 1 && separator(2)}
        )}
      {hasHidden && ', and '}
      {hasHidden && <Dropdown className='inline'
        toggleChildren={
          {num - numShown} other{num - numShown > 1 ? 's' : ''}
        }>
        {otherVoters.slice(numShown).map(p =>
          <PersonDropdownItem key={p.id} person={p}/>)}
      </Dropdown>}
       liked this.

  } else {
    return
  }
}

Voters.contextTypes = {post: object, currentUser: object}
<|endoftext|>


<commit_before>import dialogPolyfill from "dialog-polyfill";
import * as Registry from "../../core/registry";
import axios from 'axios';

export default class DAMPFabricationDialog {
    constructor() {
        this.__sendFabricationSubmissionButton = document.getElementById("send_designs_button");
        this.__dialog = document.getElementById("damp_fabricate_dialog");
        this.__showFabDialogButton = document.querySelector("#damp_fabricate");

        let ref = this;
        if (!this.__dialog.showModal) {
            dialogPolyfill.registerDialog(this.__dialog);
        }
        this.__showFabDialogButton.addEventListener("click", function() {
            ref.__dialog.showModal();
        });

        this.__sendFabricationSubmissionButton.onclick = function() {
            // Registry.viewManager.activateTool("InsertTextTool");
            let email = document.getElementById("fabricate_dialog_email_field").value;
            let address = document.getElementById("fabricate_dialog_address_field").value;
            console.log(Registry.currentDevice.toInterchangeV1())
            let endpoint = 'http://localhost:8081/api/v1/submit';
            axios.post(endpoint, {
            "email": email,
            "acceptance": "n/a",
            "completion": "not completed",
            "time": 10,
            "cost": 1000,
            "file": JSON.stringify(Registry.currentDevice.toInterchangeV1()),
            "address": address
            })
            .then((res) => {
                console.log(res);
                alert("Add the submission code here")
            })
            .catch((err) => {
                console.error(err);
                alert("Error submiting the design for fabrication:" + err.message)
            })

        };

        this.__dialog.querySelector(".close").addEventListener("click", function() {
            ref.__dialog.close();
        });
    }
}
<commit_msg>add download and open-in-3duf button<commit_after>import dialogPolyfill from "dialog-polyfill";
import * as Registry from "../../core/registry";
import axios from 'axios';

export default class DAMPFabricationDialog {
    constructor() {
        this.__sendFabricationSubmissionButton = document.getElementById("send_designs_button");
        this.__dialog = document.getElementById("damp_fabricate_dialog");
        this.__showFabDialogButton = document.querySelector("#damp_fabricate");

        let ref = this;
        if (!this.__dialog.showModal) {
            dialogPolyfill.registerDialog(this.__dialog);
        }
        this.__showFabDialogButton.addEventListener("click", function() {
            ref.__dialog.showModal();
        });

        this.__sendFabricationSubmissionButton.onclick = function() {
            // Registry.viewManager.activateTool("InsertTextTool");
            let email = document.getElementById("fabricate_dialog_email_field").value;
            let address = document.getElementById("fabricate_dialog_address_field").value;
            console.log(Registry.currentDevice.toInterchangeV1())
            let endpoint = 'http://localhost:8081/api/v1/submit';
            axios.post(endpoint, {
            "email": email,
            "design": JSON.stringify(Registry.currentDevice.toInterchangeV1()),
            "address": address
            })
            .then((res) => {
                console.log(res);
                alert("Add the submission code here")
            })
            .catch((err) => {
                console.error(err);
                alert("Error submiting the design for fabrication:" + err.message)
            })

        };

        this.__dialog.querySelector(".close").addEventListener("click", function() {
            ref.__dialog.close();
        });
    }
}
<|endoftext|>


<commit_before>// this is the main entry point for the app
// it renders the App component after wrapping it in the Provider from Redux

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { Router, Route, IndexRoute, browserHistory, Link } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';

import App from './components/App';
import MainRecipe from './components/MainRecipe';
import Profile from './components/Profile';
import Dashboard from './components/Dashboard';
import SearchResults from './components/SearchResults';
import ImageUpload from './components/ImageUpload.js';
import CreateRecipe from './components/CreateRecipe';

import rootReducer from './reducers';

// Grab the state from a global injected into server-generated HTML
const initialState = window.__INITIAL_STATE__;

// Create Redux store with initial state
// the store manages the state of our app
// createStore accepts a single reducer or a collection of reducers
const store = createStore(rootReducer, initialState);

const history = syncHistoryWithStore(browserHistory, store);

const render = function () {
  ReactDOM.render(
    <Provider store={store}>

        <Router history={history}>
          <Route path="/" component={App}>
            <IndexRoute component={Dashboard} />
            <Route path="/profile" component={Profile} />
            <Route path="/recipe" component={MainRecipe} />
            <Route path="/recipe/:id" component={MainRecipe} />
            <Route path="/dashboard" component={Dashboard} />
            <Route path="/create" component={CreateRecipe} />
            <Route path="/search" component={SearchResults} />
            <Route path="/*" component={Dashboard} />
          </Route>
        </Router>

    </Provider>,
    document.getElementById('app')
  );
};

render();
store.subscribe(render);
<commit_msg>Remove /recipe route<commit_after>// this is the main entry point for the app
// it renders the App component after wrapping it in the Provider from Redux

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { Router, Route, IndexRoute, browserHistory, Link } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';

import App from './components/App';
import MainRecipe from './components/MainRecipe';
import Profile from './components/Profile';
import Dashboard from './components/Dashboard';
import SearchResults from './components/SearchResults';
import ImageUpload from './components/ImageUpload.js';
import CreateRecipe from './components/CreateRecipe';

import rootReducer from './reducers';

// Grab the state from a global injected into server-generated HTML
const initialState = window.__INITIAL_STATE__;

// Create Redux store with initial state
// the store manages the state of our app
// createStore accepts a single reducer or a collection of reducers
const store = createStore(rootReducer, initialState);

const history = syncHistoryWithStore(browserHistory, store);

const render = function () {
  ReactDOM.render(
    <Provider store={store}>

        <Router history={history}>
          <Route path="/" component={App}>
            <IndexRoute component={Dashboard} />
            <Route path="/profile" component={Profile} />
            <Route path="/recipe/:id" component={MainRecipe} />
            <Route path="/dashboard" component={Dashboard} />
            <Route path="/create" component={CreateRecipe} />
            <Route path="/search" component={SearchResults} />
            <Route path="/*" component={Dashboard} />
          </Route>
        </Router>

    </Provider>,
    document.getElementById('app')
  );
};

render();
store.subscribe(render);
<|endoftext|>


<commit_before>(function () {
    'use strict';
    angular.module('gantt')
        .directive('ganttBackgroundStyle', ['ganttDebounce', function (debounce) {
            return {
                restrict: 'A',
                link: function (scope, element, attrs) {
                    var setNewBackgroundStyle = debounce(function (newStyles) {
                        console.count('setNewBackgroundStyle');
                        element.css('backgroundColor',newStyles);
                    }, 150);

                    scope.$watch(attrs.ganttBackgroundStyle, function ngStyleWatchAction(newStyles, oldStyles) {
                        // if (oldStyles && (newStyles !== oldStyles)) {
                        //     resetOldStyle(oldStyles);
                        // }
                        if (newStyles != null) {
                            setNewBackgroundStyle(newStyles);
                        }
                    });
                }
            };
        }])
        .directive('ganttStyle', ['ganttDebounce', function (debounce) {
            return {
                restrict: 'A',
                link: function (scope, element, attrs) {
                    // var resetOldStyle = debounce(function (oldStyles) {
                    //     console.count('resetOldStyle');
                    //     angular.forEach(oldStyles, function (val, style) {
                    //         element.css(style, '');
                    //     });
                    // }, 200);

                    var setNewStyle = debounce(function (newStyles) {
                        // console.count(element.attr('class'))
                        // console.count('    ' + _.keys(newStyles));
                        // console.count('    ' + _.values(newStyles));
                        element.css(newStyles);
                    }, 150);

                    scope.$watch(attrs.ganttStyle, function ngStyleWatchAction(newStyles, oldStyles) {
                        // if (oldStyles && (newStyles !== oldStyles)) {
                        //     resetOldStyle(oldStyles);
                        // }
                        if (newStyles && Object.keys(newStyles).length !== 0) {
                            setNewStyle(newStyles);
                        }
                    }, true);
                }
            };
        }]);
}());
<commit_msg>improve performance, pickup ng-style -> debounce style.<commit_after>(function () {
    'use strict';
    angular.module('gantt')
        .directive('ganttBackgroundStyle', ['ganttDebounce', function (debounce) {
            return {
                restrict: 'A',
                link: function (scope, element, attrs) {
                    var setNewBackgroundStyle = debounce(function (newStyles) {
                        // console.count('setNewBackgroundStyle');
                        element.css('backgroundColor',newStyles);
                    }, 150);

                    scope.$watch(attrs.ganttBackgroundStyle, function ngStyleWatchAction(newStyles, oldStyles) {
                        // if (oldStyles && (newStyles !== oldStyles)) {
                        //     resetOldStyle(oldStyles);
                        // }
                        if (newStyles != null) {
                            setNewBackgroundStyle(newStyles);
                        }
                    });
                }
            };
        }])
        .directive('ganttStyle', ['ganttDebounce', function (debounce) {
            return {
                restrict: 'A',
                link: function (scope, element, attrs) {
                    // var resetOldStyle = debounce(function (oldStyles) {
                    //     console.count('resetOldStyle');
                    //     angular.forEach(oldStyles, function (val, style) {
                    //         element.css(style, '');
                    //     });
                    // }, 200);

                    var setNewStyle = debounce(function (newStyles) {
                        // console.count(element.attr('class'))
                        // console.count('    ' + _.keys(newStyles));
                        // console.count('    ' + _.values(newStyles));
                        element.css(newStyles);
                    }, 150);

                    scope.$watch(attrs.ganttStyle, function ngStyleWatchAction(newStyles, oldStyles) {
                        // if (oldStyles && (newStyles !== oldStyles)) {
                        //     resetOldStyle(oldStyles);
                        // }
                        if (newStyles && Object.keys(newStyles).length !== 0) {
                            setNewStyle(newStyles);
                        }
                    }, true);
                }
            };
        }]);
}());
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react'

const Book = ({ volumeInfo, parentComponent, clickedAddToWishlist, clickedRemoveFromWishlist, id }) => {
  return(

      { volumeInfo.title }
      { volumeInfo.imageLinks ?  : null }
      { parentComponent === 'home' ? <button className="btn btn-info btn-block" onClick={ () => clickedAddToWishlist(id)}>Add To WishList</button> : null}
      { parentComponent === 'wishlist' ? <button className="btn btn-info btn-block" onClick={ () => clickedRemoveFromWishlist(id)}>Remove From WishList</button> : null}

  )
}

export default Book<commit_msg>refactored which buttons appear based on parent container property<commit_after>import React, { PropTypes } from 'react'

const Book = ({ volumeInfo, parentComponent, clickedAddToWishlist, clickedRemoveFromWishlist, id, clickedAddToCurrentlyReading, clickedRemoveFromCurrentlyReading }) => {
  return(

      { volumeInfo.title }
      { volumeInfo.imageLinks ?  : null }
      { parentComponent === 'wishlist' ? <button className="btn btn-info btn-block" onClick={ () => clickedRemoveFromWishlist(id)}>Remove From WishList</button> : null}
      { parentComponent === 'wishlist' ? <button className="btn btn-info btn-block" onClick={ () => clickedAddToCurrentlyReading(id)}>Add To Currently Reading</button> : null}
      { parentComponent === 'home' ? <button className="btn btn-info btn-block" onClick={ () => clickedAddToCurrentlyReading(id)}>Add To Currently Reading</button> : null}
      { parentComponent === 'home'  ? <button className="btn btn-info btn-block" onClick={ () => clickedAddToWishlist(id)}>Add To WishList</button> : null}
      { parentComponent === 'currently_reading' ? <button className="btn btn-info btn-block" onClick={ () => clickedAddToWishlist(id)}>Add To WishList</button> : null}
      { parentComponent === 'currently_reading' ? <button className="btn btn-info btn-block" onClick={ () => clickedRemoveFromCurrentlyReading(id)}>Remove From Currently Reading</button> : null}

  )
}

export default Book<|endoftext|>


<commit_before>// Dependencies

import builder from 'focus-core/component/builder';

// Stores

import applicationStore from 'focus-core/application/built-in-store';

// Mixins

const stylableBehaviour = require('../../mixin/stylable');

// Components

import Button from '../../components/button';
const Dropdown = require('../../common/select-action').component;

const ContentActions = {
    mixins: [stylableBehaviour],
    /** @inheriteddoc */
    getInitialState() {
        return this._getStateFromStore();
    },
    /** @inheriteddoc */
    componentWillMount() {
        applicationStore.addActionsChangeListener(this._handleComponentChange);
    },
    /** @inheriteddoc */
    componentWillUnmount() {
        applicationStore.removeActionsChangeListener(this._handleComponentChange);
    },
    /**
     * Get state from store
     * @return {Object} actions extracted from the store
     */
    _getStateFromStore() {
        return {
            actions: applicationStore.getActions() || {primary: [], secondary: []}};
    },
    /**
     * Component change handler
     */
    _handleComponentChange() {
        this.setState(this._getStateFromStore());
    },
    /** @inheriteddoc */
    render() {
        const {actions} = this.state;
        return (

                {actions.primary.map((primary) => {
                    return (
                        <Button handleOnClick={primary.action} icon={primary.icon} label={primary.label} shape='fab' style={{className: primary.className}} type='button'/>
                    );
                })}
                <Dropdown iconProps={{name: 'more_vert'}} operationList={actions.secondary} shape='fab'/>

        );
    }
};

module.exports = builder(ContentActions);
<commit_msg>Add dropdown in primary actions<commit_after>// Dependencies

import builder from 'focus-core/component/builder';

// Stores

import applicationStore from 'focus-core/application/built-in-store';

// Mixins

const stylableBehaviour = require('../../mixin/stylable');

// Components

import Button from '../../components/button';
const Dropdown = require('../../common/select-action').component;

const ContentActions = {
    mixins: [stylableBehaviour],
    /** @inheriteddoc */
    getInitialState() {
        return this._getStateFromStore();
    },
    /** @inheriteddoc */
    componentWillMount() {
        applicationStore.addActionsChangeListener(this._handleComponentChange);
    },
    /** @inheriteddoc */
    componentWillUnmount() {
        applicationStore.removeActionsChangeListener(this._handleComponentChange);
    },
    /**
     * Get state from store
     * @return {Object} actions extracted from the store
     */
    _getStateFromStore() {
        return {
            actions: applicationStore.getActions() || {primary: [], secondary: []}};
    },
    /**
     * Component change handler
     */
    _handleComponentChange() {
        this.setState(this._getStateFromStore());
    },
    /** @inheriteddoc */
    render() {
        const {actions} = this.state;
        return (

                {actions.primary.map((primary) => {
                    if(Array.isArray(primary.action)) {
                        return <Dropdown iconProps={{name: primary.icon}} operationList={primary.action} shape='fab'/>;
                    } else {
                        return (
                            <Button handleOnClick={primary.action} icon={primary.icon} label={primary.label} shape='fab' style={{className: primary.className}} type='button'/>
                        );
                    }
                })}
                <Dropdown iconProps={{name: 'more_vert'}} operationList={actions.secondary} shape='fab'/>

        );
    }
};

module.exports = builder(ContentActions);
<|endoftext|>