<commit_before>import { h, render, Component }			from 'preact/preact';
import NavBar 							from 'com/nav-bar/bar';

import ViewTimeline						from 'com/view-timeline/timeline';
import ViewSingle						from 'com/view-single/single';

import CoreData							from '../core-data/data';


window.LUDUMDARE_ROOT = '/';

class Main extends Component {
	constructor() {
		this.state = {
			root: 1,
			active: 1,
		};
		
		this.setActive(window.location);

		// Bind Events to handle future changes //
		var that = this;
		window.addEventListener('hashchange', that.onHashChange.bind(that));
		window.addEventListener('navchange', that.onNavChange.bind(that));
		window.addEventListener('popstate', that.onPopState.bind(that));
	}

	makeSlug( str ) {
		str = str.toLowerCase();
		str = str.replace(/%[a-f0-9]{2}/g,'-');
		str = str.replace(/[^a-z0-9]/g,'-');
		str = str.replace(/-+/g,'-');
		str = str.replace(/^-|-$/g,'');
		return str;
	}

	makeClean( str ) {
		str = str.toLowerCase();
		str = str.replace(/%[a-f0-9]{2}/g,'-');		// % codes = -
		str = str.replace(/[^a-z0-9\/#]/g,'-');		// non a-z, 0-9, #, or / with -
		str = str.replace(/-+/g,'-');				// multiple -'s to a single -
		str = str.replace(/\/+/g,'/');				// multiple /'s to a single /
//		str = str.replace(/^-|-$/g,'');				// Prefix and suffix -'s with nothing
		return str;
	}
	
	trimSlashes( str ) {
		return str.replace(/^\/|\/$/g,'');
	}
		
	setActive( whom ) {
		// Clean the URL //
		var clean = {
			pathname: this.makeClean(whom.pathname),
			search: whom.search,
			hash: this.makeClean(whom.hash),
		}
		var clean_path = clean.pathname+clean.search+clean.hash;
		console.log( clean_path );
		
		// For some reason, we need to replace the state to keep the ?search string
		
		// If current URL is unclean, replace it //
	//	if ( whom.pathname !== clean.pathname || whom.hash !== clean.hash ) {
			window.history.replaceState(window.history.state, null, clean_path);
	//	}
		
		// Parse the clean URL //
		var slugs = this.trimSlashes(clean.pathname).split('/');
		
		// Figure out what our active page_id actually is //
		this.state.active = CoreData.getItemIdByParentAndSlugs( this.state.root, slugs );
	}

	
	componentDidMount() {
		// Startup //
	}
	
	onHashChange() {
		let state = this.state;
		
		this.setState(state);
	}
	onNavChange( e ) {
		//console.log( e.detail.href, e.detail.old.href );
		if ( e.detail.href !== e.detail.old.href ) {
			this.setActive(e.detail);
			this.setState(this.state);
		}
	}
	
	onPopState( e ) {
		console.log(e);
	}
	
	getView( props, state ) {
		if ( state.active ) {
			var item = CoreData.getItemById( state.active );
	
			if ( item.type === 'root' ) {
				return <ViewTimeline item={state.active} />;
			}
			else if ( item.type === 'post' || item.type === 'game' || item.type === 'user' ) {
				return <ViewSingle item={state.active} />;
			}
			else {
				return <div>unsupported</div>;
			}
		}
		else {
			return <div>404</div>;
		}
	}
	
	render( props, state ) {
		//let hasHash = window.location.hash ? <div>{window.location.hash}</div> : <div />;
		//console.log("paint:",state);
		
		return (
			<div id="layout">
				<NavBar />
				{ this.getView(props,state) }
			</div>
		);
	}
};

render(<Main />, document.body);
<commit_msg>okay, navigation is working correctly now. I was calling replaceState too soon<commit_after>import { h, render, Component }			from 'preact/preact';
import NavBar 							from 'com/nav-bar/bar';

import ViewTimeline						from 'com/view-timeline/timeline';
import ViewSingle						from 'com/view-single/single';

import CoreData							from '../core-data/data';


window.LUDUMDARE_ROOT = '/';

class Main extends Component {
	constructor() {
//		this.state = {
//			root: 1,
//			node: 1,
//		};

		this.state = Object.assign(window.history.state, {
			root: 1,
			node: 1,
		});
		
		this.setActive(window.location);

		// Bind Events to handle future changes //
		var that = this;
		window.addEventListener('hashchange', that.onHashChange.bind(that));
		window.addEventListener('navchange', that.onNavChange.bind(that));
		window.addEventListener('popstate', that.onPopState.bind(that));
	}

	makeSlug( str ) {
		str = str.toLowerCase();
		str = str.replace(/%[a-f0-9]{2}/g,'-');
		str = str.replace(/[^a-z0-9]/g,'-');
		str = str.replace(/-+/g,'-');
		str = str.replace(/^-|-$/g,'');
		return str;
	}

	makeClean( str ) {
		str = str.toLowerCase();
		str = str.replace(/%[a-f0-9]{2}/g,'-');		// % codes = -
		str = str.replace(/[^a-z0-9\/#]/g,'-');		// non a-z, 0-9, #, or / with -
		str = str.replace(/-+/g,'-');				// multiple -'s to a single -
		str = str.replace(/\/+/g,'/');				// multiple /'s to a single /
//		str = str.replace(/^-|-$/g,'');				// Prefix and suffix -'s with nothing
		return str;
	}
	
	trimSlashes( str ) {
		return str.replace(/^\/|\/$/g,'');
	}
		
	setActive( whom ) {
		// Clean the URL //
		var clean = {
			pathname: this.makeClean(whom.pathname),
			search: whom.search,
			hash: this.makeClean(whom.hash),
		}
		var clean_path = clean.pathname+clean.search+clean.hash;
		console.log( clean_path );

		// Parse the clean URL //
		var slugs = this.trimSlashes(clean.pathname).split('/');
		
		// Figure out what our active page_id actually is //
		this.state.node = parseInt(CoreData.getItemIdByParentAndSlugs(this.state.root, slugs));
		
		// For some reason, we need to replace the state to keep the ?search string
		
		// If current URL is unclean, replace it //
	//	if ( whom.pathname !== clean.pathname || whom.hash !== clean.hash ) {
			window.history.replaceState(this.state, null, clean_path);
	//	}
	}

	
	componentDidMount() {
		// Startup //
	}
	
	onHashChange() {
		let state = this.state;
		
		this.setState(state);
	}
	onNavChange( e ) {
		//console.log( e.detail.href, e.detail.old.href );
		if ( e.detail.href !== e.detail.old.href ) {
			this.setActive(e.detail);
			this.setState(this.state);	// Force Refresh
		}
	}
	
	onPopState( e ) {
		console.log(e);
		console.log(window.location);
		this.setState(e.state);
	}
	
	getView( props, state ) {
		if ( state.node ) {
			var item = CoreData.getItemById( state.node );
	
			if ( item.type === 'root' ) {
				return <ViewTimeline item={state.node} />;
			}
			else if ( item.type === 'post' || item.type === 'game' || item.type === 'user' ) {
				return <ViewSingle item={state.node} />;
			}
			else {
				return <div>unsupported</div>;
			}
		}
		else {
			return <div>404</div>;
		}
	}
	
	render( props, state ) {
		//let hasHash = window.location.hash ? <div>{window.location.hash}</div> : <div />;
		//console.log("paint:",state);
		
		return (
			<div id="layout">
				<NavBar />
				{ this.getView(props,state) }
			</div>
		);
	}
};

render(<Main />, document.body);

{'fraction_non_alphanumeric': 0.19375, 'fraction_numerical': 0.005357142857142857, 'mean_word_length': 2.735964424680378, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1669713', 'n_tokens_mistral': 2790, 'n_tokens_neox': 2452, 'n_words': 500}