pwnstyles_rails 0.1.8 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.8
1
+ 0.1.9
@@ -18,7 +18,7 @@ class PwnFxClass
18
18
 
19
19
  # Wires JS to elements with data-pwnfx attributes.
20
20
  #
21
- # @param [Element] root the element whose content is wired; use document at
21
+ # @param {Element} root the element whose content is wired; use document at
22
22
  # load time
23
23
  wire: (root) ->
24
24
  for effect in @effects
@@ -38,19 +38,19 @@ class PwnFxClass
38
38
 
39
39
  # Registers a PwnFx effect.
40
40
  #
41
- # @param [String] attrName string following data-pwnfx- in the effect's
41
+ # @param {String} attrName string following data-pwnfx- in the effect's
42
42
  # attribute names
43
43
  # @param klass the class that wraps the effect's implementation
44
44
  registerEffect: (attrPrefix, klass) ->
45
45
  if @effectsByName[attrPrefix]
46
- throw new Error("Effect name {attrPrefix} already registered")
46
+ throw new Error("PwnFx effect name {attrPrefix} already registered")
47
47
  @effects.push [attrPrefix, klass]
48
48
 
49
49
  # Finds a scoping container.
50
50
  #
51
- # @param [String] scopeId the scope ID to look for
52
- # @param [Element] element the element where the lookup starts
53
- # @return [Element] the closest parent of the given element whose
51
+ # @param {String} scopeId the scope ID to look for
52
+ # @param {HTMLElement} element the element where the lookup starts
53
+ # @return {HTMLElement} the closest parent of the given element whose
54
54
  # data-pwnfx-scope matches the scopeId argument; window.document is
55
55
  # returned if no such element exists or if scope is null
56
56
  resolveScope: (scopeId, element) ->
@@ -61,9 +61,9 @@ class PwnFxClass
61
61
 
62
62
  # Performs a scoped querySelectAll.
63
63
  #
64
- # @param [Element] scope the DOM element serving as the search scope
65
- # @param [String] selector the CSS selector to query
66
- # @return [NodeList, Array] the elements in the scope that match the CSS
64
+ # @param {HTMLElement} scope the DOM element serving as the search scope
65
+ # @param {String} selector the CSS selector to query
66
+ # @return {NodeList, Array} the elements in the scope that match the CSS
67
67
  # selector; the scope container can belong to the returned array
68
68
  queryScope: (scope, selector) ->
69
69
  scopeMatches = false
@@ -85,6 +85,64 @@ class PwnFxClass
85
85
  else
86
86
  scope.querySelectorAll selector
87
87
 
88
+ # Executes the JavaScript inside the <script> tags in a DOM subtree.
89
+ #
90
+ # @param {HTMLElement} element the DOM element rooting the subtree that will
91
+ # be searched for <script> tags
92
+ runScripts: (element) ->
93
+ # HACK: <script>s are removed and re-inserted so the browser runs them
94
+ for scriptElement in element.querySelectorAll('script')
95
+ parent = scriptElement.parentElement
96
+ nextSibling = scriptElement.nextSibling
97
+ parent.removeChild scriptElement
98
+ parent.insertBefore scriptElement.cloneNode(true), nextSibling
99
+ null
100
+
101
+ # Replaces an element's contents with some HTML.
102
+ #
103
+ # The JavaScript inside the HTML's <script> tags will be executed.
104
+ #
105
+ # @param {HTMLElement} element the element whose contents will be replaced
106
+ # @param {String}
107
+ replaceHtml: (element, html) ->
108
+ element.innerHTML = html
109
+ @runScripts element
110
+ @wire element
111
+
112
+ # The closest form element wrapping a node.
113
+ #
114
+ # @param {HTMLElement} element the element whose parent chain will be searched
115
+ # @return {HTMLFormElement} the element's closest parent form, or null if the
116
+ # element is not wrapped in a <form>
117
+ parentForm: (element) ->
118
+ while element
119
+ return element if element.nodeName == 'FORM'
120
+ element = element.parentNode
121
+ null
122
+
123
+ # Do AJAX.
124
+ #
125
+ # @param {String} url the request URL (e.g., "http://localhost/path/to.html")
126
+ # @param {String} method the request method (e.g., "POST")
127
+ # @param [HTMLFormElement] form the DOM form whose data will be submitted
128
+ # @param [function(data)] onData callback that receives the XHR data, if the
129
+ # XHR completes successfully
130
+ xhr: (url, method, form, onData) ->
131
+ xhr = new XMLHttpRequest
132
+ xhr.onload = @_xhr_onload
133
+ xhr.pwnfxOnData = onData
134
+ xhr.open method, url
135
+ xhr.setRequestHeader 'X-Requested-With', 'XMLHttpRequest'
136
+ if form
137
+ xhr.send new FormData(form)
138
+ else
139
+ xhr.send null
140
+
141
+ # Called when an XHR request issued by PwnFx.xhr works out.
142
+ _xhr_onload: ->
143
+ if @status < 200 || @status >= 300
144
+ throw new Error("XHR result ignored due to HTTP status: #{@statusText}")
145
+ @pwnfxOnData @responseText
88
146
 
89
147
  # Singleton instance.
90
148
  PwnFx = new PwnFxClass
@@ -96,11 +154,24 @@ PwnFx = new PwnFxClass
96
154
  # data-pwnfx-move: an identifier connecting the move's target element
97
155
  # data-pwnfx-move-target: set to the same value as data-pwnfx-move on the
98
156
  # element that will receive the moved element as its last child
157
+ # data-pwnfx-move-method: 'append' adds the moved as the element as the
158
+ # target's last child, 'replace' clears the target element, then adds the
159
+ # moved element as the target's only child
99
160
  class PwnFxMove
100
161
  constructor: (element, identifier, scopeId) ->
101
162
  scope = PwnFx.resolveScope scopeId, element
163
+ method = element.getAttribute('data-pwnfx-move-method') || 'append'
102
164
  target = document.querySelector "[data-pwnfx-move-target=\"#{identifier}\"]"
103
- target.appendChild element
165
+
166
+ switch method
167
+ when 'append'
168
+ target.appendChild element
169
+ when 'replace'
170
+ target.innerHTML = ''
171
+ target.appendChild element
172
+ else
173
+ throw new Error("pwnfx-move-method #{method} not implemented")
174
+
104
175
 
105
176
  PwnFx.registerEffect 'move', PwnFxMove
106
177
 
@@ -146,68 +217,85 @@ class PwnFxRender
146
217
  PwnFx.registerEffect 'render', PwnFxRender
147
218
 
148
219
 
220
+ # Loads some content after the main page load via an AJAX request.
221
+ #
222
+ # The text / HTML returned by the request is placed in another element. Scripts
223
+ # in <script> tags are executed.
224
+ #
225
+ # Element attributes:
226
+ # data-pwnfx-delayed: identifier connecting the AJAX data receiver
227
+ # data-pwnfx-delayed-url: URL to perform an AJAX request to
228
+ # data-pwnfx-delayed-method: the HTTP method of AJAX request (default: POST)
229
+ # data-pwnfx-delayed-ms: the delay between the page load and the issuing of
230
+ # the AJAX request (default: 1000ms)
231
+ # data-pwnfx-delayed-target: set to the value of data-pwnfx-delayed on the
232
+ # element populated with the AJAX response
233
+ class PwnFxDelayed
234
+ constructor: (element, identifier, scopeId) ->
235
+ targetSelector = "[data-pwnfx-delayed-target=\"#{identifier}\"]"
236
+ xhrUrl = element.getAttribute('data-pwnfx-delayed-url')
237
+ xhrMethod = element.getAttribute('data-pwnfx-delayed-method') || 'POST'
238
+ xhrForm = PwnFx.parentForm element
239
+ delay = parseInt(
240
+ element.getAttribute('data-pwnfx-delayed-ms') || '1000');
241
+
242
+ ajaxLoad = ->
243
+ PwnFx.xhr xhrUrl, xhrMethod, xhrForm, (data) ->
244
+ scope = PwnFx.resolveScope scopeId, element
245
+ for targetElement in PwnFx.queryScope(scope, targetSelector)
246
+ PwnFx.replaceHtml targetElement, data
247
+
248
+ window.setTimeout ajaxLoad, delay
249
+
250
+ PwnFx.registerEffect 'delayed', PwnFxDelayed
251
+
252
+
149
253
  # Fires off an AJAX request (almost) every time when an element changes.
150
254
  #
151
- # The text / HTML returned by the request is placed in another element.
255
+ # The text / HTML returned by the request is placed in another element. Scripts
256
+ # in <script> tags are executed.
152
257
  #
153
258
  # Element attributes:
154
- # data-pwnfx-refresh: URL to perform an AJAX request to
259
+ # data-pwnfx-refresh: identifier connecting the AJAX data receiver
260
+ # data-pwnfx-refresh-url: URL to perform an AJAX request to
155
261
  # data-pwnfx-refresh-method: the HTTP method of AJAX request (default: POST)
156
- # data-pwnfx-refresh-ms: interval between a change on the source element and
262
+ # data-pwnfx-refresh-ms: delay between a change on the source element and
157
263
  # AJAX refresh requests (default: 200ms)
158
- # data-pwnfx-target: the element populated with the AJAX response
264
+ # data-pwnfx-refresh-target: set to the value of data-pwnfx-refresh on the
265
+ # element populated with the AJAX response
159
266
  class PwnFxRefresh
160
- constructor: (element, xhrUrl, scopeId) ->
161
- targetSelector = '#' + element.getAttribute('data-pwnfx-refresh-target')
162
- refreshInterval = parseInt(
163
- element.getAttribute('data-pwnfx-refresh-ms') || '200');
267
+ constructor: (element, identifier, scopeId) ->
268
+ targetSelector = "[data-pwnfx-refresh-target=\"#{identifier}\"]"
269
+ xhrUrl = element.getAttribute('data-pwnfx-refresh-url')
164
270
  xhrMethod = element.getAttribute('data-pwnfx-refresh-method') || 'POST'
165
- xhrForm = @parentForm element
271
+ xhrForm = PwnFx.parentForm element
272
+ refreshDelay = parseInt(
273
+ element.getAttribute('data-pwnfx-refresh-ms') || '200');
166
274
 
167
- onXhrSuccess = ->
168
- data = @responseText
275
+ onXhrData = (data) ->
169
276
  scope = PwnFx.resolveScope scopeId, element
170
277
  for targetElement in PwnFx.queryScope(scope, targetSelector)
171
- targetElement.innerHTML = data
172
- # HACK: <script>s are removed and re-inserted so the browser runs them
173
- for scriptElement in targetElement.querySelectorAll('script')
174
- parent = scriptElement.parentElement
175
- nextSibling = scriptElement.nextSibling
176
- parent.removeChild scriptElement
177
- parent.insertBefore scriptElement.cloneNode(true), nextSibling
178
- PwnFx.wire targetElement
278
+ PwnFx.replaceHtml targetElement, data
179
279
 
180
- refreshPending = false
280
+ changeTimeout = null
181
281
  refreshOldValue = null
182
282
  ajaxRefresh = ->
183
- refreshPending = false
184
- xhr = new XMLHttpRequest
185
- xhr.onload = onXhrSuccess
186
- xhr.open xhrMethod, xhrUrl
187
- xhr.send new FormData(xhrForm)
283
+ changeTimeout = null
284
+ PwnFx.xhr xhrUrl, xhrMethod, xhrForm, onXhrData
188
285
 
189
286
  onChange = ->
190
287
  value = element.value
191
288
  return true if value == refreshOldValue
192
289
  refreshOldValue = value
193
290
 
194
- return true if refreshPending
195
- refreshPending = true
196
- window.setTimeout ajaxRefresh, refreshInterval
291
+ window.clearTimeout changeTimeout if changeTimeout != null
292
+ changeTimeout = window.setTimeout ajaxRefresh, refreshDelay
197
293
  true
198
294
 
199
295
  element.addEventListener 'change', onChange, false
200
296
  element.addEventListener 'keydown', onChange, false
201
297
  element.addEventListener 'keyup', onChange, false
202
298
 
203
-
204
- # The closest form element wrapping a node.
205
- parentForm: (element) ->
206
- while element
207
- return element if element.nodeName == 'FORM'
208
- element = element.parentNode
209
- null
210
-
211
299
  PwnFx.registerEffect 'refresh', PwnFxRefresh
212
300
 
213
301
 
@@ -300,7 +388,7 @@ class PwnFxHide
300
388
  element.addEventListener 'change', onChange, false
301
389
  onChange()
302
390
  else
303
- throw new Error("Unimplemented trigger #{trigger}")
391
+ throw new Error("Unimplemented pwnfx-hide trigger #{trigger}")
304
392
 
305
393
  PwnFx.registerEffect 'hide', PwnFxHide
306
394
 
@@ -1,6 +1,6 @@
1
- <% if flash[:error] %>
1
+ <% if flash[:alert] %>
2
2
  <p class="status-bar error" data-pwnfx-hide-positive="status-bar">
3
- <%= flash[:error] %>
3
+ <%= flash[:alert] %>
4
4
 
5
5
  <span class="actions">
6
6
  <%= link_to 'Hide', '#', 'data-pwnfx-hide' => 'status-bar' %>
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "pwnstyles_rails"
8
- s.version = "0.1.8"
8
+ s.version = "0.1.9"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Victor Costan"]
12
- s.date = "2012-02-06"
12
+ s.date = "2012-02-08"
13
13
  s.description = "Included CSS was designed for reuse across pwnb.us apps."
14
14
  s.email = "victor@costan.us"
15
15
  s.extra_rdoc_files = [
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pwnstyles_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.9
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-06 00:00:00.000000000Z
12
+ date: 2012-02-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
- requirement: &19937980 !ruby/object:Gem::Requirement
16
+ requirement: &11333680 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 3.2.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *19937980
24
+ version_requirements: *11333680
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: sass-rails
27
- requirement: &19937220 !ruby/object:Gem::Requirement
27
+ requirement: &11332740 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 3.2.4
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *19937220
35
+ version_requirements: *11332740
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: shoulda
38
- requirement: &19936520 !ruby/object:Gem::Requirement
38
+ requirement: &11331580 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *19936520
46
+ version_requirements: *11331580
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: bundler
49
- requirement: &19935800 !ruby/object:Gem::Requirement
49
+ requirement: &11330960 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 1.0.0
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *19935800
57
+ version_requirements: *11330960
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: jeweler
60
- requirement: &19934980 !ruby/object:Gem::Requirement
60
+ requirement: &11330260 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 1.8.0
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *19934980
68
+ version_requirements: *11330260
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rcov
71
- requirement: &19934260 !ruby/object:Gem::Requirement
71
+ requirement: &11329560 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *19934260
79
+ version_requirements: *11329560
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: simplecov
82
- requirement: &19933540 !ruby/object:Gem::Requirement
82
+ requirement: &11328840 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,7 +87,7 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *19933540
90
+ version_requirements: *11328840
91
91
  description: Included CSS was designed for reuse across pwnb.us apps.
92
92
  email: victor@costan.us
93
93
  executables: []
@@ -152,7 +152,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
152
152
  version: '0'
153
153
  segments:
154
154
  - 0
155
- hash: -1644724603097624457
155
+ hash: -1561629047696915926
156
156
  required_rubygems_version: !ruby/object:Gem::Requirement
157
157
  none: false
158
158
  requirements: