SpontaneousCMS/spontaneous

View on GitHub
application/js/location.js

Summary

Maintainability
D
2 days
Test Coverage
// console.log("Loading Location...")

Spontaneous.Location = (function($, S) {
    var ajax = S.Ajax;

    var State = new JS.Class({
        initialize: function(path) {
            this.page_id = false;
            this.mode = null;
            if (path) {
                path = path.substr(ajax.namespace.length+1);
                this.parse_path(path);
            }
        },
        parse_path: function(path) {
            var areas = path.split('/'), id = areas[0], mode = areas[1];
            this.page_id = id;
            this.mode = mode;
        },
        restore: function() {
            if (this.mode) {
                Spontaneous.Location.view_mode_changed(this.mode);
                Spontaneous.TopBar.set_mode(this.mode);
            }
            if (this.page_id) {
                Spontaneous.Location.load_id(this.page_id);
            } else {
                Spontaneous.Location.load_path('/');
            }
        },
        to_hash: function() {
            return '#/'+(this.page_id || '') + (this.mode ? ('@' + this.mode) : '');
        },
        to_path: function() {
            return [ajax.namespace, (this.page_id || ''), this.mode].join('/');
        },
        to_obj: function() {
            return {
                page_id: this.page_id,
                mode: this.mode
            };
        }
    });

    State.extend({
        // currently just produces some kind of loop
        popstate: function(event) {
            State.restore(event);
            return false;
        },
        restore: function(event) {
            var state = new State(window.location.pathname);
            state.restore();
        },

        page: function(location, mode) {
            var s = new State();
            s.page_id = location.id;
            s.mode = mode;
            window.history.replaceState(s.to_obj(), ''+s.page_id, s.to_path());
        }
    });

    var Location = new JS.Singleton({
        include: Spontaneous.Properties,
        init: function(callback) {
            this.locationCache = {};
            callback();
            State.restore();
            // $(window).bind('hashchange', State.restore);
        },
        page_loaded: function(page) {
            // page.watch('slot', this, 'slot_changed');
        },
        slot_changed: function(slot) {
            // console.log('Location.slot_changed', slot, slot.uid(), slot.container.id());
        },
        view_mode_changed: function(mode) {
            this.set('view_mode', mode);
            if (this.get('location')) {
                this.update_state(this.get('location'), mode);
            }
        },
        load_map: function() {
        },
        location_loaded: function(location, status, xhr) {
            S.Popover.close();
            if (xhr.status === 406) { // Code returned if site is missing a root page
                var d = new Spontaneous.AddHomeDialogue(Spontaneous.Types.get('types'));
                d.open();
            } else {
                this.set('location', location);
                // HACK: see preview.js (Preview.display)
                this.set('path', location.path);
                this.update_state(location, this.get('view_mode'));
            }
            this.set('loading_location', null);
        },
        update_state: function(location, mode) {
            State.page(location, mode);
        },
        load_id: function(id) {
            var l = this.location();
            if (!l || id != l.id) {
                this.find_id(id);
            }
        },
        load_path: function(path) {
            this.find_path(path);
        },
        path_changed: function(path) {
            this.set('path', path);
        },
        url: function() {
            var l = this.location();
            return (l ? l.url : '/about');
        },
        location: function() {
            return this.get('location');
        },
        update: function(location) {
            this.set('location', location);
            this.path_from_url(location.url);
        },
        current_path: function() {
            return this.path_from_url(this.url());
        },
        find_path: function(path) {
            if (this.location() && path === this.location().path) {
                return this.location();
            }
            this.retrieve_with_progress('/map/path'+path, this.location_loaded.bind(this));
        },
        find_id: function(id) {
            if (this.location() && id === this.location().id) {
                return this.location();
            }
            this.retrieve_with_progress('/map/'+id, this.location_loaded.bind(this));
        },
        path_from_url: function(url) {
            var map = this.get('map'),
            children = map.children,
            path = [], i, ii,
            parts = url.split('/').slice(1), position = 0;
            // add root to path
            path.push({selected:0, pages:[map], root:true});
            while (position < parts.length) {
                for (i = 0, ii = children.length; i < ii; i++) {
                    var child = children[i], slug = child.url.split('/').slice(-1)[0];
                    if (slug === parts[position]) {
                        path.push({selected:i, pages: children});
                        children = child.children;
                        break;
                    }
                }
                position += 1;
            }
            return path;
        },
        retrieve_with_progress: function(url, callback) {
            this.set('loading_location', url);
            return this.retrieve(url, callback);
        },
        retrieve: function(url, callback) {
            ajax.get(url, {}, callback, {ifModified: true, cache: true});
        },
        lastModified: function(path) {
            return (this.locationCache[path] || {}).lastModified;
        },
        setLocationCache: function(path, lastModified, location) {
            this.locationCache[path] = { lastModified: lastModified, location: location };
        },
        getLocationCache: function(path) {
            return this.locationCache[path].location;
        }
    });
    // $(window).bind('popstate', State.popstate);
    return Location;
})(jQuery, Spontaneous);