citygate 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/README.rdoc +13 -3
  2. data/app/assets/javascripts/citygate/home.js.coffee.erb +6 -5
  3. data/app/controllers/citygate/application_controller.rb +1 -0
  4. data/app/controllers/citygate/users_controller.rb +2 -0
  5. data/app/models/citygate/role.rb +4 -0
  6. data/app/models/citygate/user.rb +24 -1
  7. data/config/locales/views/admin/actions/en.yml +4 -0
  8. data/db/seeds.rb +0 -14
  9. data/lib/ability/USAGE +8 -0
  10. data/lib/ability/ability_generator.rb +3 -0
  11. data/lib/ability/templates/ability.rb +25 -0
  12. data/lib/citygate/engine.rb +8 -1
  13. data/lib/citygate/version.rb +1 -1
  14. data/lib/generators/ability/USAGE +8 -0
  15. data/lib/generators/ability/ability_generator.rb +7 -0
  16. data/lib/generators/ability/templates/ability.rb +25 -0
  17. data/spec/dummy/config/application.rb +3 -1
  18. data/spec/dummy/db/development.sqlite3 +0 -0
  19. data/spec/dummy/db/migrate/{20120706095546_devise_create_users.citygate.rb → 20121010234716_devise_create_users.citygate.rb} +0 -0
  20. data/spec/dummy/db/migrate/{20120706095547_add_name_to_users.citygate.rb → 20121010234717_add_name_to_users.citygate.rb} +0 -0
  21. data/spec/dummy/db/migrate/{20120706095548_add_confirmable_to_users.citygate.rb → 20121010234718_add_confirmable_to_users.citygate.rb} +0 -0
  22. data/spec/dummy/db/migrate/{20120706095549_devise_invitable_add_to_users.citygate.rb → 20121010234719_devise_invitable_add_to_users.citygate.rb} +0 -0
  23. data/spec/dummy/db/migrate/{20120706095550_add_omniauth_to_devise.citygate.rb → 20121010234720_add_omniauth_to_devise.citygate.rb} +0 -0
  24. data/spec/dummy/db/migrate/{20120706095551_create_roles.citygate.rb → 20121010234721_create_roles.citygate.rb} +0 -0
  25. data/spec/dummy/db/schema.rb +1 -11
  26. data/spec/dummy/db/test.sqlite3 +0 -0
  27. data/spec/dummy/features/step_definitions/user_steps.rb +7 -0
  28. data/spec/dummy/features/support/paths.rb +3 -0
  29. data/spec/dummy/features/users/user_edit.feature +2 -0
  30. data/spec/dummy/features/users/users_admin.feature +1 -1
  31. data/spec/dummy/lib/ability.rb +25 -0
  32. data/spec/dummy/log/development.log +2692 -0
  33. data/spec/dummy/log/test.log +23012 -0
  34. data/spec/dummy/spec/models/role_spec.rb +13 -0
  35. data/spec/dummy/spec/models/user_spec.rb +47 -0
  36. data/spec/dummy/tmp/cache/assets/C72/B10/sprockets%2F21a4b8118f1f4254bf815e306027b951 +0 -0
  37. data/spec/dummy/tmp/cache/assets/C7A/CE0/sprockets%2F9124c83a02e7332a90b2883b69f81d04 +0 -0
  38. data/spec/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
  39. data/spec/dummy/tmp/cache/assets/CE3/150/sprockets%2F7d7a09e1df5c7510266a8d752683c4b3 +0 -0
  40. data/spec/dummy/tmp/cache/assets/D0D/DE0/sprockets%2Fa35442f02b0b2479f22d83d639d8c4fd +0 -0
  41. data/spec/dummy/tmp/cache/assets/D11/620/sprockets%2Ff9ea58224378018a71daac5437676adc +0 -0
  42. data/spec/dummy/tmp/cache/assets/D14/F80/sprockets%2F88a8b65bba21cb666758df2ff9300272 +0 -0
  43. data/spec/dummy/tmp/cache/assets/D1C/110/sprockets%2Ff7118b71a9f4d6d8bf76e874be631322 +0 -0
  44. data/spec/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  45. data/spec/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
  46. data/spec/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
  47. data/spec/dummy/tmp/cache/assets/D8F/400/sprockets%2F1aeaa1227411ad4c4ee0a489f5dbc668 +0 -0
  48. data/spec/dummy/tmp/cache/assets/D99/BF0/sprockets%2F2fd8d582e234f8d0a741c1b4cafb716e +0 -0
  49. data/spec/dummy/tmp/cache/assets/D9E/F10/sprockets%2F9ab223df888d724dcad09eb1163cc5f4 +0 -0
  50. data/spec/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
  51. data/spec/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
  52. metadata +312 -198
  53. data/app/assets/javascripts/citygate/admin_users.coffee +0 -2
  54. data/app/assets/javascripts/citygate/jquery.pjax.js +0 -690
  55. data/app/models/citygate/permission.rb +0 -24
  56. data/db/migrate/20120727143920_create_permissions_table.rb +0 -12
  57. data/db/migrate/20120916221334_add_conditions_to_permissions.rb +0 -5
  58. data/lib/ability.rb +0 -73
  59. data/spec/dummy/db/migrate/20120727145840_create_permissions_table.citygate.rb +0 -13
  60. data/spec/dummy/db/migrate/20120916223209_add_conditions_to_permissions.citygate.rb +0 -6
  61. data/spec/dummy/spec/lib/ability_spec.rb +0 -10
  62. data/spec/dummy/spec/models/permission_spec.rb +0 -13
@@ -1,2 +0,0 @@
1
- $ ->
2
- $("a").pjax("#pjax-container").on 'click'
@@ -1,690 +0,0 @@
1
- // jquery.pjax.js
2
- // copyright chris wanstrath
3
- // https://github.com/defunkt/jquery-pjax
4
-
5
- (function($){
6
-
7
- // When called on a link, fetches the href with ajax into the
8
- // container specified as the first parameter or with the data-pjax
9
- // attribute on the link itself.
10
- //
11
- // Tries to make sure the back button and ctrl+click work the way
12
- // you'd expect.
13
- //
14
- // Accepts a jQuery ajax options object that may include these
15
- // pjax specific options:
16
- //
17
- // container - Where to stick the response body. Usually a String selector.
18
- // $(container).html(xhr.responseBody)
19
- // push - Whether to pushState the URL. Defaults to true (of course).
20
- // replace - Want to use replaceState instead? That's cool.
21
- //
22
- // For convenience the first parameter can be either the container or
23
- // the options object.
24
- //
25
- // Returns the jQuery object
26
- $.fn.pjax = function( container, options ) {
27
- return this.live('click.pjax', function(event){
28
- handleClick(event, container, options)
29
- })
30
- }
31
-
32
- // Public: pjax on click handler
33
- //
34
- // Exported as $.pjax.click.
35
- //
36
- // event - "click" jQuery.Event
37
- // options - pjax options
38
- //
39
- // Examples
40
- //
41
- // $('a').live('click', $.pjax.click)
42
- // // is the same as
43
- // $('a').pjax()
44
- //
45
- // $(document).on('click', 'a', function(event) {
46
- // var container = $(this).closest('[data-pjax-container]')
47
- // return $.pjax.click(event, container)
48
- // })
49
- //
50
- // Returns false if pjax runs, otherwise nothing.
51
- function handleClick(event, container, options) {
52
- options = optionsFor(container, options)
53
-
54
- var link = event.currentTarget
55
-
56
- if (link.tagName.toUpperCase() !== 'A')
57
- throw "$.fn.pjax or $.pjax.click requires an anchor element"
58
-
59
- // Middle click, cmd click, and ctrl click should open
60
- // links in a new tab as normal.
61
- if ( event.which > 1 || event.metaKey || event.ctrlKey )
62
- return
63
-
64
- // Ignore cross origin links
65
- if ( location.protocol !== link.protocol || location.host !== link.host )
66
- return
67
-
68
- // Ignore anchors on the same page
69
- if ( link.hash && link.href.replace(link.hash, '') ===
70
- location.href.replace(location.hash, '') )
71
- return
72
-
73
- var defaults = {
74
- url: link.href,
75
- container: $(link).attr('data-pjax'),
76
- target: link,
77
- clickedElement: $(link), // DEPRECATED: use target
78
- fragment: null
79
- }
80
-
81
- $.pjax($.extend({}, defaults, options))
82
-
83
- event.preventDefault()
84
- }
85
-
86
-
87
- // Loads a URL with ajax, puts the response body inside a container,
88
- // then pushState()'s the loaded URL.
89
- //
90
- // Works just like $.ajax in that it accepts a jQuery ajax
91
- // settings object (with keys like url, type, data, etc).
92
- //
93
- // Accepts these extra keys:
94
- //
95
- // container - Where to stick the response body.
96
- // $(container).html(xhr.responseBody)
97
- // push - Whether to pushState the URL. Defaults to true (of course).
98
- // replace - Want to use replaceState instead? That's cool.
99
- //
100
- // Use it just like $.ajax:
101
- //
102
- // var xhr = $.pjax({ url: this.href, container: '#main' })
103
- // console.log( xhr.readyState )
104
- //
105
- // Returns whatever $.ajax returns.
106
- var pjax = $.pjax = function( options ) {
107
- options = $.extend(true, {}, $.ajaxSettings, pjax.defaults, options)
108
-
109
- if ($.isFunction(options.url)) {
110
- options.url = options.url()
111
- }
112
-
113
- var target = options.target
114
-
115
- // DEPRECATED: use options.target
116
- if (!target && options.clickedElement) target = options.clickedElement[0]
117
-
118
- var hash = parseURL(options.url).hash
119
-
120
- // DEPRECATED: Save references to original event callbacks. However,
121
- // listening for custom pjax:* events is prefered.
122
- var oldBeforeSend = options.beforeSend,
123
- oldComplete = options.complete,
124
- oldSuccess = options.success,
125
- oldError = options.error
126
-
127
- var context = options.context = findContainerFor(options.container)
128
-
129
- // We want the browser to maintain two separate internal caches: one
130
- // for pjax'd partial page loads and one for normal page loads.
131
- // Without adding this secret parameter, some browsers will often
132
- // confuse the two.
133
- if (!options.data) options.data = {}
134
- options.data._pjax = context.selector
135
-
136
- function fire(type, args) {
137
- var event = $.Event(type, { relatedTarget: target })
138
- context.trigger(event, args)
139
- return !event.isDefaultPrevented()
140
- }
141
-
142
- var timeoutTimer
143
-
144
- options.beforeSend = function(xhr, settings) {
145
- if (settings.timeout > 0) {
146
- timeoutTimer = setTimeout(function() {
147
- if (fire('pjax:timeout', [xhr, options]))
148
- xhr.abort('timeout')
149
- }, settings.timeout)
150
-
151
- // Clear timeout setting so jquerys internal timeout isn't invoked
152
- settings.timeout = 0
153
- }
154
-
155
- xhr.setRequestHeader('X-PJAX', 'true')
156
- xhr.setRequestHeader('X-PJAX-Container', context.selector)
157
- if(!settings.push)
158
- xhr.setRequestHeader('X-PJAX-layout','true')
159
-
160
- var result
161
-
162
- // DEPRECATED: Invoke original `beforeSend` handler
163
- if (oldBeforeSend) {
164
- result = oldBeforeSend.apply(this, arguments)
165
- if (result === false) return false
166
- }
167
-
168
- if (!fire('pjax:beforeSend', [xhr, settings]))
169
- return false
170
-
171
- options.requestUrl = parseURL(settings.url).href
172
- }
173
-
174
- options.complete = function(xhr, textStatus) {
175
- if (timeoutTimer)
176
- clearTimeout(timeoutTimer)
177
-
178
- // DEPRECATED: Invoke original `complete` handler
179
- if (oldComplete) oldComplete.apply(this, arguments)
180
-
181
- fire('pjax:complete', [xhr, textStatus, options])
182
-
183
- fire('pjax:end', [xhr, options])
184
- // end.pjax is deprecated
185
- fire('end.pjax', [xhr, options])
186
- }
187
-
188
- options.error = function(xhr, textStatus, errorThrown) {
189
- var container = extractContainer("", xhr, options)
190
-
191
- // DEPRECATED: Invoke original `error` handler
192
- if (oldError) oldError.apply(this, arguments)
193
-
194
- var allowed = fire('pjax:error', [xhr, textStatus, errorThrown, options])
195
- if (textStatus !== 'abort' && allowed)
196
- window.location = container.url
197
- }
198
-
199
- options.success = function(data, status, xhr) {
200
- var container = extractContainer(data, xhr, options)
201
-
202
- if (!container.contents) {
203
- window.location = container.url
204
- return
205
- }
206
-
207
- pjax.state = {
208
- id: options.id || uniqueId(),
209
- url: container.url,
210
- title: container.title,
211
- container: context.selector,
212
- fragment: options.fragment,
213
- timeout: options.timeout
214
- }
215
-
216
- if (options.push || options.replace) {
217
- window.history.replaceState(pjax.state, container.title, container.url)
218
- }
219
-
220
- if (container.title) document.title = container.title
221
- context.html(container.contents)
222
-
223
- // Scroll to top by default
224
- if (typeof options.scrollTo === 'number')
225
- $(window).scrollTop(options.scrollTo)
226
-
227
- // Google Analytics support
228
- if ( (options.replace || options.push) && window._gaq )
229
- _gaq.push(['_trackPageview'])
230
-
231
- // If the URL has a hash in it, make sure the browser
232
- // knows to navigate to the hash.
233
- if ( hash !== '' ) {
234
- window.location.href = hash
235
- }
236
-
237
- // DEPRECATED: Invoke original `success` handler
238
- if (oldSuccess) oldSuccess.apply(this, arguments)
239
-
240
- fire('pjax:success', [data, status, xhr, options])
241
- }
242
-
243
-
244
- // Initialize pjax.state for the initial page load. Assume we're
245
- // using the container and options of the link we're loading for the
246
- // back button to the initial page. This ensures good back button
247
- // behavior.
248
- if (!pjax.state) {
249
- pjax.state = {
250
- id: uniqueId(),
251
- url: window.location.href,
252
- title: document.title,
253
- container: context.selector,
254
- fragment: options.fragment,
255
- timeout: options.timeout
256
- }
257
- window.history.replaceState(pjax.state, document.title)
258
- }
259
-
260
- // Cancel the current request if we're already pjaxing
261
- var xhr = pjax.xhr
262
- if ( xhr && xhr.readyState < 4) {
263
- xhr.onreadystatechange = $.noop
264
- xhr.abort()
265
- }
266
-
267
- pjax.options = options
268
- var xhr = pjax.xhr = $.ajax(options)
269
-
270
- if (xhr.readyState > 0) {
271
- // pjax event is deprecated
272
- $(document).trigger('pjax', [xhr, options])
273
-
274
- if (options.push && !options.replace) {
275
- // Cache current container element before replacing it
276
- containerCache.push(pjax.state.id, context.clone(true, true).contents())
277
-
278
- window.history.pushState(null, "", options.url)
279
- }
280
-
281
- fire('pjax:start', [xhr, options])
282
- // start.pjax is deprecated
283
- fire('start.pjax', [xhr, options])
284
-
285
- fire('pjax:send', [xhr, options])
286
- }
287
-
288
- return pjax.xhr
289
- }
290
-
291
-
292
- // Internal: Generate unique id for state object.
293
- //
294
- // Use a timestamp instead of a counter since ids should still be
295
- // unique across page loads.
296
- //
297
- // Returns Number.
298
- function uniqueId() {
299
- return (new Date).getTime()
300
- }
301
-
302
- // Internal: Strips _pjax param from url
303
- //
304
- // url - String
305
- //
306
- // Returns String.
307
- function stripPjaxParam(url) {
308
- return url
309
- .replace(/\?_pjax=[^&]+&?/, '?')
310
- .replace(/_pjax=[^&]+&?/, '')
311
- .replace(/[\?&]$/, '')
312
- }
313
-
314
- // Internal: Parse URL components and returns a Locationish object.
315
- //
316
- // url - String URL
317
- //
318
- // Returns HTMLAnchorElement that acts like Location.
319
- function parseURL(url) {
320
- var a = document.createElement('a')
321
- a.href = url
322
- return a
323
- }
324
-
325
- // Internal: Build options Object for arguments.
326
- //
327
- // For convenience the first parameter can be either the container or
328
- // the options object.
329
- //
330
- // Examples
331
- //
332
- // optionsFor('#container')
333
- // // => {container: '#container'}
334
- //
335
- // optionsFor('#container', {push: true})
336
- // // => {container: '#container', push: true}
337
- //
338
- // optionsFor({container: '#container', push: true})
339
- // // => {container: '#container', push: true}
340
- //
341
- // Returns options Object.
342
- function optionsFor(container, options) {
343
- // Both container and options
344
- if ( container && options )
345
- options.container = container
346
-
347
- // First argument is options Object
348
- else if ( $.isPlainObject(container) )
349
- options = container
350
-
351
- // Only container
352
- else
353
- options = {container: container}
354
-
355
- // Find and validate container
356
- if (options.container)
357
- options.container = findContainerFor(options.container)
358
-
359
- return options
360
- }
361
-
362
- // Internal: Find container element for a variety of inputs.
363
- //
364
- // Because we can't persist elements using the history API, we must be
365
- // able to find a String selector that will consistently find the Element.
366
- //
367
- // container - A selector String, jQuery object, or DOM Element.
368
- //
369
- // Returns a jQuery object whose context is `document` and has a selector.
370
- function findContainerFor(container) {
371
- container = $(container)
372
-
373
- if ( !container.length ) {
374
- throw "no pjax container for " + container.selector
375
- } else if ( container.selector !== '' && container.context === document ) {
376
- return container
377
- } else if ( container.attr('id') ) {
378
- return $('#' + container.attr('id'))
379
- } else {
380
- throw "cant get selector for pjax container!"
381
- }
382
- }
383
-
384
- // Internal: Filter and find all elements matching the selector.
385
- //
386
- // Where $.fn.find only matches descendants, findAll will test all the
387
- // top level elements in the jQuery object as well.
388
- //
389
- // elems - jQuery object of Elements
390
- // selector - String selector to match
391
- //
392
- // Returns a jQuery object.
393
- function findAll(elems, selector) {
394
- var results = $()
395
- elems.each(function() {
396
- if ($(this).is(selector))
397
- results = results.add(this)
398
- results = results.add(selector, this)
399
- })
400
- return results
401
- }
402
-
403
- // Internal: Extracts container and metadata from response.
404
- //
405
- // 1. Extracts X-PJAX-URL header if set
406
- // 2. Extracts inline <title> tags
407
- // 3. Builds response Element and extracts fragment if set
408
- //
409
- // data - String response data
410
- // xhr - XHR response
411
- // options - pjax options Object
412
- //
413
- // Returns an Object with url, title, and contents keys.
414
- function extractContainer(data, xhr, options) {
415
- var obj = {}
416
-
417
- // Prefer X-PJAX-URL header if it was set, otherwise fallback to
418
- // using the original requested url.
419
- obj.url = stripPjaxParam(xhr.getResponseHeader('X-PJAX-URL') || options.requestUrl)
420
-
421
- // Attempt to parse response html into elements
422
- var $data = $(data)
423
-
424
- // If response data is empty, return fast
425
- if ($data.length === 0)
426
- return obj
427
-
428
- // If there's a <title> tag in the response, use it as
429
- // the page's title.
430
- obj.title = findAll($data, 'title').last().text()
431
-
432
- if (options.fragment) {
433
- // If they specified a fragment, look for it in the response
434
- // and pull it out.
435
- var $fragment = findAll($data, options.fragment).first()
436
-
437
- if ($fragment.length) {
438
- obj.contents = $fragment.contents()
439
-
440
- // If there's no title, look for data-title and title attributes
441
- // on the fragment
442
- if (!obj.title)
443
- obj.title = $fragment.attr('title') || $fragment.data('title')
444
- }
445
-
446
- } else if (!/<html/i.test(data)) {
447
- obj.contents = $data
448
- }
449
-
450
- // Clean up any <title> tags
451
- if (obj.contents) {
452
- // Remove any parent title elements
453
- obj.contents = obj.contents.not('title')
454
-
455
- // Then scrub any titles from their descendents
456
- obj.contents.find('title').remove()
457
- }
458
-
459
- // Trim any whitespace off the title
460
- if (obj.title) obj.title = $.trim(obj.title)
461
-
462
- return obj
463
- }
464
-
465
- // Public: Reload current page with pjax.
466
- //
467
- // Returns whatever $.pjax returns.
468
- pjax.reload = function(container, options) {
469
- var defaults = {
470
- url: window.location.href,
471
- push: false,
472
- replace: true,
473
- scrollTo: false
474
- }
475
-
476
- return $.pjax($.extend(defaults, optionsFor(container, options)))
477
- }
478
-
479
-
480
- pjax.defaults = {
481
- timeout: 650,
482
- push: true,
483
- replace: false,
484
- type: 'GET',
485
- dataType: 'html',
486
- scrollTo: 0,
487
- maxCacheLength: 20
488
- }
489
-
490
- // Internal: History DOM caching class.
491
- function Cache() {
492
- this.mapping = {}
493
- this.forwardStack = []
494
- this.backStack = []
495
- }
496
- // Push previous state id and container contents into the history
497
- // cache. Should be called in conjunction with `pushState` to save the
498
- // previous container contents.
499
- //
500
- // id - State ID Number
501
- // value - DOM Element to cache
502
- //
503
- // Returns nothing.
504
- Cache.prototype.push = function(id, value) {
505
- this.mapping[id] = value
506
- this.backStack.push(id)
507
-
508
- // Remove all entires in forward history stack after pushing
509
- // a new page.
510
- while (this.forwardStack.length)
511
- delete this.mapping[this.forwardStack.shift()]
512
-
513
- // Trim back history stack to max cache length.
514
- while (this.backStack.length > pjax.defaults.maxCacheLength)
515
- delete this.mapping[this.backStack.shift()]
516
- }
517
- // Retrieve cached DOM Element for state id.
518
- //
519
- // id - State ID Number
520
- //
521
- // Returns DOM Element(s) or undefined if cache miss.
522
- Cache.prototype.get = function(id) {
523
- return this.mapping[id]
524
- }
525
- // Shifts cache from forward history cache to back stack. Should be
526
- // called on `popstate` with the previous state id and container
527
- // contents.
528
- //
529
- // id - State ID Number
530
- // value - DOM Element to cache
531
- //
532
- // Returns nothing.
533
- Cache.prototype.forward = function(id, value) {
534
- this.mapping[id] = value
535
- this.backStack.push(id)
536
-
537
- if (id = this.forwardStack.pop())
538
- delete this.mapping[id]
539
- }
540
- // Shifts cache from back history cache to forward stack. Should be
541
- // called on `popstate` with the previous state id and container
542
- // contents.
543
- //
544
- // id - State ID Number
545
- // value - DOM Element to cache
546
- //
547
- // Returns nothing.
548
- Cache.prototype.back = function(id, value) {
549
- this.mapping[id] = value
550
- this.forwardStack.push(id)
551
-
552
- if (id = this.backStack.pop())
553
- delete this.mapping[id]
554
- }
555
-
556
- var containerCache = new Cache
557
-
558
-
559
- // Export $.pjax.click
560
- pjax.click = handleClick
561
-
562
-
563
- // Used to detect initial (useless) popstate.
564
- // If history.state exists, assume browser isn't going to fire initial popstate.
565
- var popped = ('state' in window.history), initialURL = location.href
566
-
567
-
568
- // popstate handler takes care of the back and forward buttons
569
- //
570
- // You probably shouldn't use pjax on pages with other pushState
571
- // stuff yet.
572
- $(window).bind('popstate', function(event){
573
- // Ignore inital popstate that some browsers fire on page load
574
- var initialPop = !popped && location.href == initialURL
575
- popped = true
576
- if ( initialPop ) return
577
-
578
- var state = event.state
579
-
580
- if (state && state.container) {
581
- var container = $(state.container)
582
- if (container.length) {
583
- var contents = containerCache.get(state.id)
584
-
585
- if (pjax.state) {
586
- // Since state ids always increase, we can deduce the history
587
- // direction from the previous state.
588
- var direction = pjax.state.id < state.id ? 'forward' : 'back'
589
-
590
- // Cache current container before replacement and inform the
591
- // cache which direction the history shifted.
592
- containerCache[direction](pjax.state.id, container.clone(true, true).contents())
593
- }
594
-
595
- var popstateEvent = $.Event('pjax:popstate', {
596
- state: state,
597
- direction: direction
598
- })
599
- container.trigger(popstateEvent)
600
-
601
- var options = {
602
- id: state.id,
603
- url: state.url,
604
- container: container,
605
- push: false,
606
- fragment: state.fragment,
607
- timeout: state.timeout,
608
- scrollTo: false
609
- }
610
-
611
- if (contents) {
612
- // pjax event is deprecated
613
- $(document).trigger('pjax', [null, options])
614
- container.trigger('pjax:start', [null, options])
615
- // end.pjax event is deprecated
616
- container.trigger('start.pjax', [null, options])
617
-
618
- if (state.title) document.title = state.title
619
- container.html(contents)
620
- pjax.state = state
621
-
622
- container.trigger('pjax:end', [null, options])
623
- // end.pjax event is deprecated
624
- container.trigger('end.pjax', [null, options])
625
- } else {
626
- $.pjax(options)
627
- }
628
-
629
- // Force reflow/relayout before the browser tries to restore the
630
- // scroll position.
631
- container[0].offsetHeight
632
- } else {
633
- window.location = location.href
634
- }
635
- }
636
- })
637
-
638
-
639
- // Add the state property to jQuery's event object so we can use it in
640
- // $(window).bind('popstate')
641
- if ( $.inArray('state', $.event.props) < 0 )
642
- $.event.props.push('state')
643
-
644
-
645
- // Is pjax supported by this browser?
646
- $.support.pjax =
647
- window.history && window.history.pushState && window.history.replaceState
648
- // pushState isn't reliable on iOS until 5.
649
- && !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/)
650
-
651
- // Fall back to normalcy for older browsers.
652
- if ( !$.support.pjax ) {
653
- $.pjax = function( options ) {
654
- var url = $.isFunction(options.url) ? options.url() : options.url,
655
- method = options.type ? options.type.toUpperCase() : 'GET'
656
-
657
- var form = $('<form>', {
658
- method: method === 'GET' ? 'GET' : 'POST',
659
- action: url,
660
- style: 'display:none'
661
- })
662
-
663
- if (method !== 'GET' && method !== 'POST') {
664
- form.append($('<input>', {
665
- type: 'hidden',
666
- name: '_method',
667
- value: method.toLowerCase()
668
- }))
669
- }
670
-
671
- var data = options.data
672
- if (typeof data === 'string') {
673
- $.each(data.split('&'), function(index, value) {
674
- var pair = value.split('=')
675
- form.append($('<input>', {type: 'hidden', name: pair[0], value: pair[1]}))
676
- })
677
- } else if (typeof data === 'object') {
678
- for (key in data)
679
- form.append($('<input>', {type: 'hidden', name: key, value: data[key]}))
680
- }
681
-
682
- $(document.body).append(form)
683
- form.submit()
684
- }
685
- $.pjax.click = $.noop
686
- $.pjax.reload = window.location.reload
687
- $.fn.pjax = function() { return this }
688
- }
689
-
690
- })(jQuery);