Created
June 30, 2015 13:27
-
-
Save Tolia/99453da0ccecf16d3cc0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
angular | |
.module('turbo.pages', []) | |
.config(["$locationProvider", ($locationProvider) -> | |
$locationProvider.html5Mode | |
enabled: true | |
requireBase: false | |
]) | |
.provider('$turboPageTemplate', -> | |
provider = | |
config: | |
heders: | |
'Accept': 'text/html' | |
$get: [ | |
"$http" | |
"$q" | |
"$cacheFactory" | |
"$documentParser" | |
"$timeout" | |
($http, $q, $cacheFactory, $documentParser, $timeout) -> | |
$cachePage = $cacheFactory "routTemplate", capacity: 20 | |
api = | |
getState: (pathname) -> | |
$cachePage.get(pathname) || {pathname: pathname} | |
updateSate: (pathname, params) -> | |
state = @getState pathname | |
if params | |
state = angular.extend state, params | |
$cachePage.put pathname, state | |
state | |
updateScroll: (pathname, scrollTop) -> | |
scrollTop = window.scrollTop || window.scrollY unless scrollTop? | |
@updateSate pathname, | |
$scrollTop: scrollTop | |
get: (pathname) -> | |
deferred = $q.defer() | |
state = @getState pathname | |
if !state || !(state.$template && state.$cache) | |
httpConfig = | |
method: 'GET' | |
url: pathname | |
cache: false | |
headers: provider.config.heders | |
parseResponse = (data) -> | |
parser = $documentParser data | |
window.parser = parser | |
page = parser.find(".turbo-page") | |
unless page | |
deferred.reject 'no turbo' | |
return | |
cacheTemplate = parser.find("[data-turbo-page-cache]")?.getAttribute('data-turbo-page-cache') | |
state = @updateSate pathname, | |
$template: page.innerHTML | |
$cache: cacheTemplate | |
$title: parser.title() | |
deferred.resolve state | |
$http(httpConfig) | |
.success parseResponse.bind(@) | |
.error parseResponse.bind(@) | |
else | |
deferred.resolve state | |
deferred.promise | |
] | |
) | |
.service('$linkParser', [ -> | |
getLink = (url) -> | |
link = document.createElement('a') | |
link.href = url | |
link | |
(url = "") -> | |
link = getLink(url) | |
parser = | |
protocol: link.protocol # "http:" | |
hostname: link.hostname # "example.com" | |
port: link.port # "3000" | |
pathname: link.pathname # "/pathname/" | |
search: link.search # "?search=test" | |
hash: link.hash # "#hash" | |
fullpath: link.pathname + link.hash | |
]) | |
.service('$documentParser', [ -> | |
createDocumentUsingParser = (html) -> | |
(new DOMParser).parseFromString html, 'text/html' | |
createDocumentUsingDOM = (html) -> | |
doc = document.implementation.createHTMLDocument '' | |
if doc.documentElement | |
doc.documentElement.innerHTML = html | |
else | |
console.error html | |
doc | |
createDocumentUsingWrite = (html) -> | |
doc = document.implementation.createHTMLDocument '' | |
doc.open 'replace' | |
doc.write html | |
doc.close() | |
doc | |
parser = do -> | |
try | |
if window.DOMParser | |
testDoc = createDocumentUsingParser '<html><body><p>test' | |
createDocumentUsingParser | |
catch e | |
testDoc = createDocumentUsingDOM '<html><body><p>test' | |
createDocumentUsingDOM | |
finally | |
unless testDoc?.body?.childNodes.length is 1 | |
return createDocumentUsingWrite | |
class domBulder | |
constructor: (text) -> | |
@doc = parser text | |
@body = @doc.body | |
title: -> | |
@doc.title | |
find: (selector) -> | |
@doc.querySelector(selector) | |
(text) -> | |
new domBulder text | |
]) | |
.directive('turboPage', [ | |
"$compile" | |
"$location" | |
"$turboPageTemplate" | |
"$rootScope" | |
"$linkParser" | |
'$timeout' | |
($compile, $location, $turboPageTemplate, $rootScope, $linkParser, $timeout) -> | |
linkTemplate = ($element, state) -> | |
$template = state.$template | |
$element.html $template | |
$compile $element.contents() | |
class CheckPagePaths | |
constructor: (newUrl, oldUrl) -> | |
@newest = $linkParser newUrl | |
@last = $linkParser oldUrl | |
validate: -> | |
@newest.fullpath != @last.fullpath | |
directive = | |
restrict: "AC" | |
priority: 999 | |
transclude: true | |
replace: true | |
scope: true | |
template: "<div ng-class=\"className\" ng-transclude></div>" | |
link: (scope, $element) -> | |
dropOldScope = -> | |
scope.$$childTail?.$destroy() | |
setSatus = (status) -> | |
scope.className = status + "_loading_router" | |
load = (path,oldPath) -> | |
setSatus "start" | |
$turboPageTemplate.updateScroll(oldPath) | |
$turboPageTemplate.get(path) | |
.then (state) -> | |
dropOldScope() | |
link = linkTemplate $element, state | |
document.title = state.$title if state.$title | |
link scope.$new() | |
$rootScope.$broadcast '$turbolinksUpdate' | |
timerId = $timeout -> | |
y = state.$scrollTop || 0 | |
window.scrollTo 0, y | |
setSatus "done" | |
, (error) -> | |
window.location.reload() | |
update = (e, newUrl, oldUrl) -> | |
check = new CheckPagePaths newUrl, oldUrl | |
if check.validate() | |
load(check.newest.fullpath, check.last.fullpath) | |
$rootScope.$on '$turbolinksReload', (event, href) => | |
load href | |
.then -> | |
window.scrollTo 0, 0 | |
$rootScope.$on '$locationChangeStart', update | |
]) | |
.directive('turboReload', [ | |
'$rootScope' | |
'$location' | |
($rootScope, $location) -> | |
directive = | |
restrict: "A" | |
link: (scope, $element) -> | |
$element.on 'click', () -> | |
href = $element.attr('href') | |
if href | |
$rootScope.$broadcast '$turbolinksReload', href | |
]) | |
.directive('turboReset', [ | |
'$linkParser' | |
'$turboPageTemplate' | |
($linkParser, $turboPageTemplate) -> | |
directive = | |
restrict: "AC" | |
scope: false | |
link: ($scope, $element, $attrs) -> | |
$element.on 'click', ($event) -> | |
return unless $event.srcElement | |
href = $event.srcElement.href | |
return if !href | |
parser = $linkParser(href) | |
$turboPageTemplate.updateScroll(parser.fullpath,0) | |
]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment