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 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: []