drupal 7 and history.js

26
Drupal 7 и History.js или как AJAX-ифицировать сайт. Малай Вадим Drupal developer [email protected] m

Upload: -

Post on 16-Jun-2015

232 views

Category:

Technology


0 download

DESCRIPTION

Drupal 7 and History.js Presentation, for Drupal Camp Kiev 2013

TRANSCRIPT

Page 1: Drupal 7 and History.js

Drupal 7 и History.jsили

как AJAX-ифицировать сайт.

Малай ВадимDrupal developer

[email protected]

Page 2: Drupal 7 and History.js

Зачем ?

• Иметь статичную зону контента.

• Иметь возможность навигации Back или Forward в истории browser-a

• Избежать несоответствий при использовании родного window.History

Page 3: Drupal 7 and History.js

Составляющие

1. Ajaxify Pages

2. History.js

3. Libraries

Page 4: Drupal 7 and History.js

History.js (Введение)

• Придерживается HTML5 History API насколько это возможно;

• Кросбраузерность для всех HTML5 браузеров;

• Поддержка HTML4 браузеров;• Адаптация link-ов в зависимости от

HTML5 или HTML4;• Поддержка javaScript framerork-ов как

"jQuery", "MooTools", "Prototype", "Zepto".

Page 5: Drupal 7 and History.js

History.js (Где это работает ?)

HTML5 Browsers

HTML4 Browsers

HTML5 BrowsersFirefox 4+ Safari 5.0+

Chrome 8+ Safari iOS 4.3+

Opera 11.5

IE 6, 7, 8, 9 Safari 4

Firefox 3 Safari iOS 4.2, 4.1, 4.0, 3.2

Opera 10, 11.0

Page 6: Drupal 7 and History.js
Page 7: Drupal 7 and History.js

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);

Page 8: Drupal 7 and History.js
Page 9: Drupal 7 and History.js

History.js (Разбор полётов)

History.Adapter.bind(window,'statechange',function(){}); - Привязка к событию

(Срабатывает, когда состояние страницы изменилось).

History.getState() - Получает текущее состояние браузера, возвращает

объект с data, title и url.

History.pushState({state:1}, "State 1", "?state=1") - Вталкивает новое "состояния"

в браузер; data может быть нулевыми или объектом, title может быть

нулевым или строкой, URL должен быть строкой.

Page 10: Drupal 7 and History.js

History.js (Разбор полётов)

History.replaceState({state:3}, "State 3", "?state=3") - Заменяет существующее "состояние" новым; (В случае замены, будет утеряно "состояние" предшествующее нынешнему)

History.back() - Назад в историю на 1 шаг;

History.go(2) - Вперед в историю на 2 шага;

History.log(...) - Вывод сообщения в консоли;

Page 11: Drupal 7 and History.js

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

Page 12: Drupal 7 and History.js

History.js в Drupal-e

Page 13: Drupal 7 and History.js

History.js и Drupal (Привязка к URL)

1. Drupal.behaviors.ajaxify_pages = {};2. Drupal.behaviors.ajaxify_pages.attach = function(context, settings) {3. $(Drupal.settings.ajaxify_pages.links_selector, context).each(function() {4. var to_avoid = Drupal.settings.ajaxify_pages.links_to_avoid;5. var links = $(this).attr("href");6. var links_obj = $(this);7. if (typeof links !== 'undefined') {8. $.each(to_avoid, function(index, value) {9. if (links.indexOf(value) < 0 && links !== '/') {10. var href = links_obj.addClass('ajaxify-pages-processed');11. href = decodeURIComponent(href);12. if (href.indexOf("<script>") > 0) {13. return false;14. }15. if (typeof href !== 'undefined') {16. $(this).click(function() {17. History.pushState(null, null, href);18. return false;19. }); }} }); } });

Page 14: Drupal 7 and History.js

History.js и Drupal (Привязка к URL)

1. if (typeof Drupal.settings.ajaxify_pages.processed !== 'undefined') {2. return false;3. }4. Drupal.settings.ajaxify_pages.processed = 'processed';5. Drupal.ajaxify_pages = {cache: {}};6. History.Adapter.bind(window, 'statechange', function() {7. loadPage(History.getState().url);8. });9. Drupal.ajaxify_pages.cache[History.getState().url] = {10. title: $('title').html(),11. content: $(Drupal.settings.ajaxify_pages.content_selector)12. };13. };

Page 15: Drupal 7 and History.js
Page 16: Drupal 7 and History.js

History.js и Drupal (Привязка к URL) Разбор полётов

Что, и зачем мы сделали ?

1. Указываем в админке части URL, при нахождении которых, мы игнорируем URL. (Избегаем внешних ссылок, картинок и т.д);

2. Заменяем каждую escape-последовательность в закодированном URI символом, который она представляет;

3. Вталкивает новое "состояния" в браузер;

4. Привязываемся к событию смены состояния страницы, и вызываемся функцию, которая будет получать новый контент;

5. Сохраняем новые значения; (При возврате на URI, на котором мы уже были, можно вытащить уже сохранённые значения, что бы не делать лишний AJAX запрос)

Page 17: Drupal 7 and History.js

History.js и Drupal Получаем новый контент

Для получения контента, делаем обычный AJAX запрос, НО ! :

1. Drupal, генерирует BODY классы в зависимости от страницы, так что не забываем их заменять на "новой" странице;

2. Разные страницы могут иметь разные CSS файлы, их тоже нужно добавить;

3. Разные страницы могут иметь разные JS файлы, и их :) ;

4. Меняем title страницы;

5. Не забываем про Trobber, потому как AJAX запрос может быть разной продолжительности;

Page 18: Drupal 7 and History.js

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_menu8. };9. processPage(Drupal.ajaxify_pages.cache[url], url);

Не забываем сохранить страницу в "кэш", что бы мы в следующий раз,

при возвращении Back в браузере, ну или новым кликом на ссылку

этой страницы, не делали новый AJAX запрос, а использовали

существующие данные.

Page 19: Drupal 7 and History.js

History.js и Drupal Заменяем контент

1. $('head script').each(function() {2. if ($(this)[0].src.length > 0) {3. to_replace.page_script.push($(this)[0].src.match(/([^<]+)(.js)/)[0]);4. }5. if ($(this).text().length > 0) {6. $(this).remove();7. }8. });9. 10. if (typeof to_replace.new_script !== 'undefined') {11. $.grep(to_replace.new_script, function(el) {12. if ($.inArray(el, to_replace.page_script) === -1)13. to_replace.diff_script.push(el);14. i++;15. });16. }

Page 20: Drupal 7 and History.js

History.js и Drupal Заменяем контент

•Нет нужды заменять все JS файлы, потому что при этом, будут

перезапущены все скрипты.

•Не стоит пугаться что JS или CSS файл не появился в вашем DOM-e.

•Мы только добавляем новые файлы.

•В определённый момент, у нас соберутся в кучу все JS и CSS файлы

сайты, но на мой взгляд, это не смертельно.

•Так же, не стоит забывать, что Drupal делает агрегацию файлов, то есть

добавляет символы в конец имени файла. Это надо учесть при получении

и сравнении новых файлов.

Page 21: Drupal 7 and History.js

History.js и Drupal Views, как быть ?

1. Drupal.settings.views = {2. ajaxViews: {},3. ajax_path: "/views/ajax"4. };5. $("[class^=view]").ready(function() {6. $(".view").each(function() {7. if ($("[class*=view-]").length > 0 && $("[class*=view-dom-id]").length > 0

&& $("[class*=view-display-id]").length > 0) {8. var view_classes_array = $("[class*=view-]").attr('class').split(' '),9. view_name = view_classes_array[1].replace(/view-/g, ""),10. view_display_id =

view_classes_array[3].replace(/view-display-id-/g, ""),11. view_dom_id = view_classes_array[4].replace(/view-dom-id-/g, ""),12. view_path = '';13. view_path = location.pathname.substring(1,

location.pathname.length);14. view_name = view_name.replace("-", "_");

Page 22: Drupal 7 and History.js

History.js и Drupal Views, как быть ?

1. Drupal.settings.views.ajaxViews['views_dom_id:'+view_display_id] = {2. pager_element: "0",3. view_args: "",4. view_base_path: null,5. view_display_id: view_display_id,6. view_dom_id: view_dom_id,7. view_name: view_name,8. view_path: view_path9. };10. }11. });12. });

Page 23: Drupal 7 and History.js

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"

Page 24: Drupal 7 and History.js

History.js и Drupal Views, как быть? (Разбор полётов)

Приведенный пример, должен использоваться не только по отношению ко Views, но также и в случае AJAX форм, Ctools modals, Omega layouts ... в общем ко всему что могло бы быть динамично добавлено при генерации страницы.

Page 25: Drupal 7 and History.js

Спасибо за Внимание !

Page 26: Drupal 7 and History.js