ajax 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +127 -36
- data/VERSION +1 -1
- data/lib/ajax/helpers/url_helper.rb +11 -7
- data/public/images/ajax-loading.gif +0 -0
- data/public/javascripts/ajax.js +102 -39
- data/rails/install.rb +1 -1
- data/spec/ajax/helpers_spec.rb +21 -1
- metadata +3 -4
- data/public/images/loading-icon-large.gif +0 -0
- data/public/images/loading-icon-small.gif +0 -0
data/README.rdoc
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
<b>A Ruby on Rails plugin to augment a traditional Rails application with a completely AJAX frontend, while transparently handling issues important to both the enterprise and end users, such as testing, SEO and browser history.</b>
|
4
4
|
|
5
|
-
The Ajax philosophy is that you
|
5
|
+
The Ajax philosophy is that you shouldn't have to develop for AJAX: Your code shouldn't change; your tests shouldn't change; and the way Google sees your site shouldn't change.
|
6
6
|
|
7
7
|
The beauty of Ajax is that your Rails application only ever sees traditional requests, so it does not have to be "Ajax aware".
|
8
8
|
|
@@ -10,8 +10,6 @@ Ajax is being used live in production on altnet.com[http://altnet.com], if you w
|
|
10
10
|
|
11
11
|
== Install
|
12
12
|
|
13
|
-
After installing, create layouts in <tt>app/views/layouts/ajax/</tt> that mimic your existing layouts. See <b>Request Handling -> Layouts</b>.
|
14
|
-
|
15
13
|
=== Rails 3
|
16
14
|
|
17
15
|
1. Add the gem to your <tt>Gemspec</tt>
|
@@ -47,20 +45,31 @@ After installing, create layouts in <tt>app/views/layouts/ajax/</tt> that mimic
|
|
47
45
|
|
48
46
|
=== Sample Output
|
49
47
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
48
|
+
$ rake ajax:install
|
49
|
+
created: app/controllers/ajax_controller.rb
|
50
|
+
created: app/views/ajax/framework.html.erb
|
51
|
+
created: config/initializers/ajax.rb
|
52
|
+
created: public/javascripts/ajax.js
|
53
|
+
created: public/javascripts/jquery.address-1.2rc.js
|
54
|
+
created: public/javascripts/jquery.address-1.2rc.min.js
|
55
|
+
created: public/javascripts/jquery.json-2.2.min.js
|
56
|
+
created: public/images/ajax-loading.gif
|
57
|
+
|
58
|
+
$ rake ajax:install
|
59
|
+
skipped: app/controllers/ajax_controller.rb exists!
|
60
|
+
skipped: app/views/ajax/framework.html.erb exists!
|
61
|
+
...
|
62
|
+
|
63
|
+
=== Post Install
|
64
|
+
|
65
|
+
1. Create layouts in <tt>app/views/layouts/ajax/</tt> that mimic your existing layouts. See <b>Request Handling -> Layouts</b>.
|
66
|
+
2. Instantiate an instance of the Ajax class in <tt>application.js</tt>. For example:
|
67
|
+
|
68
|
+
window.ajax = new Ajax({
|
69
|
+
default_container: '#main',
|
70
|
+
enabled: true,
|
71
|
+
lazy_load_assets: false
|
72
|
+
});
|
64
73
|
|
65
74
|
== Introduction
|
66
75
|
|
@@ -156,6 +165,10 @@ Please browse the {API documentation at rDoc.info}[http://rdoc.info/projects/kjv
|
|
156
165
|
|
157
166
|
It is important to be able to disable the plugin when you don't want it interfering, like when you are testing. You will also want to ensure that your site's JavaScript still works when the plugin is disabled.
|
158
167
|
|
168
|
+
<b>If Ajax is disabled</b>, your site will act like a traditional Rails application. Because each request will be a traditional request, <b>callbacks specified in the Ajax-Info header will not be parsed by the browser, and so will not execute.</b>
|
169
|
+
|
170
|
+
<b>Callbacks added directly to the <tt>window.ajax</tt> instance will still be executed, and they will execute immediately.</b>
|
171
|
+
|
159
172
|
To disable the plugin in your environment file:
|
160
173
|
|
161
174
|
# config/environments/test.rb
|
@@ -252,40 +265,118 @@ See {ajax/two_column.html.haml}[http://gist.github.com/373133#file_two_column.ht
|
|
252
265
|
|
253
266
|
== Lazy-loading Assets
|
254
267
|
|
268
|
+
<b>KJV 2010-04-22:</b> Browser support for callbacks (specifically the problem of calling them only *after* all assets have loaded) is patchy/inconsistent at this time so lazy-loading is not recommended. It has been disabled by default. Once all browsers can be supported this may change.
|
269
|
+
|
270
|
+
<b>The recommended way of dynamically enabling/disabling lazy loading:</b>
|
271
|
+
|
272
|
+
# environment/initializer
|
273
|
+
Ajax.lazy_load_assets = false # or true
|
274
|
+
|
275
|
+
# application layout (HAML example)
|
276
|
+
:javascript
|
277
|
+
var AJAX_LAZY_LOAD_ASSETS = #{Ajax.lazy_load_assets?};
|
278
|
+
|
279
|
+
if !Ajax.lazy_load_assets
|
280
|
+
include_all_assets
|
281
|
+
end
|
282
|
+
|
283
|
+
# application.js
|
284
|
+
window.ajax = new Ajax({
|
285
|
+
lazy_load_assets: window.AJAX_LAZY_LOAD_ASSETS !== undefined ? window.AJAX_LAZY_LOAD_ASSETS : false
|
286
|
+
});
|
287
|
+
|
255
288
|
Use <code>ajax_header :assets { :stylesheets => [], :javascripts => [] }</code> to define assets that a page depends on. These assets will be loaded before the response content is inserted into the DOM.
|
256
289
|
|
257
|
-
Assets that have already been loaded are not loaded again
|
290
|
+
1. Assets that have already been loaded are not loaded again
|
291
|
+
2. Assets that are loaded, remain loaded (watch out for CSS conflicts and JS memory leaks)
|
292
|
+
3. If lazy-loading assets is disabled, assets in the <tt>Ajax-Info</tt> header are ignored, but callbacks are still executed.
|
258
293
|
|
259
|
-
|
294
|
+
Often you will need to perform some DOM manipulations on the newly inserted content, or instantiate JavaScript objects that are defined in a lazy-loaded JS file. To execute some JavaScript after all assets have been loaded and the new content has been inserted, use <b>JavaScript Callbacks</b>.
|
260
295
|
|
261
|
-
==
|
296
|
+
== JavaScript Callbacks
|
262
297
|
|
263
|
-
|
298
|
+
JavaScript callbacks can be added to the response and will be executed after any assets in <tt>Ajax-Info['assets']</tt> have been loaded. (If lazy loading assets is disabled, they are executed immediately.)
|
264
299
|
|
265
|
-
|
266
|
-
|
267
|
-
|
300
|
+
You can bind callbacks directly to the <tt>window.ajax</tt> object in your view, for example, in HAML we could have:
|
301
|
+
|
302
|
+
:javascript
|
303
|
+
window.ajax.onLoad(function() {
|
304
|
+
window.juggernaut = new window.Juggernaut(#{juggernaut_options.to_json});
|
305
|
+
window.liveFeed.init();
|
306
|
+
});
|
268
307
|
|
269
|
-
|
270
|
-
|
271
|
-
|
308
|
+
window.ajax.prependOnLoad(function() {
|
309
|
+
$(document).trigger('player.init');
|
310
|
+
});
|
272
311
|
|
273
|
-
|
312
|
+
In the <tt>onLoad</tt> callback I'm scoping everything to <tt>window</tt> to <b>avoid scoping issues</b> in different browsers.
|
274
313
|
|
275
|
-
<tt>window.ajax.prependOnLoad</tt> adds the callback to the front of the queue.
|
314
|
+
<b><tt>window.ajax.prependOnLoad</tt><b> adds the callback to the front of the queue.
|
315
|
+
|
316
|
+
Alternatively callbacks can be passed as a list of Strings in the <tt>Ajax-Info</tt> header using the <tt>ajax_header</tt> helper:
|
317
|
+
|
318
|
+
ajax_header, :callbacks, 'window.player.init();'
|
319
|
+
|
320
|
+
These callbacks are executed in the global scope. This method of adding callbacks is not recommended for two reasons:
|
321
|
+
|
322
|
+
1. Safari has trouble with some String callbacks.
|
323
|
+
2. If Ajax is disabled, these callbacks will not be executed, because the <tt>Ajax-Info</tt> header will not be set.
|
324
|
+
|
325
|
+
However, callbacks added directly to the <tt>window.ajax</tt> instance will still be executed, and they will execute immediately, so your code continues to work as expected.
|
326
|
+
|
327
|
+
== JavaScript Gotchas
|
328
|
+
|
329
|
+
Most of the problems you will likely encounter from a change to Ajax will be JavaScript related. These problems become more noticeable for the following reasons:
|
330
|
+
|
331
|
+
1. JavaScript that has been loaded, remains loaded for a very long time. This can lead to:
|
332
|
+
1. Memory leaks
|
333
|
+
2. Callbacks executing ad infinitum, likely on content that has since been replaced.
|
334
|
+
2. Inconsistent browser handling of JavaScript returned via AJAX:
|
335
|
+
1. JavaScript in AJAX response is executed in local scope
|
336
|
+
1. Safari {scoping issues}[http://forum.jquery.com/topic/dealing-with-globaleval-and-safari-suggestion-for-a-better-approach]
|
337
|
+
3. {Inconsistent support for <tt>script.onload</tt>}[http://unixpapa.com/js/dyna.html]
|
338
|
+
3. Badly written JavaScript libraries
|
339
|
+
|
340
|
+
To ease some of the pain, observe some of the following advice:
|
341
|
+
|
342
|
+
1. Never use {<tt>document.write</tt>}[http://javascript.crockford.com/script.html]
|
343
|
+
2. Use <tt>window</tt> to avoid scoping issues.
|
344
|
+
3. Modify your third-party JavaScript libraries to also assign classes etc to <tt>window</tt>.
|
345
|
+
4. Use jQuery {live events}[http://api.jquery.com/live/]
|
346
|
+
5. Dynamically turn off repeating callbacks e.g.
|
347
|
+
|
348
|
+
function my_repetitive_callback() {
|
349
|
+
if ($(selector).size() == 0) {
|
350
|
+
// Turn off the interval
|
351
|
+
if (object.interval_id !== undefined) {
|
352
|
+
clearInterval(object.interval_id);
|
353
|
+
object.interval_id = undefined;
|
354
|
+
}
|
355
|
+
} else {
|
356
|
+
$(selector).do().some().jquery().kung().foo();
|
357
|
+
}
|
358
|
+
}
|
359
|
+
|
360
|
+
// Start the interval. Do this whenever a page is rendered
|
361
|
+
// that has content we want to work with. This will start
|
362
|
+
// the interval running. When we change the page, the
|
363
|
+
// content will disappear and the interval will turn itself off.
|
364
|
+
object.interval_id = setInterval(my_repetitive_callback, 5000);
|
365
|
+
|
366
|
+
== Testing
|
367
|
+
|
368
|
+
* We use RSpec
|
369
|
+
* See <tt>Ajax::Spec::Helpers</tt> and <tt>Ajax::Spec::Extension</tt> {in the rdocs}[http://rdoc.info/projects/kjvarga/ajax]
|
370
|
+
* Copy <tt>ajax/spec/integration/ajax_spec.rb</tt> into your project to ensure that the Ajax integration always works.
|
276
371
|
|
277
|
-
window.ajax.onLoad(function() {
|
278
|
-
alert('All your asset are ours!');
|
279
|
-
});
|
280
|
-
|
281
372
|
== Contributions
|
282
373
|
|
283
374
|
Contributions are welcome. Please fork the project and send me a pull request with your changes and Spec tests.
|
284
375
|
|
285
376
|
== Useful Resources
|
286
377
|
|
287
|
-
*
|
288
|
-
*
|
289
|
-
*
|
378
|
+
* {AJAX site crawling specification}[http://code.google.com/web/ajaxcrawling/docs/getting-started.html].
|
379
|
+
* AjaxPatters[http://ajaxpatterns.org/] useful discussion of AJAX-related problems and their solutions.
|
380
|
+
* {jQuery Address}[http://www.asual.com/jquery/address/] JavaScript library for managing the URL and deep-linking.
|
290
381
|
|
291
382
|
Copyright (c) 2010 Karl Varga, released under the MIT license
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.4
|
@@ -5,36 +5,40 @@ module Ajax
|
|
5
5
|
# Return a boolean indicating whether the given URL points to the
|
6
6
|
# root path.
|
7
7
|
def url_is_root?(url)
|
8
|
-
!!(
|
8
|
+
!!(encode_and_parse_url(url).path =~ %r[^\/?$])
|
9
9
|
end
|
10
10
|
|
11
11
|
# The URL is hashed if the fragment part starts with a /
|
12
12
|
#
|
13
13
|
# For example, http://lol.com#/Rihanna
|
14
14
|
def is_hashed_url?(url)
|
15
|
-
!!(
|
15
|
+
!!(encode_and_parse_url(url).fragment=~ %r[^\/])
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
# Return a hashed URL using the fragment of <tt>url</tt>
|
19
19
|
def hashed_url_from_fragment(url)
|
20
|
-
url_host(url) + ('/#/' + (
|
20
|
+
url_host(url) + ('/#/' + (encode_and_parse_url(url).fragment || '')).gsub(/\/\//, '/')
|
21
21
|
end
|
22
22
|
|
23
23
|
# Return a traditional URL from the fragment of <tt>url</tt>
|
24
24
|
def traditional_url_from_fragment(url)
|
25
|
-
url_host(url) + ('/' + (
|
25
|
+
url_host(url) + ('/' + (encode_and_parse_url(url).fragment || '')).gsub(/\/\//, '/')
|
26
26
|
end
|
27
27
|
|
28
28
|
# Return a hashed URL formed from a traditional <tt>url</tt>
|
29
29
|
def hashed_url_from_traditional(url)
|
30
|
-
uri =
|
30
|
+
uri = encode_and_parse_url(url)
|
31
31
|
hashed_url = url_host(url) + ('/#/' + (uri.path || '')).gsub(/\/\//, '/')
|
32
32
|
hashed_url += ('?' + uri.query) unless uri.query.nil?
|
33
33
|
hashed_url
|
34
34
|
end
|
35
35
|
|
36
36
|
protected
|
37
|
-
|
37
|
+
|
38
|
+
def encode_and_parse_url(url)
|
39
|
+
URI.parse(URI.encode(url).gsub("%23", "#"))
|
40
|
+
end
|
41
|
+
|
38
42
|
def url_host(url)
|
39
43
|
if url.match(/^(\w+\:\/\/[^\/]+)\/?/)
|
40
44
|
$1
|
Binary file
|
data/public/javascripts/ajax.js
CHANGED
@@ -176,50 +176,77 @@ var AjaxAssets = function(array, type) {
|
|
176
176
|
*
|
177
177
|
* Options:
|
178
178
|
* <tt>enabled</tt> boolean indicating whether the plugin is enabled.
|
179
|
-
*
|
180
|
-
*
|
179
|
+
* Callbacks that you set in the Ajax-Info header or directly on
|
180
|
+
* this instance will still be executed. They will not be queued,
|
181
|
+
* the will be executed immediately.
|
181
182
|
*
|
182
183
|
* <tt>default_container</tt> string jQuery selector of the default
|
183
184
|
* container element to receive content.
|
184
185
|
*
|
186
|
+
* <tt>lazy_load_assets</tt> boolean indicating whether to enable
|
187
|
+
* lazy loading assets. If this is disabled, callbacks will be
|
188
|
+
* executed immediately.
|
189
|
+
*
|
190
|
+
* <tt>show_loading_image</tt> (default true) boolean indicating whether
|
191
|
+
* to show the loading image.
|
192
|
+
*
|
193
|
+
* <tt>loading_image</tt> (optional) string jQuery selector of an
|
194
|
+
* existing image to show while pages are loading. If not set the default
|
195
|
+
* selector is: img#ajax-loading
|
196
|
+
*
|
197
|
+
* <tt>loading_image_path</tt> (optional) string full path to the loading
|
198
|
+
* image. Used to append an image tag to the body element
|
199
|
+
* if an existing image is not found. Default: /images/ajax-loading.gif
|
200
|
+
*
|
201
|
+
* To customize image handling, override the <tt>showLoadingImage</tt> and
|
202
|
+
* <tt>hideLoadingImage</tt> methods.
|
203
|
+
*
|
185
204
|
* Callbacks:
|
186
205
|
*
|
187
|
-
* Callbacks can be specified using Ajax-Info{ callbacks: 'javascript to eval' },
|
188
|
-
* or by adding callbacks directly to the Ajax instance
|
206
|
+
* Callbacks can be specified using Ajax-Info{ callbacks: 'javascript to eval.' },
|
207
|
+
* or by adding callbacks directly to the Ajax instance.
|
208
|
+
*
|
209
|
+
* 'onLoad' callbacks are executed once new content has been inserted into the DOM,
|
210
|
+
* and after all assets have been loaded (if using lazy-loading). I.e. "on page load".
|
211
|
+
*
|
212
|
+
* For example:
|
189
213
|
*
|
190
214
|
* window.ajax.onLoad(function() { doSomething(args); });
|
191
215
|
*
|
192
|
-
*
|
216
|
+
* To add a callback to the front of the queue use:
|
193
217
|
*
|
218
|
+
* window.ajax.prependOnLoad(function() { doSomething(args); });
|
194
219
|
*
|
220
|
+
* KJV 2010-04-22: I've experienced problems with Safari using String callbacks. YMMV.
|
221
|
+
* Browser support for callbacks is patchy at this time so lazy-loading is
|
222
|
+
* not recommended.
|
195
223
|
*/
|
196
224
|
var Ajax = function(options) {
|
197
225
|
var self = this;
|
198
|
-
|
199
|
-
self.enabled = true;
|
200
|
-
self.default_container = undefined;
|
201
|
-
self.loaded_by_framework = false;
|
202
|
-
self.loading_icon = $('#loading-icon-small');
|
203
|
-
self.javascripts = undefined;
|
204
|
-
self.stylesheets = new AjaxAssets([], 'css');
|
205
|
-
self.callbacks = [];
|
206
|
-
self.loaded = false;
|
207
|
-
self.lazy_load_assets = false;
|
208
|
-
|
209
|
-
// For initial position of the loading icon. Often the mouse does not
|
210
|
-
// move so position it by the link that was clicked.
|
211
|
-
self.last_click_coords = undefined;
|
212
|
-
|
213
|
-
// Parse options
|
214
|
-
self.options = options;
|
215
|
-
self.default_container = options.default_container;
|
216
|
-
if (options.enabled !== undefined) {
|
217
|
-
self.enabled = options.enabled;
|
218
|
-
}
|
219
|
-
if (options.lazy_load_assets !== undefined) {
|
220
|
-
self.lazy_load_assets = options.lazy_load_assets;
|
221
|
-
}
|
222
226
|
|
227
|
+
/**
|
228
|
+
* Options
|
229
|
+
*/
|
230
|
+
self.options = {
|
231
|
+
enabled: true,
|
232
|
+
default_container: undefined,
|
233
|
+
loaded_by_framework: false,
|
234
|
+
show_loading_image: true,
|
235
|
+
loading_image: 'img#ajax-loading',
|
236
|
+
loading_image_path: '/images/ajax-loading.gif',
|
237
|
+
javascripts: undefined,
|
238
|
+
stylesheets: new AjaxAssets([], 'css'),
|
239
|
+
callbacks: [],
|
240
|
+
loaded: false,
|
241
|
+
lazy_load_assets: false,
|
242
|
+
|
243
|
+
// For initial position of the loading icon. Often the mouse does not
|
244
|
+
// move so position it by the link that was clicked.
|
245
|
+
last_click_coords: undefined
|
246
|
+
};
|
247
|
+
jQuery.extend(self.options, options);
|
248
|
+
jQuery.extend(self, self.options);
|
249
|
+
|
223
250
|
// Initialize on DOM ready
|
224
251
|
$(function() { self.init() });
|
225
252
|
|
@@ -234,10 +261,6 @@ var Ajax = function(options) {
|
|
234
261
|
$.address.history(true);
|
235
262
|
$.address.change = self.addressChanged;
|
236
263
|
|
237
|
-
// Insert loading image
|
238
|
-
var image = '<img src="/images/loading-icon-small.gif" id="loading-icon-small" alt="Loading..." />'
|
239
|
-
$(image).hide().appendTo($('body'));
|
240
|
-
|
241
264
|
// Bind a live event to all ajax-enabled links
|
242
265
|
$('a[data-deep-link]').live('click', self.linkClicked);
|
243
266
|
|
@@ -328,9 +351,9 @@ var Ajax = function(options) {
|
|
328
351
|
beforeSend: self.setRequestHeaders,
|
329
352
|
success: self.responseHandler,
|
330
353
|
complete: function(XMLHttpRequest, responseText) {
|
331
|
-
//
|
332
|
-
$(document).
|
333
|
-
|
354
|
+
// Scroll to the top of the page.
|
355
|
+
$(document).scrollTop(0);
|
356
|
+
self.hideLoadingImage();
|
334
357
|
self.loaded = true;
|
335
358
|
},
|
336
359
|
error: function(XMLHttpRequest, textStatus, errorThrown) {
|
@@ -504,11 +527,30 @@ var Ajax = function(options) {
|
|
504
527
|
return data;
|
505
528
|
};
|
506
529
|
|
530
|
+
/**
|
531
|
+
* Hide the loading image.
|
532
|
+
*
|
533
|
+
* Stop watching the mouse position.
|
534
|
+
*/
|
535
|
+
self.hideLoadingImage = function() {
|
536
|
+
if (!self.show_loading_image) { return; }
|
537
|
+
$(document).unbind('mousemove', self.updateImagePosition);
|
538
|
+
$(self.loading_image).hide();
|
539
|
+
};
|
540
|
+
|
507
541
|
/**
|
508
542
|
* Show the loading image.
|
509
543
|
*/
|
510
544
|
self.showLoadingImage = function() {
|
511
|
-
|
545
|
+
if (!self.show_loading_image) { return; }
|
546
|
+
|
547
|
+
var icon = $(self.loading_image);
|
548
|
+
|
549
|
+
// Create the image if it doesn't exist
|
550
|
+
if (icon.size() == 0) {
|
551
|
+
$('<img src="'+ self.loading_image_path +'" id="ajax-loading" alt="Loading..." />').hide().appendTo($('body'));
|
552
|
+
icon = $(self.loading_image);
|
553
|
+
}
|
512
554
|
|
513
555
|
// Follow the mouse pointer
|
514
556
|
$(document).bind('mousemove', self.updateImagePosition);
|
@@ -540,7 +582,7 @@ var Ajax = function(options) {
|
|
540
582
|
* Update the position of the loading icon.
|
541
583
|
*/
|
542
584
|
self.updateImagePosition = function(e) {
|
543
|
-
$(
|
585
|
+
$(self.loading_image).css({
|
544
586
|
zIndex: 99,
|
545
587
|
position: 'absolute',
|
546
588
|
top: e.pageY + 14,
|
@@ -548,7 +590,6 @@ var Ajax = function(options) {
|
|
548
590
|
});
|
549
591
|
};
|
550
592
|
|
551
|
-
|
552
593
|
/**
|
553
594
|
* onLoad
|
554
595
|
*
|
@@ -625,4 +666,26 @@ var Ajax = function(options) {
|
|
625
666
|
self.teaser = function(callback) {
|
626
667
|
return new String(callback).slice(0,50);
|
627
668
|
};
|
669
|
+
|
670
|
+
/**
|
671
|
+
* Escape all special jQuery CSS selector characters in *selector*.
|
672
|
+
* Useful when you have a class or id which contains special characters
|
673
|
+
* which you need to include in a selector.
|
674
|
+
*/
|
675
|
+
self.escapeSelector = (function() {
|
676
|
+
var specials = [
|
677
|
+
'#', '&', '~', '=', '>',
|
678
|
+
"'", ':', '"', '!', ';', ','
|
679
|
+
];
|
680
|
+
var regexSpecials = [
|
681
|
+
'.', '*', '+', '|', '[', ']', '(', ')', '/', '^', '$'
|
682
|
+
];
|
683
|
+
var sRE = new RegExp(
|
684
|
+
'(' + specials.join('|') + '|\\' + regexSpecials.join('|\\') + ')', 'g'
|
685
|
+
);
|
686
|
+
|
687
|
+
return function(selector) {
|
688
|
+
return selector.replace(sRE, '\\$1');
|
689
|
+
}
|
690
|
+
})();
|
628
691
|
};
|
data/rails/install.rb
CHANGED
@@ -8,7 +8,7 @@ AJAX_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
|
8
8
|
public/javascripts/jquery.address-1.2rc.js
|
9
9
|
public/javascripts/jquery.address-1.2rc.min.js
|
10
10
|
public/javascripts/jquery.json-2.2.min.js
|
11
|
-
public/images/loading
|
11
|
+
public/images/ajax-loading.gif
|
12
12
|
].each do |file|
|
13
13
|
if File.exist?(File.join(Rails.root, file))
|
14
14
|
puts "skipped: #{file} exists!"
|
data/spec/ajax/helpers_spec.rb
CHANGED
@@ -16,6 +16,11 @@ context 'Ajax::UrlHelpers' do
|
|
16
16
|
Ajax.hashed_url_from_traditional('/Beyonce').should == '/#/Beyonce'
|
17
17
|
end
|
18
18
|
|
19
|
+
it "should handle special characters" do
|
20
|
+
Ajax.hashed_url_from_traditional('/beyoncé').should == '/#/beyonc%C3%A9'
|
21
|
+
Ajax.hashed_url_from_traditional('/red hot').should == '/#/red%20hot'
|
22
|
+
end
|
23
|
+
|
19
24
|
DOMAINS.each do |domain|
|
20
25
|
it "should work for domain #{domain}" do
|
21
26
|
Ajax.hashed_url_from_traditional("http://#{domain}/playlists").should == "http://#{domain}/#/playlists"
|
@@ -28,6 +33,11 @@ context 'Ajax::UrlHelpers' do
|
|
28
33
|
Ajax.hashed_url_from_fragment('/Beyonce#/Akon').should == '/#/Akon'
|
29
34
|
Ajax.hashed_url_from_fragment('/Beyonce#Akon').should == '/#/Akon'
|
30
35
|
end
|
36
|
+
|
37
|
+
it "should handle special characters" do
|
38
|
+
Ajax.hashed_url_from_fragment('/#/beyoncé').should == '/#/beyonc%C3%A9'
|
39
|
+
Ajax.hashed_url_from_fragment('/#/red hot').should == '/#/red%20hot'
|
40
|
+
end
|
31
41
|
|
32
42
|
it "should handle no fragment" do
|
33
43
|
Ajax.hashed_url_from_fragment('/Beyonce').should == '/#/'
|
@@ -46,6 +56,7 @@ context 'Ajax::UrlHelpers' do
|
|
46
56
|
it "should detect root urls" do
|
47
57
|
Ajax.url_is_root?('/#/Beyonce?query2').should be(true)
|
48
58
|
Ajax.url_is_root?('/').should be(true)
|
59
|
+
Ajax.url_is_root?('/#/beyoncé'). should be(true)
|
49
60
|
end
|
50
61
|
|
51
62
|
it "should detect non-root urls" do
|
@@ -55,6 +66,10 @@ context 'Ajax::UrlHelpers' do
|
|
55
66
|
it "should support full URLs" do
|
56
67
|
Ajax.is_hashed_url?('http://musicsocial.com.local/#/playlists').should be(true)
|
57
68
|
end
|
69
|
+
|
70
|
+
it "should support special characters" do
|
71
|
+
Ajax.is_hashed_url?('http://musicsocial.com.local/#/beyoncé').should be(true)
|
72
|
+
end
|
58
73
|
end
|
59
74
|
|
60
75
|
describe "(boolean) is_hashed_url?" do
|
@@ -88,7 +103,12 @@ context 'Ajax::UrlHelpers' do
|
|
88
103
|
end
|
89
104
|
|
90
105
|
it "should handle no fragment" do
|
91
|
-
Ajax.traditional_url_from_fragment('/Beyonce').should == '/'
|
106
|
+
Ajax.traditional_url_from_fragment('/Beyonce#/beyoncé').should == '/beyonc%C3%A9'
|
107
|
+
Ajax.traditional_url_from_fragment('/#/red hot').should == '/red%20hot'
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should handle special characters" do
|
111
|
+
Ajax.traditional_url_from_fragment('/Beyonce#/Akon').should == '/Akon'
|
92
112
|
end
|
93
113
|
|
94
114
|
DOMAINS.each do |domain|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ajax
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karl Varga
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-04-
|
12
|
+
date: 2010-04-22 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -53,8 +53,7 @@ files:
|
|
53
53
|
- lib/rack-ajax.rb
|
54
54
|
- lib/rack-ajax/decision_tree.rb
|
55
55
|
- lib/rack-ajax/parser.rb
|
56
|
-
- public/images/loading
|
57
|
-
- public/images/loading-icon-small.gif
|
56
|
+
- public/images/ajax-loading.gif
|
58
57
|
- public/javascripts/ajax.js
|
59
58
|
- public/javascripts/jquery.address-1.1.js
|
60
59
|
- public/javascripts/jquery.address-1.1.min.js
|
Binary file
|
Binary file
|