Drupal 7 и history.js или как ajax инфицировать сайт
1. Drupal 7 и History.js
или
как AJAX-ифицировать сайт.
Малай Вадим
Drupal developer
vadim.malai@wearepropeople.com
2. Зачем ?
• Иметь статичную зону контента.
• Иметь возможность навигации Back
или Forward в истории browser-a
• Избежать несоответствий при
использовании родного
window.History
4. History.js (Введение)
• Придерживается HTML5 History API
насколько это возможно;
• Кросбраузерность для всех HTML5
браузеров;
• Поддержка HTML4 браузеров;
• Адаптация link-ов в зависимости от
HTML5 или HTML4;
• Поддержка javaScript framerork-ов как "
jQuery", "MooTools", "Prototype", "Zepto".
7. History.js (Как это работает ?)
(function(window,undefined){
var History = window.History;
// Bind to StateChange Event
History.Adapter.bind(window,'statechange',function(){ // Note: We are using statechange instead of popstate
var State = History.getState(); // Note: We are using History.getState() instead of event.state
History.log(State.data, State.title, State.url);
});
// Change our States
History.pushState({state:1}, "State 1", "?state=1"); // logs {state:1}, "State 1", "?state=1"
History.pushState({state:2}, "State 2", "?state=2"); // logs {state:2}, "State 2", "?state=2"
History.replaceState({state:3}, "State 3", "?state=3"); // logs {state:3}, "State 3", "?state=3"
History.pushState(null, null, "?state=4"); // logs {}, '', "?state=4"
History.back(); // logs {state:3}, "State 3", "?state=3"
History.back(); // logs {state:1}, "State 1", "?state=1"
History.back(); // logs {}, "Home Page", "?"
History.go(2); // logs {state:3}, "State 3", "?state=3"
})(window);
8.
9. History.js (Разбор полётов)
History.Adapter.bind(window,'statechange',function(){}); - Привязка к событию
(Срабатывает, когда состояние страницы изменилось).
History.getState() - Получает текущее состояние браузера, возвращает
объект с data, title и url.
History.pushState({state:1}, "State 1", "?state=1") - Вталкивает новое
"состояния" в браузер; data может быть нулевыми или объектом, title
может быть нулевым или строкой, URL должен быть строкой.
10. History.js (Разбор полётов)
History.replaceState({state:3}, "State 3", "?state=3") - Заменяет существующее
"состояние" новым; (В случае замены, будет утеряно "состояние"
предшествующее нынешнему)
History.back() - Назад в историю на 1 шаг;
History.go(2) - Вперед в историю на 2 шага;
History.log(...) - Вывод сообщения в консоли;
11. History.js (Что еще?)
События :
1. 'statechange' - Срабатывает, когда состояние страницы изменилось;
2. 'onanchrorchange' - Срабатывает, когда "якорь" страницы изменился;
History.replaceState(data,title,url) - Заменяет текущее состояние страницы
новым.
History.getHash() - Возвращает значение URL после # (hash); (HTML 4)
History.Adapter.trigger(element,event) - Триггер события;
History.Adapter.onDomLoad(callback) - onDomLoad связующее;
History.forward() - шаг впреред в историю браузера;
History.debug(...) - тоже что и History.log(...), но работает только если
History.debug.enable === true
16. History.js и Drupal
(Привязка к URL) Разбор полётов
Что, и зачем мы сделали ?
1. Указываем в админке части URL, при нахождении которых, мы
игнорируем URL. (Избегаем внешних ссылок, картинок и т.д);
2. Заменяем каждую escape-последовательность в закодированном URI
символом, который она представляет;
3. Вталкивает новое "состояния" в браузер;
4. Привязываемся к событию смены состояния страницы, и вызываемся
функцию, которая будет получать новый контент;
5. Сохраняем новые значения; (При возврате на URI, на котором мы уже
были, можно вытащить уже сохранённые значения, что бы не делать
лишний AJAX запрос)
17. History.js и Drupal
Получаем новый контент
Для получения контента, делаем обычный AJAX запрос, НО ! :
1. Drupal, генерирует BODY классы в зависимости от страницы, так что не
забываем их заменять на "новой" странице;
2. Разные страницы могут иметь разные CSS файлы, их тоже нужно
добавить;
3. Разные страницы могут иметь разные JS файлы, и их :) ;
4. Меняем title страницы;
5. Не забываем про Trobber, потому как AJAX запрос может быть разной
продолжительности;
18. History.js и Drupal
Получаем новый контент (немного кода)
1. Drupal.ajaxify_pages.cache[url] = {
2. title: new_page.title,
3. content: new_page.content,
4. scripts: new_page.new_script,
5. css: new_page.new_css,
6. body_class: new_page.body_class,
7. admin_menu: new_page.admin_menu
8. };
9. processPage(Drupal.ajaxify_pages.cache[url], url);
Не забываем сохранить страницу в "кэш", что бы мы в следующий раз,
при возвращении Back в браузере, ну или новым кликом на ссылку
этой страницы, не делали новый AJAX запрос, а использовали
существующие данные.
20. History.js и Drupal
Заменяем контент
Нет нужды заменять все JS файлы, потому что при этом, будут
перезапущены все скрипты. При этом, не стоит пугаться что JS или CSS
файл не появился в вашем DOM-e.
Мы только добавляем новые файлы.
В определённый момент, у нас соберутся в кучу все JS и CSS файлы
сайты, но на мой взгляд, это не смертельно.
Так же, не стоит забывать, что Drupal делает агрегацию файлов, то есть
добавляет символы в конец имени файла. Это надо учесть при получении
и сравнении новых файлов.
23. History.js и Drupal
Views, как быть? (Разбор полётов)
Так как мы получаем контент по AJAX, все JS обьекты, мы строим рукчами :(
pager_element - Элемент страничной навигации;
view_args - Аргумент передаваеммый во Views;
view_base_path - Родной адресс Views;
view_display_id - ID "отображения" Views;
view_dom_id - Рандомный хэш, который присваивается как класс контейнеру
Views;
view_name - Машинное имя Views;
view_path - URL на котором вызывается Views. При совпадении с
view_base_path, можно указывать только view_path, а view_base_path оставить
как NULL.
• Drupal.settings.views = {
• ajaxViews: {},
• ajax_path: "/views/ajax"
• };
Views обьект в которов будет список
всех Views на странице.
Каждая Views идентифицируется с
помощью ключа
"'views_dom_id:'+view_display_id"
24. History.js и Drupal
Views, как быть? (Разбор полётов)
Приведенный пример, должен использоывться не только по отношению ко
Views, но также и в случае AJAX форм, Ctools modals, Omega layouts ... в
общем ко всему что могло бы быть динамично добавлено при генерации
страницы.