ajax 0.1.2 → 0.1.3

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.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.1.3
data/lib/ajax.rb CHANGED
@@ -25,7 +25,10 @@ module Ajax
25
25
  def self.is_enabled?
26
26
  @enabled.nil? ? true : !!@enabled
27
27
  end
28
-
28
+ class << self
29
+ alias_method :enabled?, :is_enabled?
30
+ end
31
+
29
32
  # Set to false to disable this plugin completely.
30
33
  #
31
34
  # ActionController and ActionView helpers are still mixed in but
@@ -35,6 +38,24 @@ module Ajax
35
38
  @enabled = !!value
36
39
  end
37
40
 
41
+ # Return a boolean indicating whether to enable lazy loading assets.
42
+ # There are currently issues with some browsers when using this feature.
43
+ #
44
+ # Disabled by default.
45
+ def self.lazy_load_assets?
46
+ @lazy_load_assets.nil? ? false : !!@lazy_load_assets
47
+ end
48
+
49
+ # Set to false to disable lazy loading assets. Callbacks will
50
+ # be executed immediately.
51
+ #
52
+ # ActionController and ActionView helpers are still mixed in but
53
+ # they are effectively disabled, which means your code will still
54
+ # run.
55
+ def self.lazy_load_assets=(value)
56
+ @lazy_load_assets = !!value
57
+ end
58
+
38
59
  # Return a boolean indicating whether the plugin is being mock tested.
39
60
  #
40
61
  # Mocking forces the environment to be returned after Ajax processing
@@ -1,3 +1,5 @@
1
+ require 'json'
2
+
1
3
  module Ajax
2
4
  module Helpers
3
5
  module RequestHelper
@@ -15,33 +17,45 @@ module Ajax
15
17
  # Hash and/or Array values are merged so you can set multiple values
16
18
  def set_header(object, key, value)
17
19
  headers = object.is_a?(::ActionController::Response) ? object.headers : object
18
- unless headers["Ajax-Info"].is_a?(Hash)
19
- headers["Ajax-Info"] = {}
20
+
21
+ info = case headers["Ajax-Info"]
22
+ when String
23
+ JSON.parse(headers["Ajax-Info"])
24
+ when Hash
25
+ headers["Ajax-Info"]
26
+ else
27
+ {}
20
28
  end
21
29
 
22
30
  # Deep merge hashes
23
- if headers["Ajax-Info"].has_key?(key.to_s) &&
31
+ if info.has_key?(key.to_s) &&
24
32
  value.is_a?(Hash) &&
25
- headers["Ajax-Info"][key.to_s].is_a?(Hash)
26
- value = headers["Ajax-Info"][key.to_s].merge(value, &DEEP_MERGE)
33
+ info[key.to_s].is_a?(Hash)
34
+ value = info[key.to_s].merge(value, &DEEP_MERGE)
27
35
  end
28
36
 
29
37
  # Concat arrays
30
- if headers["Ajax-Info"].has_key?(key.to_s) &&
38
+ if info.has_key?(key.to_s) &&
31
39
  value.is_a?(Array) &&
32
- headers["Ajax-Info"][key.to_s].is_a?(Array)
33
- value = headers["Ajax-Info"][key.to_s].concat(value)
40
+ info[key.to_s].is_a?(Array)
41
+ value = info[key.to_s].concat(value)
34
42
  end
35
43
 
36
- headers["Ajax-Info"][key.to_s] = value
44
+ info[key.to_s] = value
45
+ headers["Ajax-Info"] = info.to_json
37
46
  end
38
47
 
39
48
  def get_header(object, key)
40
49
  headers = object.is_a?(::ActionController::Request) ? object.headers : object
41
- unless headers["Ajax-Info"].is_a?(Hash)
42
- headers["Ajax-Info"] = {}
50
+ info = case headers["Ajax-Info"]
51
+ when String
52
+ JSON.parse(headers["Ajax-Info"])
53
+ when Hash
54
+ headers["Ajax-Info"]
55
+ else
56
+ {}
43
57
  end
44
- headers['Ajax-Info'][key.to_s]
58
+ info[key.to_s]
45
59
  end
46
60
 
47
61
  # Set one or more paths that can be accessed directly without the AJAX framework.
@@ -1,3 +1,64 @@
1
+ /**
2
+ * Script lazy loader 0.5
3
+ * Copyright (c) 2008 Bob Matsuoka
4
+ *
5
+ * This program is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU General Public License
7
+ * as published by the Free Software Foundation; either version 2
8
+ * of the License, or (at your option) any later version.
9
+ */
10
+
11
+ var LazyLoader = {}; //namespace
12
+ LazyLoader.timer = {}; // contains timers for scripts
13
+ LazyLoader.scripts = []; // contains called script references
14
+ LazyLoader.load = function(url, callback) {
15
+ // handle object or path
16
+ var classname = null;
17
+ var properties = null;
18
+ try {
19
+ // make sure we only load once
20
+ if (LazyLoader.scripts.indexOf(url) == -1) {
21
+ // note that we loaded already
22
+ LazyLoader.scripts.push(url);
23
+ var script = document.createElement("script");
24
+ script.src = url;
25
+ script.type = "text/javascript";
26
+ $(script).appendTo("head"); // add script tag to head element
27
+
28
+ // was a callback requested
29
+ if (callback) {
30
+ // test for onreadystatechange to trigger callback
31
+ script.onreadystatechange = function () {
32
+ if (script.readyState == 'loaded' || script.readyState == 'complete') {
33
+ callback();
34
+ }
35
+ };
36
+
37
+ // test for onload to trigger callback
38
+ script.onload = function () {
39
+ callback();
40
+ return;
41
+ };
42
+
43
+ // safari doesn't support either onload or readystate, create a timer
44
+ // only way to do this in safari
45
+ if (($.browser.webkit && !navigator.userAgent.match(/Version\/3/)) || $.browser.opera) { // sniff
46
+ LazyLoader.timer[url] = setInterval(function() {
47
+ if (/loaded|complete/.test(document.readyState)) {
48
+ clearInterval(LazyLoader.timer[url]);
49
+ callback(); // call the callback handler
50
+ }
51
+ }, 10);
52
+ }
53
+ }
54
+ } else {
55
+ if (callback) { callback(); }
56
+ }
57
+ } catch (e) {
58
+ alert(e);
59
+ }
60
+ }
61
+
1
62
  /**
2
63
  * AjaxAssets
3
64
  *
@@ -28,22 +89,28 @@ var AjaxAssets = function(array, type) {
28
89
  addAsset: function(path) {
29
90
  this.push(this.sanitizePath(path));
30
91
  },
31
-
92
+
32
93
  /**
33
94
  * Load and add an asset. The asset is loaded using the
34
95
  * unsanitized path should you need to put something in the
35
96
  * query string.
36
97
  */
37
- loadAsset: function(path) {
98
+ loadAsset: function(path, callback) {
38
99
  console.log('[ajax] loading', type, path);
39
100
  this.push(this.sanitizePath(path));
40
- this.appendScriptTag(path);
101
+ if (type == 'css') {
102
+ this.appendScriptTag(path, callback);
103
+ } else if ($.browser.msie || $.browser.mozilla) {
104
+ this.appendScriptTag(path, callback);
105
+ } else {
106
+ LazyLoader.load(path, callback);
107
+ }
41
108
  },
42
109
 
43
110
  /**
44
111
  * Return a boolean indicating whether an asset has
45
112
  * already been loaded.
46
- */
113
+ */
47
114
  loadedAsset: function(path) {
48
115
  path = this.sanitizePath(path);
49
116
  for (var i=0; i < this.length; i++) {
@@ -51,47 +118,45 @@ var AjaxAssets = function(array, type) {
51
118
  return true;
52
119
  }
53
120
  }
54
- return false;
121
+ return false;
55
122
  },
56
123
 
57
124
  /**
58
125
  * Remove query strings and otherwise cleanup paths
59
126
  * before adding them.
60
- */
127
+ */
61
128
  sanitizePath: function(path) {
62
129
  return path.replace(/\?.*/, '');
63
130
  },
64
-
131
+
65
132
  /**
66
133
  * Supports debugging and references the script files as external resources
67
134
  * rather than inline.
68
135
  *
69
136
  * @see http://stackoverflow.com/questions/690781/debugging-scripts-added-via-jquery-getscript-function
70
- */
137
+ */
71
138
  appendScriptTag: function(url, callback) {
72
139
  if (type == 'js') {
73
140
  var head = document.getElementsByTagName("head")[0];
74
141
  var script = document.createElement("script");
75
142
  script.src = url;
76
143
  script.type = 'text/javascript'
77
-
78
- { // Handle Script loading
144
+ head.appendChild(script);
145
+ // Handle Script loading
146
+ if (callback) {
79
147
  var done = false;
80
-
81
- // Attach handlers for all browsers
82
148
  script.onload = script.onreadystatechange = function(){
83
149
  if ( !done && (!this.readyState ||
84
150
  this.readyState == "loaded" || this.readyState == "complete") ) {
85
151
  done = true;
86
152
  if (callback)
87
153
  callback();
88
-
154
+
89
155
  // Handle memory leak in IE
90
156
  script.onload = script.onreadystatechange = null;
91
157
  }
92
158
  };
93
- }
94
- head.appendChild(script);
159
+ }
95
160
  } else if (type == 'css') {
96
161
  if (url.match(/datauri/)) {
97
162
  $(DATA_URI_START + '<link type="text/css" rel="stylesheet" href="'+ url +'">' + DATA_URI_END).appendTo('head');
@@ -102,7 +167,7 @@ var AjaxAssets = function(array, type) {
102
167
  }
103
168
  }
104
169
  return undefined;
105
- }
170
+ }
106
171
  });
107
172
  };
108
173
 
@@ -114,20 +179,20 @@ var AjaxAssets = function(array, type) {
114
179
  * This must be set if you are using Ajax callbacks in your code,
115
180
  * and you want them to still fire if Ajax is not enabled.
116
181
  *
117
- * <tt>default_container</tt> string jQuery selector of the default
182
+ * <tt>default_container</tt> string jQuery selector of the default
118
183
  * container element to receive content.
119
184
  *
120
185
  * Callbacks:
121
186
  *
122
187
  * Callbacks can be specified using Ajax-Info{ callbacks: 'javascript to eval' },
123
188
  * or by adding callbacks directly to the Ajax instance:
124
- *
189
+ *
125
190
  * window.ajax.onLoad(function() { doSomething(args); });
126
191
  *
127
192
  * Order of execution:
128
193
  *
129
194
  *
130
- */
195
+ */
131
196
  var Ajax = function(options) {
132
197
  var self = this;
133
198
 
@@ -139,28 +204,32 @@ var Ajax = function(options) {
139
204
  self.stylesheets = new AjaxAssets([], 'css');
140
205
  self.callbacks = [];
141
206
  self.loaded = false;
207
+ self.lazy_load_assets = false;
142
208
 
143
209
  // For initial position of the loading icon. Often the mouse does not
144
210
  // move so position it by the link that was clicked.
145
211
  self.last_click_coords = undefined;
146
212
 
147
213
  // Parse options
148
- self.options = options;
214
+ self.options = options;
149
215
  self.default_container = options.default_container;
150
216
  if (options.enabled !== undefined) {
151
217
  self.enabled = options.enabled;
152
218
  }
153
-
219
+ if (options.lazy_load_assets !== undefined) {
220
+ self.lazy_load_assets = options.lazy_load_assets;
221
+ }
222
+
154
223
  // Initialize on DOM ready
155
224
  $(function() { self.init() });
156
-
225
+
157
226
  /**
158
227
  * Initializations run on DOM ready.
159
228
  *
160
229
  * Bind event handlers and setup jQuery Address.
161
230
  */
162
231
  self.init = function() {
163
-
232
+
164
233
  // Configure jQuery Address
165
234
  $.address.history(true);
166
235
  $.address.change = self.addressChanged;
@@ -168,21 +237,21 @@ var Ajax = function(options) {
168
237
  // Insert loading image
169
238
  var image = '<img src="/images/loading-icon-small.gif" id="loading-icon-small" alt="Loading..." />'
170
239
  $(image).hide().appendTo($('body'));
171
-
240
+
172
241
  // Bind a live event to all ajax-enabled links
173
242
  $('a[data-deep-link]').live('click', self.linkClicked);
174
-
243
+
175
244
  // Initialize the list of javascript assets
176
245
  if (self.javascripts === undefined) {
177
246
  self.javascripts = new AjaxAssets([], 'js');
178
-
247
+
179
248
  $(document).find('script[type=text/javascript][src!=]').each(function() {
180
249
  var script = $(this);
181
250
  var src = script.attr('src');
182
-
251
+
183
252
  // Local scripts only
184
253
  if (src.match(/^\//)) {
185
-
254
+
186
255
  // Parse parameters passed to the script via the query string.
187
256
  // TODO: Untested. It's difficult for us to use this with Jammit.
188
257
  if (src.match(/\Wajax.js\?.+/)) {
@@ -190,7 +259,7 @@ var Ajax = function(options) {
190
259
  jQuery.each(params, function(idx, param) {
191
260
  param = param.split('=');
192
261
  if (param.length == 1) { return true; }
193
-
262
+
194
263
  switch(param[0]) {
195
264
  case 'enabled':
196
265
  self.enabled = param[1] == 'false' ? false : true;
@@ -203,33 +272,33 @@ var Ajax = function(options) {
203
272
  }
204
273
  });
205
274
  }
206
-
275
+
207
276
  self.javascripts.addAsset(script.attr('src'));
208
277
  }
209
278
  });
210
279
  }
211
280
  self.initialized = true;
212
-
281
+
213
282
  // Run onInit() callbacks
214
283
  };
215
-
284
+
216
285
  /**
217
286
  * jQuery Address callback triggered when the address changes.
218
287
  */
219
288
  self.addressChanged = function() {
220
289
  if (document.location.pathname != '/') { return false; }
221
-
222
- if (typeof(self.loaded_by_framework) == 'undefined' || self.loaded_by_framework != true) {
290
+ if (window.ajax.disable_address_intercept == true) {return false;}
291
+ if (typeof(self.loaded_by_framework) == 'undefined' || self.loaded_by_framework != true) {
223
292
  self.loaded_by_framework = true;
224
- return false;
225
- }
226
-
227
- self.loadPage({
293
+ return false;
294
+ }
295
+
296
+ self.loadPage({
228
297
  url: $.address.value().replace(/\/\//, '/')
229
298
  });
230
299
  return true;
231
300
  };
232
-
301
+
233
302
  /**
234
303
  * loadPage
235
304
  *
@@ -246,7 +315,7 @@ var Ajax = function(options) {
246
315
  * Cookies in the response are automatically set on the document.cookie.
247
316
  */
248
317
  self.loadPage = function(options) {
249
- if (!self.enabled) {
318
+ if (!self.enabled) {
250
319
  document.location = options.url;
251
320
  return true;
252
321
  }
@@ -343,16 +412,16 @@ var Ajax = function(options) {
343
412
  console.log('Using page title '+data.title);
344
413
  $.address.title(data.title);
345
414
  }
346
-
415
+
347
416
  if (data.tab !== undefined) {
348
417
  console.log('Activating tab '+data.tab);
349
418
  $(data.tab).trigger('activate');
350
419
  }
351
-
420
+
352
421
  /**
353
- * Load assets
422
+ * Load stylesheets
354
423
  */
355
- if (data.assets !== undefined && data.assets.stylesheets !== undefined) {
424
+ if (self.lazy_load_assets && data.assets && data.assets.stylesheets !== undefined) {
356
425
  jQuery.each(jQuery.makeArray(data.assets.stylesheets), function(idx, url) {
357
426
  if (self.stylesheets.loadedAsset(url)) {
358
427
  console.log('[ajax] skipping css', url);
@@ -362,17 +431,6 @@ var Ajax = function(options) {
362
431
  }
363
432
  });
364
433
  }
365
-
366
- if (data.assets !== undefined && data.assets.javascripts !== undefined) {
367
- jQuery.each(jQuery.makeArray(data.assets.javascripts), function(idx, url) {
368
- if (self.javascripts.loadedAsset(url)) {
369
- console.log('[ajax] skipping js', url);
370
- return true;
371
- } else {
372
- self.javascripts.loadAsset(url);
373
- }
374
- });
375
- }
376
434
 
377
435
  /**
378
436
  * Insert response
@@ -381,30 +439,49 @@ var Ajax = function(options) {
381
439
  console.log('Set data ',data);
382
440
  container.data('ajax-info', data)
383
441
  container.html(responseText);
384
-
442
+
385
443
  /**
386
- * Execute callbacks
444
+ * Include callbacks from Ajax-Info
387
445
  */
388
- if (data.callbacks !== undefined) {
389
- jQuery.each(jQuery.makeArray(data.callbacks), function(idx, callback) {
390
- self.executeCallback(callback);
391
- });
446
+ if (data.callbacks) {
447
+ data.callbacks = jQuery.makeArray(data.callbacks);
448
+ self.callbacks.concat(data.callbacks);
392
449
  }
393
-
394
- if (self.callbacks.length > 0) {
395
- jQuery.each(self.callbacks, function(idx, callback) {
396
- self.executeCallback(callback);
450
+
451
+ /**
452
+ * Load javascipts
453
+ */
454
+ if (self.lazy_load_assets && data.assets && data.assets.javascripts !== undefined) {
455
+ var count = data.assets.javascripts.length;
456
+ var callback;
457
+
458
+ jQuery.each(jQuery.makeArray(data.assets.javascripts), function(idx, url) {
459
+ if (self.javascripts.loadedAsset(url)) {
460
+ console.log('[ajax] skipping js', url);
461
+ return true;
462
+ }
463
+
464
+ // Execute callbacks once the last asset has loaded
465
+ callback = (idx == count - 1) ? undefined : self.executeCallbacks;
466
+ self.javascripts.loadAsset(url, callback);
397
467
  });
398
- self.callbacks = [];
468
+ } else {
469
+ // Execute callbacks immediately
470
+ self.executeCallbacks();
399
471
  }
400
-
472
+
473
+ $(document).trigger('ajax.onload');
474
+
401
475
  /**
402
- * Set cookies
476
+ * Set cookies - browsers don't seem to allow this
403
477
  */
404
- var cookie = XMLHttpRequest.getResponseHeader('Set-Cookie');
405
- if (cookie !== null) {
406
- console.log('Setting cookie');
407
- document.cookie = cookie;
478
+ try {
479
+ var cookie = XMLHttpRequest.getResponseHeader('Set-Cookie');
480
+ if (cookie !== null) {
481
+ console.log('Setting cookie');
482
+ document.cookie = cookie;
483
+ }
484
+ } catch(e) {
408
485
  }
409
486
  };
410
487
 
@@ -432,28 +509,33 @@ var Ajax = function(options) {
432
509
  */
433
510
  self.showLoadingImage = function() {
434
511
  var icon = $('#loading-icon-small');
435
-
512
+
436
513
  // Follow the mouse pointer
437
514
  $(document).bind('mousemove', self.updateImagePosition);
438
-
515
+
439
516
  // Display at last click coords initially
440
517
  if (self.last_click_coords !== undefined) {
441
518
  self.updateImagePosition(self.last_click_coords);
442
-
519
+
443
520
  // Center it
444
521
  } else {
522
+ var marginTop = parseInt(icon.css('marginTop'), 10);
523
+ var marginLeft = parseInt(icon.css('marginLeft'), 10);
524
+ marginTop = isNaN(marginTop) ? 0 : marginTop;
525
+ marginLeft = isNaN(marginLeft) ? 0 : marginLeft;
526
+
445
527
  icon.css({
446
- position: 'absolute',
447
- left: '50%',
448
- top: '50%',
449
- zIndex: '99',
450
- marginTop: parseInt(icon.css('marginTop'), 10) + jQuery(window).scrollTop(),
451
- marginLeft: parseInt(icon.css('marginLeft'), 10) + jQuery(window).scrollLeft()
452
- });
453
- }
454
- icon.show();
528
+ position: 'absolute',
529
+ left: '50%',
530
+ top: '50%',
531
+ zIndex: '99',
532
+ marginTop: marginTop + jQuery(window).scrollTop(),
533
+ marginLeft: marginLeft + jQuery(window).scrollLeft()
534
+ });
535
+ }
536
+ icon.show();
455
537
  };
456
-
538
+
457
539
  /**
458
540
  * Update the position of the loading icon.
459
541
  */
@@ -466,7 +548,7 @@ var Ajax = function(options) {
466
548
  });
467
549
  };
468
550
 
469
-
551
+
470
552
  /**
471
553
  * onLoad
472
554
  *
@@ -478,9 +560,9 @@ var Ajax = function(options) {
478
560
  * on DOM ready.
479
561
  */
480
562
  self.onLoad = function(callback) {
481
- if (self.enabled && !self.loaded) {
563
+ if (self.enabled && (self.lazy_load_assets && !self.loaded)) {
482
564
  self.callbacks.push(callback);
483
- console.log('[ajax] appending callback', callback);
565
+ console.log('[ajax] appending callback', self.teaser(callback));
484
566
  } else {
485
567
  self.executeCallback(callback, true);
486
568
  }
@@ -494,14 +576,27 @@ var Ajax = function(options) {
494
576
  * @see onLoad
495
577
  */
496
578
  self.prependOnLoad = function(callback) {
497
- if (self.enabled && !self.loaded) {
579
+ if (self.enabled && (self.lazy_load_assets && !self.loaded)) {
498
580
  self.callbacks.unshift(callback);
499
- console.log('[ajax] prepending callback', callback);
581
+ console.log('[ajax] prepending callback', self.teaser(callback));
500
582
  } else {
501
583
  self.executeCallback(callback, true);
502
584
  }
503
585
  };
504
-
586
+
587
+ /**
588
+ * Execute callbacks
589
+ */
590
+ self.executeCallbacks = function() {
591
+ var callbacks = jQuery.makeArray(self.callbacks);
592
+ if (callbacks.length > 0) {
593
+ jQuery.each(callbacks, function(idx, callback) {
594
+ self.executeCallback(callback);
595
+ });
596
+ self.callbacks = [];
597
+ }
598
+ };
599
+
505
600
  /**
506
601
  * Execute a callback given as a string or function reference.
507
602
  *
@@ -513,8 +608,8 @@ var Ajax = function(options) {
513
608
  $(function() {
514
609
  self.executeCallback(callback);
515
610
  })
516
- } else {
517
- console.log('[ajax] executing callback', callback);
611
+ } else {
612
+ console.log('[ajax] executing callback', self.teaser(callback));
518
613
  try {
519
614
  if (jQuery.isFunction(callback)) {
520
615
  callback();
@@ -524,6 +619,10 @@ var Ajax = function(options) {
524
619
  } catch(e) {
525
620
  console.log('[ajax] callback failed with exception', e);
526
621
  }
527
- }
528
- };
622
+ }
623
+ };
624
+
625
+ self.teaser = function(callback) {
626
+ return new String(callback).slice(0,50);
627
+ };
529
628
  };
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.2
4
+ version: 0.1.3
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-20 00:00:00 -07:00
12
+ date: 2010-04-21 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency