angular-turbolinks 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +47 -0
- data/Rakefile +1 -0
- data/angular-turbolinks.gemspec +25 -0
- data/lib/angular/turbolinks.rb +8 -0
- data/lib/angular/turbolinks/version.rb +5 -0
- data/lib/assets/javascripts/angular-turbolinks.js.coffee +193 -0
- metadata +109 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 154e3cc700a4bc97f9bf09d61400d4c72a10a050
|
4
|
+
data.tar.gz: c544bdd9905690010f65bd0216b29a637801672a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 79ea116909e48bc963193b8de2faf5e5bee3bca335d301be57ae335af52f201d945c467497419d0eee39f725c9747de439cc6454df6711218fa0745ca0b0e1ca
|
7
|
+
data.tar.gz: f62564cb01d3f3b2203c478b4d9dd29c199f6e11ba5a991e58e87bff82c702792933fb94bcb50c8cc84dfc4a87cb7ed0711a1ff32b9a413dee15f9ca0512e26e
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Cary Dunn
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Angular::Turbolinks
|
2
|
+
|
3
|
+
##### Add angular-turbolinks and turbolinks to your Gemfile
|
4
|
+
```sh
|
5
|
+
gem "turbolinks"
|
6
|
+
gem "angular-turbolinks"
|
7
|
+
```
|
8
|
+
|
9
|
+
##### Add angular-turbolinks to your sprockets
|
10
|
+
```sh
|
11
|
+
//= require angular-turbolinks
|
12
|
+
```
|
13
|
+
|
14
|
+
##### Add 'ngTurbolinks' and 'ngRoute' to your angular.module
|
15
|
+
```sh
|
16
|
+
var app = angular.module('...', [..., 'ngRoute', 'ngTurbolinks'])
|
17
|
+
```
|
18
|
+
|
19
|
+
##### Make sure HTML5 mode is enabled...
|
20
|
+
```sh
|
21
|
+
app.config([
|
22
|
+
"$locationProvider", function($locationProvider) {
|
23
|
+
$locationProvider.html5Mode(true);
|
24
|
+
}
|
25
|
+
]);
|
26
|
+
```
|
27
|
+
|
28
|
+
##### Move angular bootstrapping to turbolinks event
|
29
|
+
```sh
|
30
|
+
$(document).on('ready page:load', ->
|
31
|
+
angular.bootstrap($("body"), ['app'])
|
32
|
+
).on('page:before-change', ->
|
33
|
+
angular.element("body").scope().$broadcast("$destroy")
|
34
|
+
)
|
35
|
+
```
|
36
|
+
|
37
|
+
##### TODO
|
38
|
+
* add support for turbolinks redirection logic
|
39
|
+
|
40
|
+
##### Caveats
|
41
|
+
* This is a first stab just to try to get around the '10 $digest() iterations reached using $locationWatch' errors I was receiving when using turbolinks with angular
|
42
|
+
* https://github.com/angular/angular.js/issues/3915
|
43
|
+
* https://github.com/angular/angular.js/issues/2815 (among others)
|
44
|
+
* none of the suggested fixes worked for me and this was happening on chrome
|
45
|
+
* This approach uses the angular $location/$locationProvider services for click tracking and pushState, steals the $locationChangeStart event and runs the changed url through turbolinks methods
|
46
|
+
* Does not support any of the turbolinks caching
|
47
|
+
* Eventually im hoping angular $locationWatch can play nice with external plugins using pushState...
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'angular/turbolinks/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "angular-turbolinks"
|
8
|
+
spec.version = Angular::Turbolinks::VERSION
|
9
|
+
spec.authors = ["Cary Dunn"]
|
10
|
+
spec.email = ["cary.dunn@gmail.com"]
|
11
|
+
spec.description = %q{Rails Turbolinks + Angular}
|
12
|
+
spec.summary = %q{Rails Turbolinks + Angular}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_dependency 'coffee-rails'
|
24
|
+
spec.add_dependency 'turbolinks'
|
25
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
angular.module('ngTurbolinks', []).run(($location, $rootScope, $http, $q)->
|
2
|
+
|
3
|
+
loadedAssets = null
|
4
|
+
createDocument = null
|
5
|
+
xhr_req = null
|
6
|
+
referer = null
|
7
|
+
|
8
|
+
triggerEvent = (name, data) ->
|
9
|
+
event = document.createEvent 'Events'
|
10
|
+
event.data = data if data
|
11
|
+
event.initEvent name, true, true
|
12
|
+
document.dispatchEvent event
|
13
|
+
|
14
|
+
popCookie = (name) ->
|
15
|
+
value = document.cookie.match(new RegExp(name+"=(\\w+)"))?[1].toUpperCase() or ''
|
16
|
+
document.cookie = name + '=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/'
|
17
|
+
value
|
18
|
+
|
19
|
+
rememberReferer = ->
|
20
|
+
referer = document.location.href
|
21
|
+
|
22
|
+
processResponse = (responseText, status, headers)->
|
23
|
+
clientOrServerError = ->
|
24
|
+
400 <= status < 600
|
25
|
+
|
26
|
+
validContent = ->
|
27
|
+
headers()["content-type"].match /^(?:text\/html|application\/xhtml\+xml|application\/xml)(?:;|$)/
|
28
|
+
|
29
|
+
extractTrackAssets = (doc) ->
|
30
|
+
for node in doc.head.childNodes when node.getAttribute?('data-turbolinks-track')?
|
31
|
+
node.getAttribute('src') or node.getAttribute('href')
|
32
|
+
|
33
|
+
assetsChanged = (doc) ->
|
34
|
+
loadedAssets ||= extractTrackAssets document
|
35
|
+
fetchedAssets = extractTrackAssets doc
|
36
|
+
fetchedAssets.length isnt loadedAssets.length or intersection(fetchedAssets, loadedAssets).length isnt loadedAssets.length
|
37
|
+
|
38
|
+
intersection = (a, b) ->
|
39
|
+
[a, b] = [b, a] if a.length > b.length
|
40
|
+
value for value in a when value in b
|
41
|
+
|
42
|
+
if not clientOrServerError() and validContent()
|
43
|
+
doc = createDocument responseText
|
44
|
+
if doc and !assetsChanged doc
|
45
|
+
return doc
|
46
|
+
|
47
|
+
browserCompatibleDocumentParser = ->
|
48
|
+
createDocumentUsingParser = (html) ->
|
49
|
+
(new DOMParser).parseFromString html, 'text/html'
|
50
|
+
|
51
|
+
createDocumentUsingDOM = (html) ->
|
52
|
+
doc = document.implementation.createHTMLDocument ''
|
53
|
+
doc.documentElement.innerHTML = html
|
54
|
+
doc
|
55
|
+
|
56
|
+
createDocumentUsingWrite = (html) ->
|
57
|
+
doc = document.implementation.createHTMLDocument ''
|
58
|
+
doc.open 'replace'
|
59
|
+
doc.write html
|
60
|
+
doc.close()
|
61
|
+
doc
|
62
|
+
|
63
|
+
# Use createDocumentUsingParser if DOMParser is defined and natively
|
64
|
+
# supports 'text/html' parsing (Firefox 12+, IE 10)
|
65
|
+
#
|
66
|
+
# Use createDocumentUsingDOM if createDocumentUsingParser throws an exception
|
67
|
+
# due to unsupported type 'text/html' (Firefox < 12, Opera)
|
68
|
+
#
|
69
|
+
# Use createDocumentUsingWrite if:
|
70
|
+
# - DOMParser isn't defined
|
71
|
+
# - createDocumentUsingParser returns null due to unsupported type 'text/html' (Chrome, Safari)
|
72
|
+
# - createDocumentUsingDOM doesn't create a valid HTML document (safeguarding against potential edge cases)
|
73
|
+
try
|
74
|
+
if window.DOMParser
|
75
|
+
testDoc = createDocumentUsingParser '<html><body><p>test'
|
76
|
+
createDocumentUsingParser
|
77
|
+
catch e
|
78
|
+
testDoc = createDocumentUsingDOM '<html><body><p>test'
|
79
|
+
createDocumentUsingDOM
|
80
|
+
finally
|
81
|
+
unless testDoc?.body?.childNodes.length is 1
|
82
|
+
return createDocumentUsingWrite
|
83
|
+
|
84
|
+
extractTitleAndBody = (doc) ->
|
85
|
+
title = doc.querySelector 'title'
|
86
|
+
[ title?.textContent, removeNoscriptTags(doc.body), CSRFToken.get(doc).token, 'runScripts' ]
|
87
|
+
|
88
|
+
CSRFToken =
|
89
|
+
get: (doc = document) ->
|
90
|
+
node: tag = doc.querySelector 'meta[name="csrf-token"]'
|
91
|
+
token: tag?.getAttribute? 'content'
|
92
|
+
|
93
|
+
update: (latest) ->
|
94
|
+
current = @get()
|
95
|
+
if current.token? and latest? and current.token isnt latest
|
96
|
+
current.node.setAttribute 'content', latest
|
97
|
+
|
98
|
+
changePage = (title, body, csrfToken, runScripts) ->
|
99
|
+
document.title = title
|
100
|
+
document.documentElement.replaceChild body, document.body
|
101
|
+
CSRFToken.update csrfToken if csrfToken?
|
102
|
+
executeScriptTags() if runScripts
|
103
|
+
currentState = window.history.state
|
104
|
+
triggerEvent 'page:change'
|
105
|
+
triggerEvent 'page:update'
|
106
|
+
|
107
|
+
executeScriptTags = ->
|
108
|
+
scripts = Array::slice.call document.body.querySelectorAll 'script:not([data-turbolinks-eval="false"])'
|
109
|
+
for script in scripts when script.type in ['', 'text/javascript']
|
110
|
+
copy = document.createElement 'script'
|
111
|
+
copy.setAttribute attr.name, attr.value for attr in script.attributes
|
112
|
+
copy.appendChild document.createTextNode script.innerHTML
|
113
|
+
{ parentNode, nextSibling } = script
|
114
|
+
parentNode.removeChild script
|
115
|
+
parentNode.insertBefore copy, nextSibling
|
116
|
+
return
|
117
|
+
|
118
|
+
removeNoscriptTags = (node) ->
|
119
|
+
node.innerHTML = node.innerHTML.replace /<noscript[\S\s]*?<\/noscript>/ig, ''
|
120
|
+
node
|
121
|
+
|
122
|
+
fetch = (url)->
|
123
|
+
rememberReferer()
|
124
|
+
|
125
|
+
xhr_req.resolve() if xhr_req
|
126
|
+
xhr_req = $q.defer()
|
127
|
+
|
128
|
+
$http.get(url, {
|
129
|
+
headers: {
|
130
|
+
'Accept' : 'text/html, application/xhtml+xml, application/xml'
|
131
|
+
'X-XHR-Referer' : referer
|
132
|
+
},
|
133
|
+
timeout: xhr_req.promise
|
134
|
+
}).success((data, status, headers)->
|
135
|
+
if doc = processResponse(data, status, headers)
|
136
|
+
changePage extractTitleAndBody(doc)...
|
137
|
+
#reflectRedirectedUrl()
|
138
|
+
triggerEvent 'page:load'
|
139
|
+
else
|
140
|
+
document.location.href = url
|
141
|
+
).error(->
|
142
|
+
console.log 'error'
|
143
|
+
)
|
144
|
+
|
145
|
+
# Handle bug in Firefox 26/27 where history.state is initially undefined
|
146
|
+
historyStateIsDefined =
|
147
|
+
window.history.state != undefined or navigator.userAgent.match /Firefox\/2[6|7]/
|
148
|
+
|
149
|
+
browserSupportsPushState =
|
150
|
+
window.history and window.history.pushState and window.history.replaceState and historyStateIsDefined
|
151
|
+
|
152
|
+
browserIsntBuggy =
|
153
|
+
!navigator.userAgent.match /CriOS\//
|
154
|
+
|
155
|
+
requestMethodIsSafe =
|
156
|
+
popCookie('request_method') in ['GET','']
|
157
|
+
|
158
|
+
browserSupportsTurbolinks = browserSupportsPushState and browserIsntBuggy and requestMethodIsSafe
|
159
|
+
|
160
|
+
browserSupportsCustomEvents =
|
161
|
+
document.addEventListener and document.createEvent
|
162
|
+
|
163
|
+
installDocumentReadyPageEventTriggers = ->
|
164
|
+
document.addEventListener 'DOMContentLoaded', ( ->
|
165
|
+
triggerEvent 'page:change'
|
166
|
+
triggerEvent 'page:update'
|
167
|
+
), true
|
168
|
+
|
169
|
+
installJqueryAjaxSuccessPageUpdateTrigger = ->
|
170
|
+
if typeof jQuery isnt 'undefined'
|
171
|
+
jQuery(document).on 'ajaxSuccess', (event, xhr, settings) ->
|
172
|
+
return unless jQuery.trim xhr.responseText
|
173
|
+
triggerEvent 'page:update'
|
174
|
+
|
175
|
+
if browserSupportsCustomEvents
|
176
|
+
installDocumentReadyPageEventTriggers()
|
177
|
+
installJqueryAjaxSuccessPageUpdateTrigger()
|
178
|
+
|
179
|
+
if browserSupportsTurbolinks
|
180
|
+
visit = fetch
|
181
|
+
createDocument = browserCompatibleDocumentParser()
|
182
|
+
else
|
183
|
+
visit = (url) ->
|
184
|
+
document.location.href = url
|
185
|
+
|
186
|
+
$rootScope.$on("$locationChangeStart", (event, url, prev_url)->
|
187
|
+
if url == prev_url
|
188
|
+
event.preventDefault()
|
189
|
+
return false
|
190
|
+
|
191
|
+
visit(url)
|
192
|
+
)
|
193
|
+
)
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: angular-turbolinks
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cary Dunn
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-01-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: coffee-rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: turbolinks
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Rails Turbolinks + Angular
|
70
|
+
email:
|
71
|
+
- cary.dunn@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE.txt
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- angular-turbolinks.gemspec
|
82
|
+
- lib/angular/turbolinks.rb
|
83
|
+
- lib/angular/turbolinks/version.rb
|
84
|
+
- lib/assets/javascripts/angular-turbolinks.js.coffee
|
85
|
+
homepage: ''
|
86
|
+
licenses:
|
87
|
+
- MIT
|
88
|
+
metadata: {}
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options: []
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
requirements: []
|
104
|
+
rubyforge_project:
|
105
|
+
rubygems_version: 2.1.11
|
106
|
+
signing_key:
|
107
|
+
specification_version: 4
|
108
|
+
summary: Rails Turbolinks + Angular
|
109
|
+
test_files: []
|