Как сохранить и восстановить весь сайт, используя Javascript? - PullRequest
7 голосов
/ 22 апреля 2011

Здравствуйте, я разрабатываю свой собственный маршрутизатор API в Javascript. Он выполняет маршрутизацию на основе #FregmentIdentifiers (document.location.hash).

API завершен, но я все еще работаю над событием backbuttom. Всякий раз, когда нажата кнопка, и хэш изменился, и его видели раньше, старый контент будет восстановлен.

Знаете ли вы, как сохранить и восстановить весь контент?

Моя проблема здесь в том, что если я сохраню и восстановлю document.body.innerHTML, будет восстановлена ​​только разметка, но не события, например, например. гуглмапс перестает работать. Я пытался клонировать document.body или document.documentElement, но javascript либо сказал мне, что в поле нет установщика, либо что мой клон недопустим.

EDIT:

Чтобы после всего понять, над чем я работаю, я решил опубликовать свой текущий код. Вопрос направлен на части, отмеченные комментарием // TODO.

function Router(){
var that = this;
var router = this;
var executionObservers = [];
that.routes = [];
this.registerRoute = function(route){
    that.routes.push(route);
};
var history = null;
this.init = function(){
    var i;
    var identifier = document.location.hash;
    history = new History();
    history.start();
    if(identifier.length > 0){
        identifier = identifier.substring(1,identifier.length);
        for(i = 0; i< that.routes.length; i++){
            var route = that.routes[i];
            if(route.contains(identifier)){
                route.getAction(identifier)(route.getParams(identifier));
                return true;
            }
        }
    }
    return false;
};
this.executed = function (identifier){
    var i; 
    for(i=0; i<executionObservers.length; i++){
        executionObservers[i](identifier);
    }
    document.location.hash = identifier;
};

this.addExecutionObserver = function(observer){
    executionObservers.push(observer);
};

function History(){
    var history = [];
    var timeout = 200;
    var lastAddedHash = null;
    var loop = function(callback){
        var hash = window.location.hash;
        window.setTimeout(
            function(){
                if(window.location.hash!=hash){
                    hash = window.location.hash;
                    callback(hash);
                }
                loop(callback);
            },
            timeout
        );
    };
    this.add = function(hash){
        lastAddedHash  = hash;
        window.setTimeout(addCallback(hash), timeout);          
    };
    addCallback = function(hash){
        return function(){
            var i;
            var found = false;
            for(i =0; i< history.length&&!found; i++){
                if(history[i][1] == hash){
                    found = true;
                    //TODO create backup
                    //history[i][0] = 
                }
            }
            if(!found){history.push(new Array(document.documentElement.cloneNode(true),hash));}
        }
    }
    this.setTimeout = function(micoseconds){
        timeout = microseconds;
    };
    started = false;
    this.start = function(){
        if(!started){
            started = true;
            loop(function(hash){
                var i;
                if(lastAddedHash!=null&&hash!=lastAddedHash){
                    for(i =0; i<history.length; i++){
                        if(history[i][1] == hash){
                            //TODO restore from backup
                            document.location.reload();
                        }
                    }
                }
            });
        }
    };
    router.addExecutionObserver(this.add);
}
}

Router.instance = null;
Router.getInstance = function(){
    if(Router.instance === null ){
        Router.instance = new Router();
    }
    return Router.instance;
};

/**
 * @param getParams = function(identifier)
 * @param getIdentifier = function(params)
 * @param contains = function(identifier)
 */
function Route(action, getParams, getIdentifier, contains){
    var that = this;
    var router = Router.getInstance();
    this.contains = contains;
    this.getParams = getParams;
    this.getAction = function(){
        return action;
    }
    this.reExecute = function(identifier){
        action(getParams(identifier));
    };
    this.execute = function(params){
        action(params);
        this.executed(params);
    }
    this.executed = function(params){
        router.executed('#' + getIdentifier(params));
    };
    this.register = function(){
        router.registerRoute(this);
    };
}
function PrefixedRouterConfig(prefix,paramRegexes){
    this.contains = function(identifier){
        var regex = "^" + prefix;
        for(var i=0;i<paramRegexes.length;i++){
            regex+="_"+paramRegexes[i];
        }
        regex +="$";
        var match = identifier.match(regex);
        return match != null && (typeof match) == 'object' && (match[0] == identifier);
    };
    this.getIdentifier = function(params){
        ret = prefix;
        for(var i=0;i<params.length;i++){
            ret+="_"+params[i];
        }
        return ret;
    };
    this.getParams = function(identifier){
        var regex = "^" + prefix;
        for(var i=0;i<paramRegexes.length;i++){
            regex+="_("+paramRegexes[i]+")";
        }
        regex +="$";
        var matches = identifier.match(regex);
        var ret = [];
        for(var i=1;i<matches.length;i++){
            ret.push(matches[i]);
        }
        return ret;
    };
}

Пример использования моего API может выглядеть следующим образом:

config = new PrefixedRouterConfig('show_map',new Array("\\d+", "-?\\d+(?:\\.\\d+)?", "-?\\d+(?:\\.\\d+)?"));
var ROUTE_SHOW_MAP = new Route(
    function(params){
        var zoom = params[0];
        var lat = params[1];
        var lng = params[2];
        MyGmapInterface.preparePage(-1);
        addTabSelectedCallback(MyGmapInterface.tabLoaded);
        addTabClosedCallback(MyGmapInterface.tabClosed);
        MyGmapInterface.tabsLoaded = true;
        MyGmapInterface.myMap = new MyMap(lat,lng,zoom,MyGmapInterface.getMapContainer(),MyGmapInterface.notCompatible);
        MyGmapInterface.addNewCamMarkers(MyGmapInterface.loadCams());
        MyGmapInterface.initListeners();
        tabSelected(TAB_LEFT);
    },
    config.getParams,
    config.getIdentifier,
    config.contains
);
ROUTE_SHOW_MAP.register();

После того, как все файлы Javascript включены (которые могут регистрировать маршруты), я вызываю Router.getInstance (). Init ();

Когда я делаю где-нибудь ajax-запрос (вручную), для которого существует маршрут, я вызываю ROUTE_NAME.executed (), чтобы установить идентификатор фрагмента и зарегистрировать его в истории.

Кроме того, у меня есть наблюдатель, который обновляет некоторые ссылки, которые используются для прямых переводов, всякий раз, когда хеш местоположения изменяется с помощью execute ()

Ответы [ 6 ]

8 голосов
/ 22 апреля 2011

Это та же самая ситуация, что и обновление, поэтому вы должны повторно использовать эту систему.

По сути, ваш хэш должен содержать достаточно информации, чтобы перестроить всю страницу.Конечно, иногда вам нужно сохранить некоторые пользовательские данные, чтобы перестроить страницу.Вот для чего предназначен localStorage (userData for IE)

2 голосов
/ 28 апреля 2011

Как насчет того, чтобы иметь все в IFRAME и отражать все изменения фрагмента URL в родительском элементе, а затем воздействовать на iframe. Возможно, здесь может возникнуть проблема межсайтового скриптинга.

Очень сложно, чем вы занимаетесь, потому что браузер кэширует - он решает, загружать ли его из памяти, а не вы. Поэтому, если вышеприведенный вариант не подходит, вы можете создать его только через расширение браузера, которое прослушивает событие кнопки «Назад» и действует соответственно.

2 голосов
/ 22 апреля 2011

Если вы не добавили свои события через API, который отслеживает их (как это делает jQuery; см. http://api.jquery.com/clone#true), вы не сможете отразить события, которые были добавлены, чтобы получить их сериализованная / сохраняется.

Если вы сделали маловероятный выбор использования пользовательских данных DOM, вам также потребуется setUserData () для сериализации любых пользовательских данных DOM (или, опять же, библиотеки, подобной jQuery, чтобы отслеживать их для вас).

1 голос
/ 26 апреля 2011

То, что вы хотите, практически невозможно, вы могли бы сделать это, если бы вы использовали библиотеку, такую ​​как jquery, для создания событий вашей страницы, как предложено brettz9, но в вашем случае вы используете карты Google и другие внешние библиотеки, так что это не вариант , Для этого вам необходимо узнать, на какой странице вы находитесь, и выполнить javascript, который инициализирует эту страницу, как если бы она была загружена в первый раз. Для этого вам нужно отслеживать не только html страницы, но и javascript, которые выполняются при загрузке страницы.

1 голос
/ 22 апреля 2011

Вы смотрели на jQuery плагин истории ? Я знаю, что в другом посте вы упомянули, что jQuery не был вариантом, но вы могли бы подражать их подходу.

Я не эксперт по этому вопросу, но из-за различных реализаций браузера, я считаю, это не тривиально , чтобы заставить работать кросс-браузер.

Основной сайт: http://tkyk.github.com/jquery-history-plugin/#

Демонстрационная страница: http://www.serpere.info/jquery-history-plugin/samples/ajax/

0 голосов
/ 27 апреля 2011

Единственный способ, которым я знаю, - обмануть браузер и заставить поверить, что каждое стоящее событие - это новая страница.Вы можете сделать это, загрузив новую страницу, используя window.location, или отправить форму, используя get (= строка запроса).Новое местоположение или данные формы должны содержать все необходимое для отображения нужной информации.У этого есть свои недостатки - вот мой взгляд:

Хорошо:

  • работают кнопки «назад» и «вперед»
  • представления ваших данных могут быть добавлены в закладки
  • при тщательном использовании данных строки запроса он предлагает API для вашей системы

Плохо:

  • каждое стоящее событие должно проходить через страницу загрузки
  • не может использовать ajax
  • вы должны придумать способ кодировать каждое состояние вашей системы в виде строки запроса.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...