Source: PageState.js

/**
                * @author Rafael Ostertag <rafael.ostertag@math.uzh.ch>
                */

                /* @depend QfqEvents.js */
                /* global EventEmitter */

                /**
                * Qfq Namespace
                *
                * @namespace QfqNS
                */
                var QfqNS = QfqNS || {};

                (function (n) {
                'use strict';


                /**
                *
                * @constructor
                * @name QfqNS.PageState
                */
                n.PageState = function () {
                this.pageState = location.hash.slice(1);
                this.data = null;
                this.inPoppingHandler = false;
                this.eventEmitter = new EventEmitter();

                window.addEventListener("popstate", this.popStateHandler.bind(this));
                };

                n.PageState.prototype.on = n.EventEmitter.onMixin;
                /**
                *
                * @param event
                *
                * @private
                */
                n.PageState.prototype.popStateHandler = function (event) {

                n.Log.debug("Enter: PageState.popStateHandler()");

                this.inPoppingHandler = true;
                this.pageState = location.hash.slice(1);
                this.data = window.history.state;

                n.Log.debug("PageState.popStateHandler(): invoke user pop state handler(s)");

                this.eventEmitter.emitEvent('pagestate.state.popped', n.EventEmitter.makePayload(this, null));

                this.inPoppingHandler = false;
                n.Log.debug("Exit: PageState.popStateHandler()");

                };

                n.PageState.prototype.getPageState = function () {
                return this.pageState;
                };

                n.PageState.prototype.getPageData = function () {
                return this.data;
                };

                n.PageState.prototype.setPageState = function (state, data) {
                if (state.startsWith('#')) {
                this.pageState = state.slice(1);
                window.history.replaceState(data, null, state);
                } else {
                this.pageState = state;
                window.history.replaceState(data, null, '#' + state);
                }
                this.data = data;
                };

                n.PageState.prototype.newPageState = function (state, data) {
                if (state.startsWith('#')) {
                this.pageState = state.slice(1);
                window.history.pushState(data, null, state);
                } else {
                this.pageState = state;
                window.history.pushState(data, null, '#' + state);
                }

                this.data = data;
                };

                })(QfqNS);