breezy 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/lib/assets/javascript/breezy.js +6067 -0
  3. data/lib/breezy.rb +0 -7
  4. data/lib/breezy/configuration.rb +9 -3
  5. data/lib/breezy/helpers.rb +1 -1
  6. data/lib/breezy/render.rb +1 -1
  7. data/lib/breezy/version.rb +1 -1
  8. data/lib/generators/breezy/view/templates/view.js +17 -0
  9. data/lib/generators/breezy/view/templates/view.js.breezy +2 -0
  10. data/lib/generators/breezy/view/templates/view.jsx +21 -0
  11. data/lib/generators/breezy/view/view_generator.rb +40 -7
  12. data/lib/install/mobile.rb +54 -0
  13. data/lib/install/templates/mobile/app.js +84 -0
  14. data/lib/install/templates/mobile/app.json +6 -0
  15. data/lib/install/templates/mobile/package.json +32 -0
  16. data/lib/install/templates/mobile/rn-cli.config.js +4 -0
  17. data/lib/install/templates/web/application.js +62 -0
  18. data/lib/install/web.rb +72 -0
  19. data/lib/tasks/install.rake +46 -0
  20. data/test/render_test.rb +2 -2
  21. data/test/test_helper.rb +2 -0
  22. metadata +37 -48
  23. data/README.md +0 -338
  24. data/lib/assets/javascripts/breezy.coffee +0 -4
  25. data/lib/assets/javascripts/breezy/component_url.coffee +0 -61
  26. data/lib/assets/javascripts/breezy/controller.coffee +0 -197
  27. data/lib/assets/javascripts/breezy/csrf_token.coffee +0 -9
  28. data/lib/assets/javascripts/breezy/doubly_linked_list.coffee +0 -57
  29. data/lib/assets/javascripts/breezy/parallel_queue.coffee +0 -35
  30. data/lib/assets/javascripts/breezy/progress_bar.coffee +0 -139
  31. data/lib/assets/javascripts/breezy/remote.coffee +0 -136
  32. data/lib/assets/javascripts/breezy/snapshot.coffee +0 -100
  33. data/lib/assets/javascripts/breezy/start.coffee +0 -60
  34. data/lib/assets/javascripts/breezy/utils.coffee +0 -174
  35. data/lib/breezy/active_support.rb +0 -21
  36. data/lib/breezy_template.rb +0 -320
  37. data/lib/breezy_template/deferment_extension.rb +0 -48
  38. data/lib/breezy_template/dependency_tracker.rb +0 -47
  39. data/lib/breezy_template/digestor.rb +0 -30
  40. data/lib/breezy_template/handler.rb +0 -43
  41. data/lib/breezy_template/partial_extension.rb +0 -87
  42. data/lib/breezy_template/search_extension.rb +0 -108
  43. data/lib/generators/breezy/install/install_generator.rb +0 -61
  44. data/lib/generators/breezy/install/templates/Default.js.jsx +0 -7
  45. data/lib/generators/breezy/install/templates/View.js.jsx +0 -7
  46. data/lib/generators/breezy/install/templates/boot.js +0 -5
  47. data/lib/generators/breezy/view/templates/view.js.jsx +0 -8
  48. data/test/blade_helper.rb +0 -22
  49. data/test/breezy_template_test.rb +0 -1095
  50. data/test/dependency_tracker_test.rb +0 -66
@@ -1,136 +0,0 @@
1
- class Breezy.Remote
2
- SUPPORTED_METHODS = ['GET', 'PUT', 'POST', 'DELETE', 'PATCH']
3
- FALLBACK_LINK_METHOD = 'GET'
4
- FALLBACK_FORM_METHOD = 'POST'
5
-
6
- constructor: (target, opts={})->
7
- @target = target
8
- @payload = ''
9
- @contentType = null
10
- @setRequestType(target)
11
- @async = @getBZAttribute(target, 'bz-remote-async') || false
12
- @pushState = !(@getBZAttribute(target, 'bz-push-state') == 'false')
13
- @httpUrl = target.getAttribute('href') || target.getAttribute('action')
14
- @silent = @getBZAttribute(target, 'bz-silent') || false
15
- @setPayload(target)
16
-
17
- toOptions: =>
18
- requestMethod: @actualRequestType
19
- payload: @payload
20
- contentType: @contentType
21
- silent: @silent
22
- target: @target
23
- async: @async
24
- pushState: @pushState
25
-
26
- setRequestType: (target)=>
27
- if target.tagName == 'A'
28
- @httpRequestType = @getBZAttribute(target, 'bz-remote')
29
- @httpRequestType ?= ''
30
- @httpRequestType = @httpRequestType.toUpperCase()
31
-
32
- if @httpRequestType not in SUPPORTED_METHODS
33
- @httpRequestType = FALLBACK_LINK_METHOD
34
-
35
- if target.tagName == 'FORM'
36
- formActionMethod = target.getAttribute('method')
37
- @httpRequestType = formActionMethod || @getBZAttribute(target, 'bz-remote')
38
- @httpRequestType ?= ''
39
- @httpRequestType = @httpRequestType.toUpperCase()
40
-
41
- if @httpRequestType not in SUPPORTED_METHODS
42
- @httpRequestType = FALLBACK_FORM_METHOD
43
-
44
- @actualRequestType = if @httpRequestType == 'GET' then 'GET' else 'POST'
45
-
46
- setPayload: (target)=>
47
- if target.tagName == 'FORM'
48
- @payload = @nativeEncodeForm(target)
49
-
50
- if @payload not instanceof FormData
51
- if @payload.indexOf("_method") == -1 && @httpRequestType && @actualRequestType != 'GET'
52
- @contentType = "application/x-www-form-urlencoded; charset=UTF-8"
53
- @payload = @formAppend(@payload, "_method", @httpRequestType)
54
- else
55
- if !target.querySelector('[name=_method]') && @httpRequestType not in ['GET', 'POST']
56
- @payload.append("_method", @httpRequestType)
57
-
58
- isValid: =>
59
- @isValidLink() || @isValidForm()
60
-
61
- isValidLink: =>
62
- if @target.tagName != 'A'
63
- return false
64
-
65
- @hasBZAttribute(@target, 'bz-remote')
66
-
67
- isValidForm: =>
68
- if @target.tagName != 'FORM'
69
- return false
70
- @hasBZAttribute(@target, 'bz-remote') &&
71
- @target.getAttribute('action')?
72
-
73
- formAppend: (uriEncoded, key, value) ->
74
- uriEncoded += "&" if uriEncoded.length
75
- uriEncoded += "#{encodeURIComponent(key)}=#{encodeURIComponent(value)}"
76
-
77
- formDataAppend: (formData, input) ->
78
- if input.type == 'file'
79
- for file in input.files
80
- formData.append(input.name, file)
81
- else
82
- formData.append(input.name, input.value)
83
- formData
84
-
85
- nativeEncodeForm: (form) ->
86
- formData = new FormData
87
- @iterateOverFormInputs form, (input) =>
88
- formData = @formDataAppend(formData, input)
89
- formData
90
-
91
- iterateOverFormInputs: (form, callback) ->
92
- inputs = @enabledInputs(form)
93
- for input in inputs
94
- inputEnabled = !input.disabled
95
- radioOrCheck = (input.type == 'checkbox' || input.type == 'radio')
96
-
97
- if inputEnabled && input.name
98
- if (radioOrCheck && input.checked) || !radioOrCheck
99
- callback(input)
100
-
101
- enabledInputs: (form) ->
102
- selector = "input:not([type='reset']):not([type='button']):not([type='submit']):not([type='image']), select, textarea"
103
- inputs = Array::slice.call(form.querySelectorAll(selector))
104
- disabledNodes = Array::slice.call(@querySelectorAllBZAttribute(form, 'bz-remote-noserialize'))
105
-
106
- return inputs unless disabledNodes.length
107
-
108
- disabledInputs = disabledNodes
109
- for node in disabledNodes
110
- disabledInputs = disabledInputs.concat(Array::slice.call(node.querySelectorAll(selector)))
111
-
112
- enabledInputs = []
113
- for input in inputs when disabledInputs.indexOf(input) < 0
114
- enabledInputs.push(input)
115
- enabledInputs
116
-
117
- bzAttribute: (attr) ->
118
- bzAttr = if attr[0...3] == 'bz-'
119
- "data-#{attr}"
120
- else
121
- "data-bz-#{attr}"
122
-
123
- getBZAttribute: (node, attr) ->
124
- bzAttr = @bzAttribute(attr)
125
- (node.getAttribute(bzAttr) || node.getAttribute(attr))
126
-
127
- querySelectorAllBZAttribute: (node, attr, value = null) ->
128
- bzAttr = @bzAttribute(attr)
129
- if value
130
- node.querySelectorAll("[#{bzAttr}=#{value}], [#{attr}=#{value}]")
131
- else
132
- node.querySelectorAll("[#{bzAttr}], [#{attr}]")
133
-
134
- hasBZAttribute: (node, attr) ->
135
- bzAttr = @bzAttribute(attr)
136
- node.getAttribute(bzAttr)? || node.getAttribute(attr)?
@@ -1,100 +0,0 @@
1
- #= require breezy/component_url
2
- #= require breezy/csrf_token
3
- #= require breezy/utils
4
-
5
- class Breezy.Snapshot
6
- constructor: (@controller) ->
7
- @pageCache = {}
8
- @currentBrowserState = null
9
- @pageCacheSize = 10
10
- @currentPage = null
11
- @loadedAssets= null
12
-
13
- onHistoryChange: (event) =>
14
- if event.state?.breezy && event.state.url != @currentBrowserState.url
15
- previousUrl = new Breezy.ComponentUrl(@currentBrowserState.url)
16
- newUrl = new Breezy.ComponentUrl(event.state.url)
17
-
18
- if restorePoint = @pageCache[newUrl.absolute]
19
- @cacheCurrentPage()
20
- @currentPage = restorePoint
21
- @controller.restore(@currentPage)
22
- else
23
- @controller.request event.target.location.href
24
-
25
- constrainPageCacheTo: (limit = @pageCacheSize) =>
26
- pageCacheKeys = Object.keys @pageCache
27
-
28
- cacheTimesRecentFirst = pageCacheKeys.map (url) =>
29
- @pageCache[url].cachedAt
30
- .sort (a, b) -> b - a
31
-
32
- for key in pageCacheKeys when @pageCache[key].cachedAt <= cacheTimesRecentFirst[limit]
33
- delete @pageCache[key]
34
-
35
- transitionCacheFor: (url) =>
36
- return if url is @currentBrowserState.url
37
- cachedPage = @pageCache[url]
38
- cachedPage if cachedPage and !cachedPage.transitionCacheDisabled
39
-
40
- pagesCached: (size = @pageCacheSize) =>
41
- @pageCacheSize = parseInt(size) if /^[\d]+$/.test size
42
-
43
- cacheCurrentPage: =>
44
- return unless @currentPage
45
- currentUrl = new Breezy.ComponentUrl @currentBrowserState.url
46
-
47
- Breezy.Utils.merge @currentPage,
48
- cachedAt: new Date().getTime()
49
- positionY: window.pageYOffset
50
- positionX: window.pageXOffset
51
- url: currentUrl.relative
52
- pathname: currentUrl.pathname
53
- transition_cache: true
54
-
55
- @pageCache[currentUrl.absolute] = @currentPage
56
-
57
- rememberCurrentUrlAndState: =>
58
- window.history.replaceState { breezy: true, url: document.location.href }, '', document.location.href
59
- @currentBrowserState = window.history.state
60
-
61
- removeParamFromUrl: (url, parameter) =>
62
- return url
63
- .replace(new RegExp('^([^#]*\?)(([^#]*)&)?' + parameter + '(\=[^&#]*)?(&|#|$)' ), '$1$3$5')
64
- .replace(/^([^#]*)((\?)&|\?(#|$))/,'$1$3$4')
65
-
66
- reflectNewUrl: (url) =>
67
- if (url = new Breezy.ComponentUrl url).absolute != document.location.href
68
- preservedHash = if url.hasNoHash() then document.location.hash else ''
69
- fullUrl = url.absolute + preservedHash
70
- fullUrl = @removeParamFromUrl(fullUrl, '_breezy_filter')
71
- fullUrl = @removeParamFromUrl(fullUrl, '__')
72
-
73
- window.history.pushState { breezy: true, url: url.absolute + preservedHash }, '', fullUrl
74
-
75
- updateCurrentBrowserState: =>
76
- @currentBrowserState = window.history.state
77
-
78
- changePage: (nextPage, options) =>
79
- if @currentPage and @assetsChanged(nextPage)
80
- document.location.reload()
81
- return
82
-
83
- @currentPage = nextPage
84
- @currentPage.title = options.title ? @currentPage.title
85
- document.title = @currentPage.title if @currentPage.title isnt false
86
-
87
- Breezy.CSRFToken.update @currentPage.csrf_token if @currentPage.csrf_token?
88
- @updateCurrentBrowserState()
89
-
90
- assetsChanged: (nextPage) =>
91
- @loadedAssets ||= @currentPage.assets
92
- fetchedAssets = nextPage.assets
93
- fetchedAssets.length isnt @loadedAssets.length or Breezy.Utils.intersection(fetchedAssets, @loadedAssets).length isnt @loadedAssets.length
94
-
95
- graftByKeypath: (keypath, node, opts={})=>
96
- for k, v in @pageCache
97
- @history.pageCache[k] = Breezy.Utils.graftByKeypath(keypath, node, v, opts)
98
-
99
- @currentPage = Breezy.Utils.graftByKeypath(keypath, node, @currentPage, opts)
100
- Breezy.Utils.triggerEvent Breezy.EVENTS.LOAD, @currentPage
@@ -1,60 +0,0 @@
1
- #= require breezy/controller
2
- #= require breezy/remote
3
- #= require breezy/utils
4
-
5
- EVENTS =
6
- BEFORE_CHANGE: 'breezy:click'
7
- ERROR: 'breezy:request-error'
8
- FETCH: 'breezy:request-start'
9
- RECEIVE: 'breezy:request-end'
10
- LOAD: 'breezy:load'
11
- RESTORE: 'breezy:restore'
12
-
13
- controller = new Breezy.Controller
14
- progressBar = controller.progressBar
15
-
16
- ProgressBarAPI =
17
- enable: ->
18
- progressBar.install()
19
- disable: ->
20
- progressBar.uninstall()
21
- setDelay: (value) -> progressBar.setDelay(value)
22
- start: (options) -> progressBar.start(options)
23
- advanceTo: (value) -> progressBar.advanceTo(value)
24
- done: -> progressBar.done()
25
-
26
- remoteHandler = (ev) ->
27
- target = ev.target
28
- remote = new Breezy.Remote(target)
29
- return unless remote.isValid()
30
- ev.preventDefault()
31
- controller.request remote.httpUrl, remote.toOptions()
32
-
33
- browserSupportsCustomEvents =
34
- document.addEventListener and document.createEvent
35
-
36
- initializeBreezy = ->
37
- ProgressBarAPI.enable()
38
- window.addEventListener 'hashchange', controller.history.rememberCurrentUrlAndState, false
39
- window.addEventListener 'popstate', controller.history.onHistoryChange, false
40
- Breezy.Utils.documentListenerForLinks 'click', remoteHandler
41
- document.addEventListener "submit", remoteHandler
42
-
43
- if Breezy.Utils.browserSupportsBreezy()
44
- visit = controller.request
45
- initializeBreezy()
46
- else
47
- visit = (url = document.location.href) -> document.location.href = url
48
-
49
- Breezy.controller = controller
50
- Breezy.graftByKeypath = controller.history.graftByKeypath
51
- Breezy.visit = visit
52
- Breezy.replace = controller.replace
53
- Breezy.cache = controller.cache
54
- Breezy.pagesCached = controller.history.pagesCached
55
- Breezy.enableTransitionCache = controller.enableTransitionCache
56
- Breezy.disableRequestCaching = controller.disableRequestCaching
57
- Breezy.ProgressBar = ProgressBarAPI
58
- Breezy.supported = Breezy.Utils.browserSupportsBreezy()
59
- Breezy.EVENTS = Breezy.Utils.clone(EVENTS)
60
- Breezy.currentPage = controller.currentPage
@@ -1,174 +0,0 @@
1
- reverseMerge = (dest, obj) ->
2
- for k, v of obj
3
- dest[k] = v if !dest.hasOwnProperty(k)
4
- dest
5
-
6
- merge = (dest, obj) ->
7
- for k, v of obj
8
- dest[k] = v
9
- dest
10
-
11
- clone = (original) ->
12
- return original if not original? or typeof original isnt 'object'
13
- copy = new original.constructor()
14
- copy[key] = clone value for key, value of original
15
- copy
16
-
17
- withDefaults = (page, state) =>
18
- currentUrl = new Breezy.ComponentUrl state.url
19
-
20
- reverseMerge page,
21
- url: currentUrl.relative
22
- pathname: currentUrl.pathname
23
- cachedAt: new Date().getTime()
24
- assets: []
25
- data: {}
26
- title: ''
27
- positionY: 0
28
- positionX: 0
29
- csrf_token: null
30
-
31
- browserIsBuggy = () ->
32
- # Copied from https://github.com/Modernizr/Modernizr/blob/master/feature-detects/history.js
33
- ua = navigator.userAgent
34
- (ua.indexOf('Android 2.') != -1 or ua.indexOf('Android 4.0') != -1) and
35
- ua.indexOf('Mobile Safari') != -1 and
36
- ua.indexOf('Chrome') == -1 and
37
- ua.indexOf('Windows Phone') == -1
38
-
39
- browserSupportsPushState = () ->
40
- window.history and 'pushState' of window.history and 'state' of window.history
41
-
42
- popCookie = (name) ->
43
- value = document.cookie.match(new RegExp(name+"=(\\w+)"))?[1].toUpperCase() or ''
44
- document.cookie = name + '=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/'
45
- value
46
-
47
- requestMethodIsSafe = -> popCookie('request_method') in ['GET','']
48
-
49
- browserSupportsBreezy = ->
50
- browserSupportsPushState() and !browserIsBuggy() and requestMethodIsSafe()
51
-
52
- intersection = (a, b) ->
53
- [a, b] = [b, a] if a.length > b.length
54
- value for value in a when value in b
55
-
56
-
57
- triggerEvent = (name, data, target = document) =>
58
- event = document.createEvent 'Events'
59
- event.data = data if data
60
- event.initEvent name, true, true
61
- target.dispatchEvent event
62
-
63
- documentListenerForLinks = (eventType, handler) ->
64
- document.addEventListener eventType, (ev) ->
65
- target = ev.target
66
- while target != document && target?
67
- if target.nodeName == "A"
68
- isNodeDisabled = target.getAttribute('disabled')
69
- ev.preventDefault() if target.getAttribute('disabled')
70
- unless isNodeDisabled
71
- handler(ev)
72
- return
73
-
74
- target = target.parentNode
75
-
76
- isObject = (val) ->
77
- Object.prototype.toString.call(val) is '[object Object]'
78
-
79
- isArray = (val) ->
80
- Object.prototype.toString.call(val) is '[object Array]'
81
-
82
- class Breezy.Grafter
83
- constructor: ->
84
- @current_path = []
85
-
86
- graftByKeypath: (path, leaf, obj, opts={}) ->
87
- if typeof path is "string"
88
- path = path.split('.')
89
- return @graftByKeypath(path, leaf, obj, opts)
90
-
91
- head = path[0]
92
- @current_path.push(head)
93
- child = obj[head] if obj?
94
- remaining = path.slice(1)
95
-
96
- if path.length is 0
97
- if opts.type == 'add' and isArray(obj)
98
- copy = []
99
- for child in obj
100
- copy.push child
101
-
102
- copy.push leaf
103
- return copy
104
- else
105
- return leaf
106
-
107
- if isObject(obj)
108
- copy = {}
109
- found = false
110
- for key, value of obj
111
- if key is head
112
- node = @graftByKeypath(remaining, leaf, child, opts)
113
- found = true unless child is node
114
- copy[key] = node
115
- else
116
- copy[key] = value
117
-
118
- return if found
119
- @current_path.pop()
120
- copy
121
- else
122
- Breezy.Utils.warn "Could not find key #{head} in keypath #{@current_path.join('.')}"
123
- obj
124
-
125
- else if isArray(obj)
126
- [attr, id] = head.split('=')
127
- found = false
128
- if id == undefined
129
- index = parseInt(attr)
130
- child = obj[index]
131
- node = @graftByKeypath(remaining, leaf, child, opts)
132
- found = true unless child is node
133
-
134
- copy = obj.slice(0, index)
135
- copy.push(node)
136
- copy = copy.concat(obj.slice(index + 1, obj.length))
137
- else
138
- id = parseInt(id) || 0
139
- copy = []
140
- for child in obj
141
- if child[attr] == id
142
- node = @graftByKeypath(remaining, leaf, child, opts)
143
- found = true unless child is node
144
- copy.push node
145
- else
146
- copy.push child
147
-
148
- return if found
149
- @current_path.pop()
150
- copy
151
- else
152
- Breezy.Utils.warn "Could not find key #{head} in keypath #{@current_path.join('.')}"
153
- obj
154
- else
155
- obj
156
-
157
-
158
-
159
- @Breezy.Utils =
160
- warn: ->
161
- console.warn.apply(@, arguments)
162
- graftByKeypath: ->
163
- grafter = new Breezy.Grafter
164
- grafter.graftByKeypath.apply(grafter, arguments)
165
- documentListenerForLinks: documentListenerForLinks
166
- reverseMerge: reverseMerge
167
- merge: merge
168
- clone: clone
169
- withDefaults: withDefaults
170
- browserSupportsBreezy: browserSupportsBreezy
171
- intersection: intersection
172
- triggerEvent: triggerEvent
173
-
174
-