angular-turbolinks 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.swp
19
+ *.swo
20
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in angular-turbolinks.gemspec
4
+ gemspec
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,8 @@
1
+ require "angular/turbolinks/version"
2
+
3
+ module Angular
4
+ module Turbolinks
5
+ class Engine < ::Rails::Engine
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module Angular
2
+ module Turbolinks
3
+ VERSION = "0.0.1"
4
+ end
5
+ 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: []