breezy 0.1.3 → 0.1.4
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 +4 -4
- data/README.md +3 -3
- data/app/views/breezy/response.html.erb +0 -0
- data/lib/assets/javascripts/breezy/component_url.coffee +61 -0
- data/lib/assets/javascripts/breezy/controller.coffee +197 -0
- data/lib/assets/javascripts/breezy/csrf_token.coffee +9 -0
- data/lib/assets/javascripts/breezy/doubly_linked_list.coffee +57 -0
- data/lib/assets/javascripts/breezy/parallel_queue.coffee +35 -0
- data/lib/assets/javascripts/breezy/progress_bar.coffee +139 -0
- data/lib/assets/javascripts/breezy/remote.coffee +136 -0
- data/lib/assets/javascripts/breezy/snapshot.coffee +100 -0
- data/lib/assets/javascripts/breezy/start.coffee +60 -0
- data/lib/assets/javascripts/breezy/utils.coffee +174 -0
- data/lib/breezy/version.rb +1 -1
- data/lib/breezy_template/search_extension.rb +39 -14
- data/lib/generators/breezy/install/install_generator.rb +61 -0
- data/lib/generators/breezy/install/templates/Default.js.jsx +7 -0
- data/lib/generators/breezy/install/templates/View.js.jsx +7 -0
- data/lib/generators/breezy/install/templates/boot.js +5 -0
- data/lib/generators/breezy/view/templates/view.js.breezy +15 -0
- data/lib/generators/breezy/view/templates/view.js.jsx +8 -0
- data/lib/generators/breezy/view/view_generator.rb +35 -0
- data/test/breezy_template_test.rb +49 -5
- metadata +20 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a241ba166d21aca45e519db2413f0fc9d47c6209
|
4
|
+
data.tar.gz: 697ff9e8f58420f08dc10d01c185f200b00a6357
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad4a653fc55253f0ae7ca1f381f3ff34db917460a62b52cbe9dfe766335003b1b978adfb041fe8ff563e82ae0288db986d8b70c61f5d9b5272c65efefcd3f0e9
|
7
|
+
data.tar.gz: 8f10b7d1ed970640d8472991697f4ceb4883c46757831fbe89db4dfe44f61a2db5b73f05bfa6534b29655aab2b7d4d2d1aaf6eff388518a305f24c24249f81f0
|
data/README.md
CHANGED
@@ -104,7 +104,7 @@ rails g breezy:view Posts new index
|
|
104
104
|
```
|
105
105
|
|
106
106
|
# Navigation and Forms
|
107
|
-
Breezy intercepts all clicks on `<a>` and all submits on `<form>` elements enabled with `data-bz-remote`. Breezy will `preventDefault` then make the same request using XMLHttpRequest with a content type of `.js`. If there's an existing request, Breezy will cancel it unless the `data-bz-async` option is used.
|
107
|
+
Breezy intercepts all clicks on `<a>` and all submits on `<form>` elements enabled with `data-bz-remote`. Breezy will `preventDefault` then make the same request using XMLHttpRequest with a content type of `.js`. If there's an existing request, Breezy will cancel it unless the `data-bz-remote-async` option is used.
|
108
108
|
|
109
109
|
Once the response loads, a `breezy:load` event will be fired with the JS object that you created with BreezyTemplates. If you used the installation generator, the event will be set for you in the `<head>` element of your layout:
|
110
110
|
|
@@ -123,8 +123,8 @@ document.addEventListener('breezy:load', function(event){
|
|
123
123
|
Attribute | default value | description
|
124
124
|
-------------------|--------------------------|------------
|
125
125
|
`data-bz-remote` | For `<a>` the default is `get`. For forms, the default is `post` if a method is not specified. | Use this to create seamless page to page transitions. Works for both links and forms. You can specify the request method by giving it a value, e.g `<a href='foobar' data-bz-remote=post>`. For forms, the request method of the form is used. `<form action=foobar method='post' data-bz-remote>`.
|
126
|
-
`data-bz-async` | `false` | Fires off an async request. Responses are pushed into a queue will be evaluated in order of click or submit.
|
127
|
-
`data-bz-push-state` | `true` | Captures the element's URL in the browsers history. Normally used with `data-bz-async`.
|
126
|
+
`data-bz-remote-async` | `false` | Fires off an async request. Responses are pushed into a queue will be evaluated in order of click or submit.
|
127
|
+
`data-bz-push-state` | `true` | Captures the element's URL in the browsers history. Normally used with `data-bz-remote-async`.
|
128
128
|
`data-bz-silent` | false | To be used with the `breezy_silent?` ruby helper. Useful if you don't want to perform a redirect or render. Just return a 204, and Breezy will not fire a `breezy:load` event.
|
129
129
|
|
130
130
|
|
File without changes
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# The ComponentUrl class converts a basic URL string into an object
|
2
|
+
# that behaves similarly to document.location.
|
3
|
+
#
|
4
|
+
# If an instance is created from a relative URL, the current document
|
5
|
+
# is used to fill in the missing attributes (protocol, host, port).
|
6
|
+
uniqueId = ->
|
7
|
+
new Date().getTime().toString(36)
|
8
|
+
|
9
|
+
class Breezy.ComponentUrl
|
10
|
+
constructor: (@original = document.location.href) ->
|
11
|
+
return @original if @original.constructor is Breezy.ComponentUrl
|
12
|
+
@_parse()
|
13
|
+
|
14
|
+
withoutHash: -> @href.replace(@hash, '').replace('#', '')
|
15
|
+
|
16
|
+
# Intention revealing function alias
|
17
|
+
withoutHashForIE10compatibility: -> @withoutHash()
|
18
|
+
|
19
|
+
hasNoHash: -> @hash.length is 0
|
20
|
+
|
21
|
+
crossOrigin: ->
|
22
|
+
@origin isnt (new Breezy.ComponentUrl).origin
|
23
|
+
|
24
|
+
formatForXHR: (options = {}) ->
|
25
|
+
(if options.cache then @withMimeBust() else @withAntiCacheParam()).withoutHashForIE10compatibility()
|
26
|
+
|
27
|
+
withMimeBust: ->
|
28
|
+
new Breezy.ComponentUrl(
|
29
|
+
if /([?&])__=[^&]*/.test @absolute
|
30
|
+
@absolute
|
31
|
+
else
|
32
|
+
new Breezy.ComponentUrl(@withoutHash() + (if /\?/.test(@absolute) then "&" else "?") + "__=0" + @hash)
|
33
|
+
)
|
34
|
+
|
35
|
+
withAntiCacheParam: ->
|
36
|
+
new Breezy.ComponentUrl(
|
37
|
+
if /([?&])_=[^&]*/.test @absolute
|
38
|
+
@absolute.replace /([?&])_=[^&]*/, "$1_=#{uniqueId()}"
|
39
|
+
else
|
40
|
+
new Breezy.ComponentUrl(@withoutHash() + (if /\?/.test(@absolute) then "&" else "?") + "_=#{uniqueId()}" + @hash)
|
41
|
+
)
|
42
|
+
|
43
|
+
_parse: ->
|
44
|
+
(@link ?= document.createElement 'a').href = @original
|
45
|
+
{ @href, @protocol, @host, @hostname, @port, @pathname, @search, @hash } = @link
|
46
|
+
|
47
|
+
if @protocol == ':'
|
48
|
+
@protocol = document.location.protocol
|
49
|
+
if @protocol == ''
|
50
|
+
@protocol = document.location.protocol
|
51
|
+
if @port == ''
|
52
|
+
@port = document.location.port
|
53
|
+
if @hostname == ''
|
54
|
+
@hostname = document.location.hostname
|
55
|
+
if @pathname == ''
|
56
|
+
@pathname = '/'
|
57
|
+
|
58
|
+
@origin = [@protocol, '//', @hostname].join ''
|
59
|
+
@origin += ":#{@port}" unless @port.length is 0
|
60
|
+
@relative = [@pathname, @search, @hash].join ''
|
61
|
+
@absolute = @href
|
@@ -0,0 +1,197 @@
|
|
1
|
+
#= require breezy/doubly_linked_list
|
2
|
+
#= require breezy/snapshot
|
3
|
+
#= require breezy/progress_bar
|
4
|
+
#= require breezy/parallel_queue
|
5
|
+
#= require breezy/component_url
|
6
|
+
|
7
|
+
PAGE_CACHE_SIZE = 20
|
8
|
+
|
9
|
+
class Breezy.Controller
|
10
|
+
constructor: ->
|
11
|
+
@atomCache = {}
|
12
|
+
@history = new Breezy.Snapshot(this)
|
13
|
+
@transitionCacheEnabled = false
|
14
|
+
@requestCachingEnabled = true
|
15
|
+
|
16
|
+
@progressBar = new Breezy.ProgressBar 'html'
|
17
|
+
@pq = new Breezy.ParallelQueue
|
18
|
+
@http = null
|
19
|
+
|
20
|
+
@history.rememberCurrentUrlAndState()
|
21
|
+
|
22
|
+
currentPage: =>
|
23
|
+
@history.currentPage
|
24
|
+
|
25
|
+
request: (url, options = {}) =>
|
26
|
+
options = Breezy.Utils.reverseMerge options,
|
27
|
+
pushState: true
|
28
|
+
|
29
|
+
url = new Breezy.ComponentUrl url
|
30
|
+
return if @pageChangePrevented(url.absolute, options.target)
|
31
|
+
|
32
|
+
if url.crossOrigin()
|
33
|
+
document.location.href = url.absolute
|
34
|
+
return
|
35
|
+
|
36
|
+
@history.cacheCurrentPage()
|
37
|
+
if @progressBar? and !options.async
|
38
|
+
@progressBar?.start()
|
39
|
+
restorePoint = @history.transitionCacheFor(url.absolute)
|
40
|
+
|
41
|
+
if @transitionCacheEnabled and restorePoint and restorePoint.transition_cache
|
42
|
+
@history.reflectNewUrl(url)
|
43
|
+
@restore(restorePoint)
|
44
|
+
options.showProgressBar = false
|
45
|
+
|
46
|
+
options.cacheRequest ?= @requestCachingEnabled
|
47
|
+
options.showProgressBar ?= true
|
48
|
+
|
49
|
+
Breezy.Utils.triggerEvent Breezy.EVENTS.FETCH, url: url.absolute, options.target
|
50
|
+
|
51
|
+
if options.async
|
52
|
+
options.showProgressBar = false
|
53
|
+
req = @createRequest(url, options)
|
54
|
+
req.onError = ->
|
55
|
+
Breezy.Utils.triggerEvent Breezy.EVENTS.ERROR, null, options.target
|
56
|
+
@pq.push(req)
|
57
|
+
req.send(options.payload)
|
58
|
+
else
|
59
|
+
@pq.drain()
|
60
|
+
@http?.abort()
|
61
|
+
@http = @createRequest(url, options)
|
62
|
+
@http.send(options.payload)
|
63
|
+
|
64
|
+
enableTransitionCache: (enable = true) =>
|
65
|
+
@transitionCacheEnabled = enable
|
66
|
+
|
67
|
+
disableRequestCaching: (disable = true) =>
|
68
|
+
@requestCachingEnabled = not disable
|
69
|
+
disable
|
70
|
+
|
71
|
+
restore: (cachedPage, options = {}) =>
|
72
|
+
@http?.abort()
|
73
|
+
@history.changePage(cachedPage, options)
|
74
|
+
|
75
|
+
@progressBar?.done()
|
76
|
+
Breezy.Utils.triggerEvent Breezy.EVENTS.RESTORE
|
77
|
+
Breezy.Utils.triggerEvent Breezy.EVENTS.LOAD, cachedPage
|
78
|
+
|
79
|
+
replace: (nextPage, options = {}) =>
|
80
|
+
Breezy.Utils.withDefaults(nextPage, @history.currentBrowserState)
|
81
|
+
@history.changePage(nextPage, options)
|
82
|
+
Breezy.Utils.triggerEvent Breezy.EVENTS.LOAD, @currentPage()
|
83
|
+
|
84
|
+
crossOriginRedirect: =>
|
85
|
+
redirect = @http.getResponseHeader('Location')
|
86
|
+
crossOrigin = (new Breezy.ComponentUrl(redirect)).crossOrigin()
|
87
|
+
|
88
|
+
if redirect? and crossOrigin
|
89
|
+
redirect
|
90
|
+
|
91
|
+
pageChangePrevented: (url, target) =>
|
92
|
+
!Breezy.Utils.triggerEvent Breezy.EVENTS.BEFORE_CHANGE, url: url, target
|
93
|
+
|
94
|
+
cache: (key, value) =>
|
95
|
+
return @atomCache[key] if value == null
|
96
|
+
@atomCache[key] ||= value
|
97
|
+
|
98
|
+
# Events
|
99
|
+
onLoadEnd: => @http = null
|
100
|
+
|
101
|
+
onLoad: (xhr, url, options) =>
|
102
|
+
Breezy.Utils.triggerEvent Breezy.EVENTS.RECEIVE, url: url.absolute, options.target
|
103
|
+
nextPage = @processResponse(xhr)
|
104
|
+
if xhr.status == 0
|
105
|
+
return
|
106
|
+
|
107
|
+
if nextPage
|
108
|
+
if options.async && url.pathname != @currentPage().pathname
|
109
|
+
|
110
|
+
unless options.ignoreSamePathConstraint
|
111
|
+
@progressBar?.done()
|
112
|
+
Breezy.Utils.warn("Async response path is different from current page path")
|
113
|
+
return
|
114
|
+
|
115
|
+
if options.pushState
|
116
|
+
@history.reflectNewUrl url
|
117
|
+
|
118
|
+
Breezy.Utils.withDefaults(nextPage, @history.currentBrowserState)
|
119
|
+
|
120
|
+
if nextPage.action != 'graft'
|
121
|
+
@history.changePage(nextPage, options)
|
122
|
+
Breezy.Utils.triggerEvent Breezy.EVENTS.LOAD, @currentPage()
|
123
|
+
else
|
124
|
+
##clean this up
|
125
|
+
@history.graftByKeypath("data.#{nextPage.path}", nextPage.data)
|
126
|
+
|
127
|
+
if options.showProgressBar
|
128
|
+
@progressBar?.done()
|
129
|
+
@history.constrainPageCacheTo()
|
130
|
+
else
|
131
|
+
if options.async
|
132
|
+
Breezy.Utils.triggerEvent Breezy.EVENTS.ERROR, xhr, options.target
|
133
|
+
else
|
134
|
+
@progressBar?.done()
|
135
|
+
document.location.href = @crossOriginRedirect() or url.absolute
|
136
|
+
|
137
|
+
onProgress: (event) =>
|
138
|
+
@progressBar.advanceFromEvent(event)
|
139
|
+
|
140
|
+
onError: (url) =>
|
141
|
+
document.location.href = url.absolute
|
142
|
+
|
143
|
+
createRequest: (url, opts)=>
|
144
|
+
jsAccept = 'text/javascript, application/x-javascript, application/javascript'
|
145
|
+
requestMethod = opts.requestMethod || 'GET'
|
146
|
+
|
147
|
+
xhr = new XMLHttpRequest
|
148
|
+
xhr.open requestMethod, url.formatForXHR(cache: opts.cacheRequest), true
|
149
|
+
xhr.setRequestHeader 'Accept', jsAccept
|
150
|
+
xhr.setRequestHeader 'X-XHR-Referer', document.location.href
|
151
|
+
xhr.setRequestHeader 'X-Silent', opts.silent if opts.silent
|
152
|
+
xhr.setRequestHeader 'X-Requested-With', 'XMLHttpRequest'
|
153
|
+
xhr.setRequestHeader 'Content-Type', opts.contentType if opts.contentType
|
154
|
+
|
155
|
+
csrfToken = Breezy.CSRFToken.get().token
|
156
|
+
xhr.setRequestHeader('X-CSRF-Token', csrfToken) if csrfToken
|
157
|
+
|
158
|
+
if !opts.silent
|
159
|
+
xhr.onload = =>
|
160
|
+
self = ` this `
|
161
|
+
redirectedUrl = self.getResponseHeader 'X-XHR-Redirected-To'
|
162
|
+
actualUrl = redirectedUrl || url
|
163
|
+
@onLoad(self, actualUrl, opts)
|
164
|
+
else
|
165
|
+
xhr.onload = =>
|
166
|
+
@progressBar?.done()
|
167
|
+
|
168
|
+
xhr.onprogress = @onProgress if @progressBar and opts.showProgressBar
|
169
|
+
xhr.onloadend = @onLoadEnd
|
170
|
+
xhr.onerror = =>
|
171
|
+
@onError(url)
|
172
|
+
xhr
|
173
|
+
|
174
|
+
processResponse: (xhr) ->
|
175
|
+
if @hasValidResponse(xhr)
|
176
|
+
return @responseContent(xhr)
|
177
|
+
|
178
|
+
hasValidResponse: (xhr) ->
|
179
|
+
not @clientOrServerError(xhr) and @validContent(xhr) and not @downloadingFile(xhr)
|
180
|
+
|
181
|
+
responseContent: (xhr) ->
|
182
|
+
new Function("'use strict'; return " + xhr.responseText )()
|
183
|
+
|
184
|
+
clientOrServerError: (xhr) ->
|
185
|
+
400 <= xhr.status < 600
|
186
|
+
|
187
|
+
validContent: (xhr) ->
|
188
|
+
contentType = xhr.getResponseHeader('Content-Type')
|
189
|
+
jsContent = /^(?:text\/javascript|application\/x-javascript|application\/javascript)(?:;|$)/
|
190
|
+
|
191
|
+
contentType? and contentType.match jsContent
|
192
|
+
|
193
|
+
downloadingFile: (xhr) ->
|
194
|
+
(disposition = xhr.getResponseHeader('Content-Disposition'))? and
|
195
|
+
disposition.match /^attachment/
|
196
|
+
|
197
|
+
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class Breezy.CSRFToken
|
2
|
+
@get: (doc = document) ->
|
3
|
+
node: tag = doc.querySelector 'meta[name="csrf-token"]'
|
4
|
+
token: tag?.getAttribute? 'content'
|
5
|
+
|
6
|
+
@update: (latest) ->
|
7
|
+
current = @get()
|
8
|
+
if current.token? and latest? and current.token isnt latest
|
9
|
+
current.node.setAttribute 'content', latest
|
@@ -0,0 +1,57 @@
|
|
1
|
+
class Breezy.DoublyLinkedList
|
2
|
+
constructor: ->
|
3
|
+
@head = @tail = null
|
4
|
+
@length = 0
|
5
|
+
|
6
|
+
createNode: (obj) ->
|
7
|
+
return {prev: null, element: obj, next: null}
|
8
|
+
|
9
|
+
push: (obj) ->
|
10
|
+
if (@tail)
|
11
|
+
ele = @createNode(obj)
|
12
|
+
ele.prev = @tail
|
13
|
+
@tail = @tail.next = ele
|
14
|
+
@length += 1
|
15
|
+
else
|
16
|
+
@head = @tail = @createNode(obj)
|
17
|
+
@length += 1
|
18
|
+
|
19
|
+
pop: ()->
|
20
|
+
if (@tail)
|
21
|
+
element = @tail
|
22
|
+
@tail = element.prev
|
23
|
+
element.prev = null
|
24
|
+
if (@tail)
|
25
|
+
@tail.next = null
|
26
|
+
if (@head == element)
|
27
|
+
@head = null
|
28
|
+
@length -= 1
|
29
|
+
|
30
|
+
element.element
|
31
|
+
else
|
32
|
+
null
|
33
|
+
|
34
|
+
shift: ()->
|
35
|
+
if (@head)
|
36
|
+
element = @head
|
37
|
+
@head = element.next
|
38
|
+
element.next = null
|
39
|
+
if (@head)
|
40
|
+
@head.prev = null
|
41
|
+
if (@tail == element)
|
42
|
+
@tail = null
|
43
|
+
@length -= 1
|
44
|
+
|
45
|
+
element.element
|
46
|
+
else
|
47
|
+
null
|
48
|
+
|
49
|
+
unshift: (obj)->
|
50
|
+
if (@head)
|
51
|
+
ele = @createNode(obj)
|
52
|
+
ele.next = @head
|
53
|
+
@head = @head.prev = ele
|
54
|
+
@length += 1
|
55
|
+
else
|
56
|
+
@head = @tail = @createNode(obj)
|
57
|
+
@length += 1
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#= require breezy/doubly_linked_list
|
2
|
+
|
3
|
+
class Breezy.ParallelQueue
|
4
|
+
constructor: ->
|
5
|
+
@dll = new Breezy.DoublyLinkedList
|
6
|
+
@active = true
|
7
|
+
|
8
|
+
push:(xhr)->
|
9
|
+
@dll.push(xhr)
|
10
|
+
xhr._originalOnLoad = xhr.onload.bind(xhr)
|
11
|
+
|
12
|
+
xhr.onload = =>
|
13
|
+
if @active
|
14
|
+
xhr._isDone = true
|
15
|
+
node = @dll.head
|
16
|
+
while(node)
|
17
|
+
qxhr = node.element
|
18
|
+
if !qxhr._isDone
|
19
|
+
node = null
|
20
|
+
else
|
21
|
+
node = node.next
|
22
|
+
@dll.shift()
|
23
|
+
qxhr._originalOnLoad()
|
24
|
+
|
25
|
+
drain: ->
|
26
|
+
@active = false
|
27
|
+
node = @dll.head
|
28
|
+
while(node)
|
29
|
+
qxhr = node.element
|
30
|
+
qxhr.abort()
|
31
|
+
qxhr._isDone = true
|
32
|
+
node = node.next
|
33
|
+
@dll = new Breezy.DoublyLinkedList
|
34
|
+
@active = true
|
35
|
+
|
@@ -0,0 +1,139 @@
|
|
1
|
+
class Breezy.ProgressBar
|
2
|
+
className = 'breezy-progress-bar'
|
3
|
+
# Setting the opacity to a value < 1 fixes a display issue in Safari 6 and
|
4
|
+
# iOS 6 where the progress bar would fill the entire page.
|
5
|
+
originalOpacity = 0.99
|
6
|
+
|
7
|
+
constructor: (@elementSelector) ->
|
8
|
+
@value = 0
|
9
|
+
@content = ''
|
10
|
+
@speed = 300
|
11
|
+
@opacity = originalOpacity
|
12
|
+
@delay = 400
|
13
|
+
@active = null
|
14
|
+
@install()
|
15
|
+
|
16
|
+
install: ->
|
17
|
+
if @active
|
18
|
+
return
|
19
|
+
|
20
|
+
@active = true
|
21
|
+
@element = document.querySelector(@elementSelector)
|
22
|
+
@element.classList.add(className)
|
23
|
+
@styleElement = document.createElement('style')
|
24
|
+
document.head.appendChild(@styleElement)
|
25
|
+
@_updateStyle()
|
26
|
+
|
27
|
+
uninstall: ->
|
28
|
+
if !@active
|
29
|
+
return
|
30
|
+
|
31
|
+
@active = false
|
32
|
+
@element.classList.remove(className)
|
33
|
+
document.head.removeChild(@styleElement)
|
34
|
+
|
35
|
+
start: ({delay} = {})->
|
36
|
+
clearTimeout(@displayTimeout)
|
37
|
+
if @delay
|
38
|
+
@display = false
|
39
|
+
@displayTimeout = setTimeout =>
|
40
|
+
@display = true
|
41
|
+
, @delay
|
42
|
+
else
|
43
|
+
@display = true
|
44
|
+
|
45
|
+
if @value > 0
|
46
|
+
@_reset()
|
47
|
+
@_reflow()
|
48
|
+
|
49
|
+
@advanceTo(5)
|
50
|
+
|
51
|
+
advanceTo: (value) ->
|
52
|
+
if value > @value <= 100
|
53
|
+
@value = value
|
54
|
+
@_updateStyle()
|
55
|
+
|
56
|
+
if @value is 100
|
57
|
+
@_stopTrickle()
|
58
|
+
else if @value > 0
|
59
|
+
@_startTrickle()
|
60
|
+
|
61
|
+
advanceFromEvent: (event) =>
|
62
|
+
percent = if event.lengthComputable
|
63
|
+
event.loaded / event.total * 100
|
64
|
+
else
|
65
|
+
@value + (100 - @value) / 10
|
66
|
+
@advanceTo(percent)
|
67
|
+
|
68
|
+
done: ->
|
69
|
+
if @value > 0
|
70
|
+
@advanceTo(100)
|
71
|
+
@_finish()
|
72
|
+
|
73
|
+
setDelay: (milliseconds) =>
|
74
|
+
@delay = milliseconds
|
75
|
+
|
76
|
+
_finish: ->
|
77
|
+
@fadeTimer = setTimeout =>
|
78
|
+
@opacity = 0
|
79
|
+
@_updateStyle()
|
80
|
+
, @speed / 2
|
81
|
+
|
82
|
+
@resetTimer = setTimeout(@_reset, @speed)
|
83
|
+
|
84
|
+
_reflow: ->
|
85
|
+
@element.offsetHeight
|
86
|
+
|
87
|
+
_reset: =>
|
88
|
+
@_stopTimers()
|
89
|
+
@value = 0
|
90
|
+
@opacity = originalOpacity
|
91
|
+
@_withSpeed(0, => @_updateStyle(true))
|
92
|
+
|
93
|
+
_stopTimers: ->
|
94
|
+
@_stopTrickle()
|
95
|
+
clearTimeout(@fadeTimer)
|
96
|
+
clearTimeout(@resetTimer)
|
97
|
+
|
98
|
+
_startTrickle: ->
|
99
|
+
return if @trickleTimer
|
100
|
+
@trickleTimer = setTimeout(@_trickle, @speed)
|
101
|
+
|
102
|
+
_stopTrickle: ->
|
103
|
+
clearTimeout(@trickleTimer)
|
104
|
+
delete @trickleTimer
|
105
|
+
|
106
|
+
_trickle: =>
|
107
|
+
@advanceTo(@value + Math.random() / 2)
|
108
|
+
@trickleTimer = setTimeout(@_trickle, @speed)
|
109
|
+
|
110
|
+
_withSpeed: (speed, fn) ->
|
111
|
+
originalSpeed = @speed
|
112
|
+
@speed = speed
|
113
|
+
result = fn()
|
114
|
+
@speed = originalSpeed
|
115
|
+
result
|
116
|
+
|
117
|
+
_updateStyle: (forceRepaint = false) ->
|
118
|
+
@_changeContentToForceRepaint() if forceRepaint
|
119
|
+
@styleElement.textContent = @_createCSSRule()
|
120
|
+
|
121
|
+
_changeContentToForceRepaint: ->
|
122
|
+
@content = if @content is '' then ' ' else ''
|
123
|
+
|
124
|
+
_createCSSRule: ->
|
125
|
+
"""
|
126
|
+
#{@elementSelector}.#{className}::before {
|
127
|
+
content: '#{@content}';
|
128
|
+
position: fixed;
|
129
|
+
top: 0;
|
130
|
+
left: 0;
|
131
|
+
z-index: 2000;
|
132
|
+
background-color: #0076ff;
|
133
|
+
height: 3px;
|
134
|
+
opacity: #{@opacity};
|
135
|
+
width: #{if @display then @value else 0}%;
|
136
|
+
transition: width #{@speed}ms ease-out, opacity #{@speed / 2}ms ease-in;
|
137
|
+
transform: translate3d(0,0,0);
|
138
|
+
}
|
139
|
+
"""
|