New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Вынесен polyfill для HTML5 History API #171
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# ns.History | ||
|
||
В noscript для смены URL в адресной строке используется HTML5 History API, который не поддерживается [в IE раньше 10](http://caniuse.com/#feat=history). | ||
|
||
## Polyfill для IE | ||
|
||
В качестве полифилла можно использовать [devote/HTML5-History-API](https://github.com/devote/HTML5-History-API). Скрипт предоставляет стандартизированное API и будет использовать смену хеш-фрагмента URL для навигации. | ||
|
||
/notes/141 -> /#/notes/141 | ||
|
||
Кроме подключения самого скрипта на страницу нужно проделать небольшую работу: | ||
|
||
1. Организовать редирект до старта приложения: | ||
|
||
```js | ||
if (window.history.emulate) { | ||
// Тут может произойти смена URL и перезагрузка, поэтому какие-нибудь | ||
// ручки до редиректа запрашивать бессмысленно. | ||
window.history.redirect(); | ||
} | ||
|
||
ns.init(); | ||
``` | ||
|
||
2. Переопределить вычисление текущего URL приложения: | ||
|
||
```js | ||
var history = window.history; | ||
|
||
if (history.emulate) { | ||
ns.page.getCurrentUrl = function() { | ||
return history.location.pathname + history.location.search; | ||
}; | ||
} | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -198,8 +198,8 @@ ns.action._process = function(e) { | |
return true; | ||
} | ||
|
||
// если host ссылки не равен нашему хосту | ||
if (target.host != window.location.host) { | ||
// если hostname ссылки не равен нашему хосту | ||
if (target.hostname != window.location.hostname) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Тут поправил ошибку в IE9, там |
||
return true; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,104 +1,44 @@ | ||
(function() { | ||
|
||
/** | ||
* Объект для работы с историей и адресной строкой браузера. | ||
* | ||
* Методы: | ||
* | ||
* `ns.history.pushState(url)` | ||
* Меняет URL в адресной строке, запоминая его в истории браузера. | ||
* `ns.history.replaceState(url)` | ||
* Меняет URL в адресной строке, заменяя текущую запись в истории браузера. | ||
* `ns.history.adapt()` | ||
* Адаптирует хешовые URL для браузеров, поддерживающих HTML5 History API, | ||
* выполняя трансформации типа `/#/message/123/` в `/message/123/`. | ||
* `ns.history.legacy` | ||
* {Boolean} | ||
* Флаг использования HTML5 History API или отката на `hashchange`. | ||
* @namespace | ||
*/ | ||
ns.history = (function(window, ns) { | ||
|
||
var history = window.history; | ||
var loc = window.location; | ||
|
||
var legacy = !(history.pushState && history.replaceState); | ||
|
||
// API для браузеров с поддержкой HTML5 History API. | ||
if (!legacy) { | ||
return { | ||
pushState: function(url, title) { | ||
history.pushState(null, title || ns.page.title(url), url); | ||
}, | ||
replaceState: function(url, title) { | ||
history.replaceState(null, title || ns.page.title(url), url); | ||
}, | ||
|
||
// Редирект с хешового урла на его полноценный аналог. | ||
adapt: function() { | ||
var hash = loc.hash.substr(1); | ||
|
||
if (hash.length) { | ||
|
||
var hashRoute = ns.router(hash); | ||
if (hashRoute.page !== ns.R.NOT_FOUND && hashRoute.page !== ns.R.REDIRECT) { | ||
|
||
// TODO: При добавлении способа задания корневого урла заменить | ||
// слеш на нужное свойство/метод. | ||
if (loc.pathname === '/' || ns.router(loc.pathname).page === ns.R.NOT_FOUND) { | ||
// Если в хеше уже есть какие-то query параметры, | ||
// текущие надо к ним прибавить. | ||
var search = hash.indexOf('?') !== -1 ? loc.search.replace(/^\?/, '&') : loc.search; | ||
this.replaceState(hash + search); | ||
} | ||
} | ||
} | ||
ns.history = {}; | ||
|
||
window.addEventListener('popstate', function(e) { | ||
// прибиваем событие, чтобы не дергалась адресная строка | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
ns.history.init = function() { | ||
$(window).on('popstate', function(e) { | ||
// прибиваем событие, чтобы не дергалась адресная строка | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
|
||
ns.page.go('', true); | ||
}, false); | ||
ns.history.onpopstate(e); | ||
}); | ||
}; | ||
|
||
// Здесь `ns.page.go` можно не вызывать, потому что после `ns.init` | ||
// `ns.page.go` все равно вызывается. | ||
}, | ||
legacy: false | ||
}; | ||
|
||
// Откат на `hashchange`. | ||
} else { | ||
// Редирект с текущего полноценного урла на его хешовый аналог. | ||
// | ||
// TODO: При добавлении способа задания корневого урла заменить | ||
// слеш на нужное свойство/метод. | ||
if ((loc.pathname + loc.search) !== '/') { | ||
return loc.replace('/#' + loc.pathname + loc.search); | ||
} | ||
|
||
// Заставляет `hashchange` игнорировать смену URL через вызов legacy | ||
// `pushState` или `replaceState`. | ||
var ignore = false; | ||
ns.history.pushState = function(url, title) { | ||
if (isFunction(window.history.pushState)) { | ||
window.history.pushState(null, title || ns.page.title(url), url); | ||
} | ||
}; | ||
|
||
window.addEventListener('hashchange', function() { | ||
if (!ignore) { | ||
ns.page.go(); | ||
} | ||
ns.history.replaceState = function(url, title) { | ||
if (isFunction(window.history.replaceState)) { | ||
window.history.replaceState(null, title || ns.page.title(url), url); | ||
} | ||
}; | ||
|
||
ignore = false; | ||
}, false); | ||
ns.history.onpopstate = function() { | ||
ns.page.go('', true); | ||
}; | ||
|
||
return { | ||
pushState: function(url) { | ||
ignore = true; | ||
loc.hash = url; | ||
}, | ||
replaceState: function(url) { | ||
ignore = true; | ||
loc.replace(loc.pathname + loc.search + '#' + url); | ||
}, | ||
adapt: no.nop, | ||
legacy: true | ||
}; | ||
} | ||
/** | ||
* Проверяет, является ли переданный объект функцией. | ||
* @param {Function} fn | ||
* @return {Boolean} | ||
*/ | ||
function isFunction(fn) { | ||
return 'function' == typeof fn; | ||
} | ||
|
||
}(window, ns)); | ||
})(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,7 @@ ns.page._lastUrl = ''; | |
|
||
/** | ||
* Осуществляем переход по ссылке. | ||
* @param {String} [url=location.pathname + location.search] | ||
* @param {String} [url=ns.page.getCurrentUrl()] | ||
* @param {Boolean} [preventAddingToHistory=false] Не добавлять урл в историю браузера. | ||
* @return {no.Promise} | ||
*/ | ||
|
@@ -29,9 +29,7 @@ ns.page.go = function(url, preventAddingToHistory) { | |
return no.Promise.rejected('transaction'); | ||
} | ||
|
||
var loc = window.location; | ||
|
||
url = url || (ns.history.legacy ? loc.hash.substr(1) : (loc.pathname + loc.search)); | ||
url = url || ns.page.getCurrentUrl(); | ||
|
||
// возможность заблокировать переход | ||
if (!ns.page.block.check(url)) { | ||
|
@@ -165,6 +163,13 @@ ns.page.getDefaultUrl = function() { | |
return ns.router.url('/'); | ||
}; | ||
|
||
/** | ||
* Calculates current application url, fed as default value for `ns.page.go`. | ||
*/ | ||
ns.page.getCurrentUrl = function() { | ||
return window.location.pathname + window.location.search; | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Можно просто написать: ns.page.getCurrentUrl = function() {
var location = window.history.location || window.location;
return location.pathname + location.search;
} и не нужно будет писать вот этого кода: if (history.emulate) {
ns.page.getCurrentUrl = function() {
return history.location.pathname + history.location.search;
};
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Дело в том, что мы не включаем HTML5-History-API в noscript по умолчанию: страница
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. не вижу ничего ужасного в добавлении условия Но это лишь мое мнение, решать конечно автору приложения о котором тут ведется речь) |
||
|
||
/** | ||
* Object to work with application history. | ||
* @namespace | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.redirect()
полезно использовать и в новых браузерах, что бы было автоматическое преобразование из ссылок вида:/#/notes/141
в ссылки вида:/notes/141
Но вам виднее конечно.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
О, спасибо за комментарий, это правда полезнее. Да и вообще, спасибо за библиотеку.