mera 0.1.9 → 0.3.0

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.
@@ -1,141 +1,950 @@
1
- /**
2
- *
3
- * My Easy Rails Ajax
4
- * Open under GPL (General Public License)
5
- * Author Richard Hutta 2012
6
- *
7
- */
8
1
 
2
+ (function($, undefined) {
9
3
 
10
- $(function(){
4
+ /**
5
+ * = Jquery_Ujs
6
+ *
7
+ * Unobtrusive scripting adapter for jQuery
8
+ *
9
+ * Requires jQuery 1.6.0 or later.
10
+ * https://github.com/rails/jquery-ujs
11
+ *
12
+ * =========================================
13
+ *
14
+ * = Pjax
15
+ *
16
+ * Pjax, loads HTML from your server into the current page without a full reload. It's ajax with real
17
+ * permalinks, page titles, and a working back button that fully degrades.
18
+ *
19
+ * Requires jQuery 1.7.0 or later.
20
+ * https://github.com/defunkt/jquery-pjax
21
+ *
22
+ * =========================================
23
+ *
24
+ * = Mera
25
+ *
26
+ * Is technology what combine classic Jquery_Ujs (only core) and Pjax (only core), together
27
+ *
28
+ * https://github.com/huttarichard/Mera
29
+ *
30
+ * =========================================
31
+ *
32
+ * Each project is open under Mit license
33
+ *
34
+ *
35
+ * Copyright (c) Mera 2012 & Pjax 2012 & Jquery_Ujs 2012
36
+ *
37
+ * Permission is hereby granted, free of charge, to any person
38
+ * obtaining a copy of this software and associated documentation
39
+ * files (the "Software"), to deal in the Software without
40
+ * restriction, including without limitation the rights to use,
41
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
42
+ * copies of the Software, and to permit persons to whom the
43
+ * Software is furnished to do so, subject to the following
44
+ * conditions:
45
+ *
46
+ * The above copyright notice and this permission notice shall be
47
+ * included in all copies or substantial portions of the Software.
48
+ *
49
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
50
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
51
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
52
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
53
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
54
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
55
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
56
+ * OTHER DEALINGS IN THE SOFTWARE.
57
+ *
58
+ */
11
59
 
12
- $.mera = {
13
- init: function(options){
14
- return $('a[data-skip-mera]').mera(options);
60
+ // Cut down on the number if issues from people inadvertently including jquery_ujs twice
61
+ // by detecting and raising an error when it happens.
62
+ var alreadyInitialized = function() {
63
+ var events = $._data(document, 'events');
64
+ return events && events.click && $.grep(events.click, function(e) { return e.namespace === 'rails'; }).length;
65
+ };
66
+
67
+ if ( alreadyInitialized() ) {
68
+ $.error('jquery-ujs has already been loaded!');
69
+ }
70
+
71
+ // Shorthand to make it a little easier to call public rails functions from within rails.js
72
+ var rails;
73
+ var cacheMapping = {};
74
+ var cacheForwardStack = [];
75
+ var cacheBackStack = [];
76
+ var mera = {};
77
+
78
+ $.rails = rails = {
79
+ // Link elements bound by jquery-ujs
80
+ linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote], a[data-disable-with]',
81
+
82
+ // Select elements bound by jquery-ujs
83
+ inputChangeSelector: 'select[data-remote], input[data-remote], textarea[data-remote]',
84
+
85
+ // Form elements bound by jquery-ujs
86
+ formSubmitSelector: 'form',
87
+
88
+ // Form input elements bound by jquery-ujs
89
+ formInputClickSelector: 'form input[type=submit], form input[type=image], form button[type=submit], form button:not([type])',
90
+
91
+ // Form input elements disabled during form submission
92
+ disableSelector: 'input[data-disable-with], button[data-disable-with], textarea[data-disable-with]',
93
+
94
+ // Form input elements re-enabled after form submission
95
+ enableSelector: 'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled',
96
+
97
+ // Form required input elements
98
+ requiredInputSelector: 'input[name][required]:not([disabled]),textarea[name][required]:not([disabled])',
99
+
100
+ // Form file input elements
101
+ fileInputSelector: 'input:file',
102
+
103
+ // Link onClick disable selector with possible reenable after remote submission
104
+ linkDisableSelector: 'a[data-disable-with]',
105
+
106
+ // Define location path
107
+ locationPath: location.pathname,
108
+
109
+ // Define location url
110
+ locationUrl: location.href,
111
+
112
+ // Define default container what will be updated
113
+ meraContainer: "body",
114
+
115
+ // Make sure that every Ajax request sends the CSRF token
116
+ CSRFProtection: function(xhr) {
117
+ var token = $('meta[name="csrf-token"]').attr('content');
118
+ if (token) xhr.setRequestHeader('X-CSRF-Token', token);
15
119
  },
16
120
 
17
- version: function(){
18
- return "0.1.8";
19
- }
20
- };
121
+ // Triggers an event on an element and returns false if the event result is false
122
+ fire: function(obj, name, data) {
123
+ var event = $.Event(name);
124
+ obj.trigger(event, data);
125
+ return event.result !== false;
126
+ },
21
127
 
22
- jQuery.fn.mera = function(options) {
23
- //get actual location
24
- $location = location.pathname;
25
- //get current url
26
- $absoluteUrl = location.href;
27
- //get this identifier
28
- $this = $(this);
29
- //get default options
30
- $default = {
31
- before : function(){$('body').hide();},
32
- after : function(){$('body').fadeIn();},
33
- error : function(xhr, status, error){alert(error);},
34
- confirme : function(question){return confirm(question);},
35
- compress: true
36
- };
37
- //get user options
38
- $options = $.extend({}, $default, options);
39
- //get if data-update-only
40
- $dataUpdateOnly = false;
41
-
42
- $this.click(function(){
43
- window.location.href = $(this).attr('href');
44
- });
128
+ // Default confirm dialog, may be overridden with custom confirm dialog in $.rails.confirm
129
+ confirm: function(message) {
130
+ return confirm(message);
131
+ },
45
132
 
46
- //handle a click
47
- $('a:not([data-remote=true])').click(function(){
48
- var hrefMera = $(this).attr('href');
133
+ // Default ajax function, may be overridden with custom function in $.rails.ajax
134
+ ajax: function(options) {
135
+ return $.ajax(options);
136
+ },
49
137
 
50
- if($(this).attr('data-method') !== undefined){
51
- $.rails.handleMethodRemote($(this));
138
+ // Default options for rails.ajax
139
+ ajaxDefault: {
140
+ timeout: 650,
141
+ push: true,
142
+ replace: false,
143
+ type: 'GET',
144
+ dataType: 'html',
145
+ scrollTo: 0,
146
+ maxCacheLength: 20
147
+ },
148
+
149
+ // Default way to get an element's href. May be overridden at $.rails.href.
150
+ href: function(element) {
151
+ return element.attr('href');
152
+ },
153
+
154
+ // Is mera supported?
155
+ // from pjax + custom mera
156
+ supportMera: function(){
157
+ return (window.history &&
158
+ window.history.pushState &&
159
+ window.history.replaceState &&
160
+ !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/));
161
+ },
162
+
163
+ // Get container for added element
164
+ // from pjax + custom mera
165
+ findContainerFor: function (container) {
166
+ container = $(container);
167
+
168
+ if (!container.length) {
169
+ throw "Mera have not container for '" + container.selector + "'!";
170
+ } else if (container.selector !== '' && container.context === document) {
171
+ return container;
172
+ } else if (container.attr('id')) {
173
+ return $('#' + container.attr('id'));
52
174
  } else {
53
- $.rails.handleRemote($(this));
175
+ throw "Can not get selector for Mera container!"
54
176
  }
177
+ },
55
178
 
56
- history.pushState({url: $location}, document.title, hrefMera);
179
+ // Find data in for or in element
180
+ // custom mera
181
+ findDataFor: function(element){
182
+ var object, method, _method, params, _params;
57
183
 
58
- return false
59
- });
184
+ if(element.is('form')){
185
+ object = element.find('input[name=ajaxParams]').val();
186
+ if(object && object.length)
187
+ eval('object = ' + object);
188
+ else
189
+ object = {};
60
190
 
61
- //handle all form
62
- $('form:not([data-remote=true])').on('submit', function(){
63
- $.rails.handleRemote($(this));
64
- return false
65
- });
191
+ object = $.extend(object, {
192
+ url: element.attr('action'),
193
+ method: element.attr('method'),
194
+ data: element.serialize()
195
+ });
196
+ } else {
197
+ object = {};
198
+ object.crossDomain = element.data('cross-domain');
199
+ object.withCredentials = element.data('with-credentials');
200
+ object.container = element.data('container');
201
+ object.event = element.data('event');
202
+ object.push = element.data('push');
203
+
204
+ method = element.data('method');
205
+ _method = method ? "_method=" + method + "&" : "";
206
+
207
+ params = element.data('params');
208
+ _params = params ? params : "";
209
+
210
+ object = $.extend(object, {
211
+ url: (rails.href(element) || element.data('url')),
212
+ method: method,
213
+ data: _method + _params
214
+ });
215
+ }
216
+
217
+ object.crossDomain = object.crossDomain || false;
218
+ object.withCredentials = object.withCredentials || false;
219
+ object.push = object.push == undefined ? object.url : object.push;
220
+ object.container = object.container !== undefined ? object.container : rails.meraContainer;
221
+ object.event = object.event ? 'ajax:' + object.event : false;
222
+
223
+ return object;
224
+ },
225
+
226
+ // Get link from url
227
+ // custom mera
228
+ getUrlElement: function (url) {
229
+ return $('<a/>', {href: url}).get(0);
230
+ },
231
+
232
+ // Filter data
233
+ // from pjax
234
+ findAll: function findAll(element, selector) {
235
+ return element.filter(selector).add(element.find(selector));
236
+ },
237
+
238
+ // Location replace
239
+ // from pjax + custom mera
240
+ locationReplace: function(url) {
241
+ window.history.replaceState(null, "", "/");
242
+ window.location.replace(url);
243
+ },
244
+
245
+ // Extract container for update
246
+ // from pjax + custom mera
247
+ extractContainer: function (data, xhr, options) {
248
+ var obj, $head, $body, $fragment;
66
249
 
67
- $(window).bind('popstate', function(event){
68
- if(location.href !== $absoluteUrl){
69
- window.location.replace(location.href);
250
+ obj = {};
251
+
252
+ // Prefer X-MERA-URL header if it was set, otherwise fallback to
253
+ // using the original requested url.
254
+ obj.url = (xhr.getResponseHeader('X-MERA-URL') || options.requestUrl);
255
+
256
+ // Attempt to parse response html into elements
257
+ if (/<html/i.test(data)) {
258
+ $head = $(data.match(/<head[^>]*>([\s\S.]*)<\/head>/i)[0]);
259
+ $body = $(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0]);
260
+ } else {
261
+ $head = $body = $(data);
70
262
  }
71
- });
72
263
 
73
- if ($.inArray('state', $.event.props) < 0){
74
- $.event.props.push('state');
75
- }
264
+ // If response data is empty, return fast
265
+ if ($body.length === 0)
266
+ return obj;
76
267
 
77
- $(window).on('ajax:beforeSend', function(event, xhr, settings) {
78
- $options.before();
79
- xhr.setRequestHeader('X-Mera', 'enabled');
80
- });
268
+ // If there's a <title> tag in the header, use it as
269
+ // the page's title.
270
+ obj.title = rails.findAll($head, 'title').last().text();
81
271
 
82
- $(window).on('ajax:success', function(event, data, status) {
83
- $.meraUpdater(data);
84
- $options.after();
85
- });
272
+ if (options.container) {
273
+ // If they specified a fragment, look for it in the response
274
+ // and pull it out.
275
+ if (options.container === 'body') {
276
+ $fragment = $body;
277
+ } else {
278
+ $fragment = rails.findAll($body, options.container).first().contents();
279
+ }
86
280
 
87
- $(window).on('ajax:error', function(event, xhr, status, error) {
88
- $options.error(xhr, status, error);
89
- });
281
+ if ($fragment.length) {
282
+ obj.contents = $fragment;
283
+ // If there's no title, look for data-title and title attributes
284
+ // on the fragment
285
+ if (!obj.title)
286
+ obj.title = $fragment.attr('title') || $fragment.data('title');
287
+ }
90
288
 
91
- $.meraUpdater = function(data){
92
- var resBody = data.split(/.*<body.*>.*/)[1].split(/.*<\/body>.*/)[0];
93
- var resHead = data.split(/.*<head.*>.*/)[1].split(/.*<\/head>.*/)[0];
289
+ } else if (!/<html/i.test(data)) {
290
+ obj.contents = $body;
291
+ }
94
292
 
95
- if($options.compress){
96
- resBody = $.whiteSpaceRemover(resBody);
97
- resHead = $.whiteSpaceRemover(resHead);
293
+ // Clean up any <title> tags
294
+ if (obj.contents) {
295
+ // Remove any parent title elements
296
+ obj.contents = obj.contents.not('title');
297
+
298
+ // Then scrub any titles from their descendents
299
+ obj.contents.find('title').remove();
98
300
  }
99
301
 
100
- $('head').html(resHead);
101
- $('body').html(resBody);
102
- };
302
+ // Trim any whitespace off the title
303
+ if (obj.title) obj.title = $.trim(obj.title);
103
304
 
104
- $.whiteSpaceRemover = function(data){
105
- data = data.replace(/ /g,'');
106
- data = data.replace(/\n/g,'');
107
- data = $.trim(data);
305
+ return obj;
306
+ },
108
307
 
109
- return data;
110
- };
308
+ // Get number / random
309
+ // from pjax core
310
+ uniqueId: function() {
311
+ return (new Date).getTime();
312
+ },
111
313
 
112
- $.rails.handleMethodRemote = function(link) {
113
- var href = $.rails.href(link),
114
- method = link.data('method'),
115
- target = link.attr('target'),
116
- confirmLink = link.attr('data-confirm'),
314
+ // Get / Save cache of page handled of mera
315
+ // from pjax core
316
+ cachePush: function (id, value) {
317
+ cacheMapping[id] = value;
318
+ cacheBackStack.push(id);
319
+
320
+ // Remove all entires in forward history stack after pushing
321
+ // a new page.
322
+ while (cacheForwardStack.length)
323
+ delete cacheMapping[cacheForwardStack.shift()];
324
+
325
+ // Trim back history stack to max cache length.
326
+ while (cacheBackStack.length > rails.ajaxDefault.maxCacheLength)
327
+ delete cacheMapping[cacheBackStack.shift()];
328
+ },
329
+
330
+ cachePop: function (direction, id, value) {
331
+ var pushStack, popStack;
332
+
333
+ cacheMapping[id] = value;
334
+
335
+ if (direction === 'forward') {
336
+ pushStack = cacheBackStack;
337
+ popStack = cacheForwardStack;
338
+ } else {
339
+ pushStack = cacheForwardStack;
340
+ popStack = cacheBackStack;
341
+ }
342
+
343
+ pushStack.push(id);
344
+
345
+ if (id = popStack.pop())
346
+ delete cacheMapping[id];
347
+ },
348
+
349
+ // Handle back/forward button in MERA
350
+ // from pjax core
351
+ onMeraPopstate: function (event) {
352
+ var state, container, contents, direction, popstateEvent, options;
353
+
354
+ state = event.state;
355
+
356
+ if (state && state.container) {
357
+ container = $(state.container);
358
+ if (container.length) {
359
+ contents = cacheMapping[state.id];
360
+
361
+ if (mera.state) {
362
+ // Since state ids always increase, we can deduce the history
363
+ // direction from the previous state.
364
+ direction = mera.state.id < state.id ? 'forward' : 'back';
365
+
366
+ // Cache current container before replacement and inform the
367
+ // cache which direction the history shifted.
368
+ rails.cachePop(direction, mera.state.id, container.clone().contents())
369
+ }
370
+
371
+ popstateEvent = $.Event('ajax:popstate', {
372
+ state: state,
373
+ direction: direction
374
+ });
375
+ container.trigger(popstateEvent);
376
+
377
+ options = {
378
+ id: state.id,
379
+ url: state.url,
380
+ container: container,
381
+ push: false,
382
+ timeout: state.timeout,
383
+ scrollTo: false
384
+ };
385
+
386
+ if (contents) {
387
+ container.trigger('ajax:start', [null, options]);
388
+
389
+ if (state.title){
390
+ document.title = state.title;
391
+ container.html(contents);
392
+ mera.state = state;
393
+ }
394
+
395
+ container.trigger('ajax:end', [null, options]);
396
+ } else {
397
+ rails.mjax(options);
398
+ }
399
+
400
+ // Force reflow/relayout before the browser tries to restore the
401
+ // scroll position.
402
+ container[0].offsetHeight;
403
+ } else {
404
+ rails.locationReplace(location.href);
405
+ }
406
+ }
407
+ },
408
+
409
+ // Core of PJAX and MERA => Mjax
410
+ // Options will be merge with $.ajaxDefault, and user options
411
+ // from pjax + custom mera
412
+ mjax: function (options) {
413
+ var target, hash, origin, context,timeoutTimer, xhr;
414
+
415
+ options = $.extend(true, {}, $.ajaxSettings, rails.ajaxDefault, options);
416
+
417
+ if ($.isFunction(options.url)) {
418
+ options.url = options.url();
419
+ }
420
+
421
+ target = options.target;
422
+ hash = rails.getUrlElement(options.url).hash;
423
+
424
+ if(!options.container){
425
+ origin = options.container;
426
+ options.c = origin;
427
+ options.container = rails.meraContainer;
428
+ } else {
429
+ options.c = options.container;
430
+ origin = true;
431
+ }
432
+
433
+ context = options.context = rails.findContainerFor(options.container);
434
+
435
+ function fire(type, args) {
436
+ var event = $.Event(type, { relatedTarget: target });
437
+ context.trigger(event, args);
438
+ return !event.isDefaultPrevented();
439
+ }
440
+
441
+ options.beforeSend = function(xhr, settings) {
442
+ // No timeout for non-GET requests
443
+ // Its not safe to request the resource again with a fallback method.
444
+ if (settings.type !== 'GET')
445
+ settings.timeout = 0;
446
+
447
+ if (settings.timeout > 0) {
448
+ timeoutTimer = setTimeout(function() {
449
+ if (fire('ajax:timeout', [xhr, options]))
450
+ xhr.abort('timeout');
451
+ }, settings.timeout);
452
+
453
+ // Clear timeout setting so jquerys internal timeout isn't invoked
454
+ settings.timeout = 0;
455
+ }
456
+
457
+ xhr.setRequestHeader('X-MERA', 'true');
458
+ xhr.setRequestHeader('X-MERA-CONTAINER', context.selector);
459
+
460
+ if (!fire('ajax:beforeSend', [xhr, settings, options]))
461
+ return false;
462
+
463
+ options.requestUrl = rails.getUrlElement(settings.url).href;
464
+ };
465
+
466
+ options.complete = function(xhr, textStatus) {
467
+ if (timeoutTimer)
468
+ clearTimeout(timeoutTimer);
469
+
470
+ if(options.customEvent)
471
+ fire(options.customEvent, [xhr, textStatus, options]);
472
+
473
+ fire('ajax:complete', [xhr, textStatus, options]);
474
+ fire('ajax:end', [xhr, options]);
475
+ };
476
+
477
+ options.error = function(xhr, textStatus, errorThrown) {
478
+ var container, allowed;
479
+
480
+ container = rails.extractContainer("", xhr, options);
481
+ allowed = fire('ajax:error', [xhr, textStatus, errorThrown, options]);
482
+
483
+ if (textStatus !== 'abort' && allowed)
484
+ rails.locationReplace(container.url);
485
+ };
486
+
487
+ options.success = function(data, status, xhr) {
488
+ var container, url, target;
489
+
490
+ container = rails.extractContainer(data, xhr, options);
491
+
492
+ if (!container.contents) {
493
+ rails.locationReplace(container.url);
494
+ return;
495
+ }
496
+
497
+ mera.state = {
498
+ id: options.id || rails.uniqueId(),
499
+ url: container.url,
500
+ title: container.title,
501
+ container: context.selector,
502
+ timeout: options.timeout
503
+ };
504
+
505
+ if (options.push || options.replace) {
506
+ window.history.replaceState(mera.state, container.title, options.push)
507
+ }
508
+
509
+ if (container.title){
510
+ document.title = container.title;
511
+ if(origin)
512
+ context.html(container.contents);
513
+ }
514
+
515
+
516
+ // Scroll to top by default
517
+ if (typeof options.scrollTo === 'number')
518
+ $(window).scrollTop(options.scrollTo);
519
+
520
+ // Google Analytics support
521
+ if ( (options.replace || options.push) && window._gaq )
522
+ _gaq.push(['_trackPageview']);
523
+
524
+ // If the URL has a hash in it, make sure the browser
525
+ // knows to navigate to the hash.
526
+ if ( hash !== '' ) {
527
+ // Avoid using simple hash set here. Will add another history
528
+ // entry. Replace the url with replaceState and scroll to target
529
+ // by hand.
530
+ //
531
+ // window.location.hash = hash
532
+ url = rails.getUrlElement(container.url);
533
+ url.hash = hash;
534
+
535
+ mera.state.url = url.href;
536
+ window.history.replaceState(mera.state, container.title, url.href);
537
+
538
+ target = $(url.hash);
539
+
540
+ if (target.length)
541
+ $(window).scrollTop(target.offset().top);
542
+ }
543
+
544
+ fire('ajax:success', [data, status, xhr, options]);
545
+ };
546
+
547
+ options.xhrFields = {
548
+ withCredentials: options.credentials
549
+ };
550
+
551
+ // Initialize mera.state for the initial page load. Assume we're
552
+ // using the container and options of the link we're loading for the
553
+ // back button to the initial page. This ensures good back button
554
+ // behavior.
555
+ if (!mera.state) {
556
+ mera.state = {
557
+ id: rails.uniqueId(),
558
+ url: window.location.href,
559
+ title: document.title,
560
+ container: context.selector,
561
+ timeout: options.timeout
562
+ };
563
+ window.history.replaceState(mera.state, document.title);
564
+ }
565
+
566
+ // Cancel the current request if we're already meraing
567
+ xhr = mera.xhr;
568
+
569
+ if (xhr && xhr.readyState < 4) {
570
+ xhr.onreadystatechange = $.noop;
571
+ xhr.abort();
572
+ }
573
+
574
+ mera.options = options;
575
+
576
+ xhr = mera.xhr = rails.ajax(options);
577
+
578
+ if (xhr.readyState > 0) {
579
+ if (options.push && !options.replace) {
580
+ // Cache current container element before replacing it
581
+ rails.cachePush(mera.state.id, context.clone().contents());
582
+
583
+ if(options.push !== false)
584
+ window.history.pushState(null, "", options.push);
585
+ }
586
+
587
+ fire('ajax:start', [xhr, options]);
588
+ fire('ajax:send', [xhr, options]);
589
+ }
590
+
591
+ return mera.xhr;
592
+ },
593
+
594
+ // Submits "remote" forms and links with ajax
595
+ // This method handle links, forms and other elements with ajax
596
+
597
+ handleRemote: function(element, dataType) {
598
+ if (rails.fire(element, 'ajax:before')) {
599
+ var obj = rails.findDataFor(element);
600
+
601
+ var options = {
602
+ type: obj.method ? 'POST' : 'GET',
603
+ dataType: dataType ? dataType : 'html',
604
+ container: obj.container,
605
+ url: obj.url,
606
+ data: obj.data,
607
+ push: obj.push,
608
+ credentials: obj.withCredentials,
609
+ crossDomain: obj.crossDomain,
610
+ customEvent: obj.event
611
+ };
612
+ return options.url ? rails.mjax(options) : false;
613
+ } else {
614
+ return false;
615
+ }
616
+ },
617
+
618
+ // Handles "data-method" on links such as:
619
+ // <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a>
620
+ handleMethod: function(link, remote) {
621
+ var href = rails.href(link),
622
+ method = link.data('method'),
623
+ target = link.attr('target'),
117
624
  csrf_token = $('meta[name=csrf-token]').attr('content'),
118
625
  csrf_param = $('meta[name=csrf-param]').attr('content'),
119
- form = $('<form method="post" action="' + href + '"></form>'),
120
- metadata_input = '<input name="_method" value="' + method + '" type="hidden" />';
626
+ form = $('<form/>', {method: "post", action: href});
627
+
628
+ $('<input>', {name:"_method", value: method, type: "hidden"}).appendTo(form);
629
+
630
+ if (csrf_param && csrf_token)
631
+ $('<input>', {name: csrf_param, value: csrf_token, type: "hidden"}).appendTo(form);
632
+
633
+ if (target)
634
+ form.attr('target', target);
635
+
636
+ form.hide().appendTo('body');
637
+ return form.submit();
638
+ },
639
+
640
+ // Rails ajax method
641
+ // $.rails.mera({url: "/example/1", method: "put", update: "#response"})
642
+ mera: function(opt){
643
+ var a = $('<a/>', {
644
+ "data-push": opt.push,
645
+ "data-container": opt.update,
646
+ "data-event": opt.customEvent,
647
+ "data-method": opt.method,
648
+ "data-cross-domain": opt.crossDomain,
649
+ "data-with-credentials": opt.withCredentials,
650
+ href: opt.url
651
+ });
652
+ return opt.url ? rails.handleRemote(a, opt.dataType) : false;
653
+ },
654
+
655
+ /* Disables form elements:
656
+ - Caches element value in 'ujs:enable-with' data store
657
+ - Replaces element text with value of 'data-disable-with' attribute
658
+ - Sets disabled property to true
659
+ */
660
+ disableFormElements: function(form) {
661
+ form.find(rails.disableSelector).each(function() {
662
+ var element = $(this), method = element.is('button') ? 'html' : 'val';
663
+ element.data('ujs:enable-with', element[method]());
664
+ element[method](element.data('disable-with'));
665
+ element.prop('disabled', true);
666
+ });
667
+ },
668
+
669
+ /* Re-enables disabled form elements:
670
+ - Replaces element text with cached value from 'ujs:enable-with' data store (created in `disableFormElements`)
671
+ - Sets disabled property to false
672
+ */
673
+ enableFormElements: function(form) {
674
+ form.find(rails.enableSelector).each(function() {
675
+ var element = $(this), method = element.is('button') ? 'html' : 'val';
676
+ if (element.data('ujs:enable-with')) element[method](element.data('ujs:enable-with'));
677
+ element.prop('disabled', false);
678
+ });
679
+ },
680
+
681
+ /* For 'data-confirm' attribute:
682
+ - Fires `confirm` event
683
+ - Shows the confirmation dialog
684
+ - Fires the `confirm:complete` event
685
+
686
+ Returns `true` if no function stops the chain and user chose yes; `false` otherwise.
687
+ Attaching a handler to the element's `confirm` event that returns a `falsy` value cancels the confirmation dialog.
688
+ Attaching a handler to the element's `confirm:complete` event that returns a `falsy` value makes this function
689
+ return false. The `confirm:complete` event is fired whether or not the user answered true or false to the dialog.
690
+ */
691
+ allowAction: function(element) {
692
+ var message = element.data('confirm'),
693
+ answer = false, callback;
694
+ if (!message) { return true; }
121
695
 
122
- if (csrf_param !== undefined && csrf_token !== undefined) {
123
- metadata_input += '<input name="' + csrf_param + '" value="' + csrf_token + '" type="hidden" />';
696
+ if (rails.fire(element, 'confirm')) {
697
+ answer = rails.confirm(message);
698
+ callback = rails.fire(element, 'confirm:complete', [answer]);
124
699
  }
700
+ return answer && callback;
701
+ },
702
+
703
+ // Helper function which checks for blank inputs in a form that match the specified CSS selector
704
+ blankInputs: function(form, specifiedSelector, nonBlank) {
705
+ var inputs = $(), input, valueToCheck,
706
+ selector = specifiedSelector || 'input,textarea',
707
+ allInputs = form.find(selector);
125
708
 
126
- if (target) { form.attr('target', target); }
709
+ allInputs.each(function() {
710
+ input = $(this);
711
+ valueToCheck = input.is(':checkbox,:radio') ? input.is(':checked') : input.val();
712
+ // If nonBlank and valueToCheck are both truthy, or nonBlank and valueToCheck are both falsey
713
+ if (!valueToCheck === !nonBlank) {
127
714
 
128
- form.hide().append(metadata_input).appendTo('body');
715
+ // Don't count unchecked required radio if other radio with same name is checked
716
+ if (input.is(':radio') && allInputs.filter('input:radio:checked[name="' + input.attr('name') + '"]').length) {
717
+ return true; // Skip to next input
718
+ }
129
719
 
130
- if(confirmLink !== undefined ){
131
- if($options.confirme(confirmLink)){
132
- $.rails.handleRemote(form);
720
+ inputs = inputs.add(input);
133
721
  }
134
- } else {
135
- $.rails.handleRemote(form);
722
+ });
723
+ return inputs.length ? inputs : false;
724
+ },
725
+
726
+ // Helper function which checks for non-blank inputs in a form that match the specified CSS selector
727
+ nonBlankInputs: function(form, specifiedSelector) {
728
+ return rails.blankInputs(form, specifiedSelector, true); // true specifies nonBlank
729
+ },
730
+
731
+ // Helper function, needed to provide consistent behavior in IE
732
+ stopEverything: function(e) {
733
+ $(e.target).trigger('ujs:everythingStopped');
734
+ e.stopImmediatePropagation();
735
+ return false;
736
+ },
737
+
738
+ // find all the submit events directly bound to the form and
739
+ // manually invoke them. If anyone returns false then stop the loop
740
+ callFormSubmitBindings: function(form, event) {
741
+ var events = form.data('events'), continuePropagation = true;
742
+ if (events !== undefined && events['submit'] !== undefined) {
743
+ $.each(events['submit'], function(i, obj){
744
+ if (typeof obj.handler === 'function') return continuePropagation = obj.handler(event);
745
+ });
136
746
  }
137
- };
747
+ return continuePropagation;
748
+ },
749
+
750
+ // replace element's html with the 'data-disable-with' after storing original html
751
+ // and prevent clicking on it
752
+ disableElement: function(element) {
753
+ element.data('ujs:enable-with', element.html()); // store enabled state
754
+ element.html(element.data('disable-with')); // set to disabled state
755
+ element.bind('click.railsDisable', function(e) { // prevent further clicking
756
+ return rails.stopEverything(e);
757
+ });
758
+ },
759
+
760
+ // restore element to its original state which was disabled by 'disableElement' above
761
+ enableElement: function(element) {
762
+ if (element.data('ujs:enable-with') !== undefined) {
763
+ element.html(element.data('ujs:enable-with')); // set to old enabled state
764
+ // this should be element.removeData('ujs:enable-with')
765
+ // but, there is currently a bug in jquery which makes hyphenated data attributes not get removed
766
+ element.data('ujs:enable-with', false); // clean up cache
767
+ }
768
+ element.unbind('click.railsDisable'); // enable element
769
+ },
770
+
771
+ // Handle cookies
772
+ // Can use with get, set and remove
773
+ cookie: {
774
+ get: function(key){
775
+ var name = new String();
776
+ var splitedCookies = document.cookie.split('; ');
777
+
778
+ for(var key in splitedCookies){
779
+ var cookie = splitedCookies[key].split('=');
780
+ if(cookie[0] == key){
781
+ name = decodeURIComponent(cookie[1]);
782
+ }
783
+ }
784
+ return name;
785
+ },
786
+
787
+ set: function(name, value, days){
788
+ var today = new Date();
789
+ var expire = new Date();
790
+
791
+ if (days == null || days == 0) {
792
+ days = 1;
793
+ }
794
+
795
+ expire.setTime(today.getTime() + (3600000 * 24 * days));
796
+ document.cookie = (
797
+ name + "=" + encodeURIComponent(value)
798
+ + ";expires=" + expire.toGMTString()
799
+ );
800
+ },
801
+
802
+ remove: function(key){
803
+ document.cookie = key + '=; expires=Thu, 01-Jan-70 00:00:01 GMT;';
804
+ }
805
+ },
806
+
807
+ //clean white spaces in code
808
+ cleanSpaces: function(data){
809
+ if(data !== undefined)
810
+ return $.trim(data.replace(/ /g,'').replace(/\n/g,''));
811
+ }
138
812
 
139
813
  };
140
- });
141
814
 
815
+ if (rails.fire($(document), 'rails:attachBindings')) {
816
+
817
+ $.ajaxPrefilter(function(options, originalOptions, xhr){
818
+ if (!options.crossDomain) rails.CSRFProtection(xhr);
819
+ });
820
+
821
+ $(document).delegate(rails.linkDisableSelector, 'ajax:complete', function() {
822
+ rails.enableElement($(this));
823
+ });
824
+
825
+ $(document).delegate(rails.linkClickSelector, 'click.rails', function(e) {
826
+ var link = $(this),
827
+ method = link.data('method'),
828
+ data = link.data('params');
829
+
830
+ if (!rails.allowAction(link))
831
+ return rails.stopEverything(e);
832
+
833
+ if (link.is(rails.linkDisableSelector))
834
+ rails.disableElement(link);
835
+
836
+ if (link.data('remote')) {
837
+ if ((e.metaKey || e.ctrlKey) && (!method || method === 'GET') && !data )
838
+ return true;
839
+
840
+ var handleRemote = rails.handleRemote(link);
841
+ // response from rails.handleRemote() will either be false or a deferred object promise.
842
+ if (handleRemote === false) {
843
+ rails.enableElement(link);
844
+ } else {
845
+ handleRemote.error(function() {
846
+ rails.enableElement(link);
847
+ });
848
+ }
849
+ return false;
850
+ } else if (link.data('method')) {
851
+ rails.handleMethod(link);
852
+ return false;
853
+ }
854
+ });
855
+
856
+ $(document).delegate(rails.inputChangeSelector, 'change.rails', function(e) {
857
+ var link = $(this);
858
+ if (!rails.allowAction(link))
859
+ return rails.stopEverything(e);
860
+
861
+ rails.handleRemote(link);
862
+ return false;
863
+ });
864
+
865
+ $(document).delegate(rails.formSubmitSelector, 'submit.rails', function(e) {
866
+ var form = $(this),
867
+ remote = form.data('remote') !== undefined,
868
+ blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector),
869
+ nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector);
870
+
871
+ if (!rails.allowAction(form))
872
+ return rails.stopEverything(e);
873
+
874
+ // skip other logic when required values are missing or file upload is present
875
+ if (blankRequiredInputs && form.attr("novalidate") == undefined && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs]))
876
+ return rails.stopEverything(e);
877
+
878
+ if (remote) {
879
+ if (nonBlankFileInputs) {
880
+ // slight timeout so that the submit button gets properly serialized
881
+ // (make it easy for event handler to serialize form without disabled values)
882
+ setTimeout(function(){
883
+ rails.disableFormElements(form);
884
+ }, 13);
885
+
886
+ var aborted = rails.fire(form, 'ajax:aborted:file', [nonBlankFileInputs]);
887
+
888
+ // re-enable form elements if event bindings return false (canceling normal form submission)
889
+ if (!aborted) {setTimeout(function(){
890
+ rails.enableFormElements(form);
891
+ }, 13); }
892
+
893
+ return aborted;
894
+ }
895
+
896
+ // If browser does not support submit bubbling, then this live-binding will be called before direct
897
+ // bindings. Therefore, we should directly call any direct bindings before remotely submitting form.
898
+ if (!$.support.submitBubbles && $().jquery < '1.7' && rails.callFormSubmitBindings(form, e) === false)
899
+ return rails.stopEverything(e);
900
+
901
+ rails.handleRemote(form);
902
+ return false;
903
+
904
+ } else {
905
+ // slight timeout so that the submit button gets properly serialized
906
+ setTimeout(function(){
907
+ rails.disableFormElements(form);
908
+ }, 13);
909
+ }
910
+ });
911
+
912
+ $(document).delegate(rails.formInputClickSelector, 'click.rails', function(event) {
913
+ var button = $(this);
914
+
915
+ if (!rails.allowAction(button))
916
+ return rails.stopEverything(event);
917
+
918
+ // register the pressed submit button
919
+ var name = button.attr('name'),
920
+ data = name ? {name:name, value:button.val()} : null;
921
+
922
+ button.closest('form').data('ujs:submit-button', data);
923
+ });
924
+
925
+ $(document).delegate(rails.formSubmitSelector, 'ajax:beforeSend.rails', function(event) {
926
+ if (this == event.target) rails.disableFormElements($(this));
927
+ });
928
+
929
+ $(document).delegate(rails.formSubmitSelector, 'ajax:complete.rails', function(event) {
930
+ if (this == event.target) rails.enableFormElements($(this));
931
+ });
932
+
933
+ $(function(){
934
+ // making sure that all forms have actual up-to-date token(cached forms contain old one)
935
+ csrf_token = $('meta[name=csrf-token]').attr('content');
936
+ csrf_param = $('meta[name=csrf-param]').attr('content');
937
+ $('form input[name="' + csrf_param + '"]').val(csrf_token);
938
+
939
+ if ($.inArray('state', $.event.props) < 0)
940
+ $.event.props.push('state');
941
+
942
+ if(rails.supportMera()){
943
+ $(window).bind('popstate.ajax', rails.onMeraPopstate);
944
+ window.location.redirect = function(url){
945
+ return $.rails.mera({url: url});
946
+ }
947
+ }
948
+ });
949
+ }
950
+ })( jQuery );
@@ -0,0 +1,58 @@
1
+ /**
2
+ * = Jquery_Ujs
3
+ *
4
+ * Unobtrusive scripting adapter for jQuery
5
+ *
6
+ * Requires jQuery 1.6.0 or later.
7
+ * https://github.com/rails/jquery-ujs
8
+ *
9
+ * =========================================
10
+ *
11
+ * = Pjax
12
+ *
13
+ * Pjax, loads HTML from your server into the current page without a full reload. It's ajax with real
14
+ * permalinks, page titles, and a working back button that fully degrades.
15
+ *
16
+ * Requires jQuery 1.7.0 or later.
17
+ * https://github.com/defunkt/jquery-pjax
18
+ *
19
+ * =========================================
20
+ *
21
+ * = Mera
22
+ *
23
+ * Is technology what combine classic Jquery_Ujs (only core) and Pjax (only core), together
24
+ *
25
+ * https://github.com/huttarichard/Mera
26
+ *
27
+ * =========================================
28
+ *
29
+ * Each project is open under Mit license
30
+ *
31
+ *
32
+ * Copyright (c) Mera 2012 & Pjax 2012 & Jquery_Ujs 2012
33
+ *
34
+ * Permission is hereby granted, free of charge, to any person
35
+ * obtaining a copy of this software and associated documentation
36
+ * files (the "Software"), to deal in the Software without
37
+ * restriction, including without limitation the rights to use,
38
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
39
+ * copies of the Software, and to permit persons to whom the
40
+ * Software is furnished to do so, subject to the following
41
+ * conditions:
42
+ *
43
+ * The above copyright notice and this permission notice shall be
44
+ * included in all copies or substantial portions of the Software.
45
+ *
46
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
47
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
48
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
49
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
50
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
51
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
52
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
53
+ * OTHER DEALINGS IN THE SOFTWARE.
54
+ *
55
+ */
56
+
57
+ (function($,undefined){var alreadyInitialized=function(){var events=$._data(document,'events');return events&&events.click&&$.grep(events.click,function(e){return e.namespace==='rails';}).length;};if(alreadyInitialized()){$.error('jquery-ujs has already been loaded!');}var rails;var cacheMapping={};var cacheForwardStack=[];var cacheBackStack=[];var mera={};$.rails=rails={linkClickSelector:'a[data-confirm], a[data-method], a[data-remote], a[data-disable-with]',inputChangeSelector:'select[data-remote], input[data-remote], textarea[data-remote]',formSubmitSelector:'form',formInputClickSelector:'form input[type=submit], form input[type=image], form button[type=submit], form button:not([type])',disableSelector:'input[data-disable-with], button[data-disable-with], textarea[data-disable-with]',enableSelector:'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled',requiredInputSelector:'input[name][required]:not([disabled]),textarea[name][required]:not([disabled])',fileInputSelector:'input:file',linkDisableSelector:'a[data-disable-with]',locationPath:location.pathname,locationUrl:location.href,meraContainer:"body",CSRFProtection:function(xhr){var token=$('meta[name="csrf-token"]').attr('content');if(token)xhr.setRequestHeader('X-CSRF-Token',token);},fire:function(obj,name,data){var event=$.Event(name);obj.trigger(event,data);return event.result!==false;},confirm:function(message){return confirm(message);},ajax:function(options){return $.ajax(options);},ajaxDefault:{timeout:650,push:true,replace:false,type:'GET',dataType:'html',scrollTo:0,maxCacheLength:20},href:function(element){return element.attr('href');},supportMera:function(){return(window.history&&window.history.pushState&&window.history.replaceState&&!navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/));},findContainerFor:function(container){container=$(container);if(!container.length){throw"Mera have not container for '"+container.selector+"'!";}else if(container.selector!==''&&container.context===document){return container;}else if(container.attr('id')){return $('#'+container.attr('id'));}else{throw"Can not get selector for Mera container!"}},findDataFor:function(element){var object,method,_method,params,_params;if(element.is('form')){object=element.find('input[name=ajaxParams]').val();if(object&&object.length)eval('object = '+object);else
58
+ object={};object=$.extend(object,{url:element.attr('action'),method:element.attr('method'),data:element.serialize()});}else{object={};object.crossDomain=element.data('cross-domain');object.withCredentials=element.data('with-credentials');object.container=element.data('container');object.event=element.data('event');object.push=element.data('push');method=element.data('method');_method=method?"_method="+method+"&":"";params=element.data('params');_params=params?params:"";object=$.extend(object,{url:(rails.href(element)||element.data('url')),method:method,data:_method+_params});}object.crossDomain=object.crossDomain||false;object.withCredentials=object.withCredentials||false;object.push=object.push==undefined?object.url:object.push;object.container=object.container!==undefined?object.container:rails.meraContainer;object.event=object.event?'ajax:'+object.event:false;return object;},getUrlElement:function(url){return $('<a/>',{href:url}).get(0);},findAll:function findAll(element,selector){return element.filter(selector).add(element.find(selector));},locationReplace:function(url){window.history.replaceState(null,"","/");window.location.replace(url);},extractContainer:function(data,xhr,options){var obj,$head,$body,$fragment;obj={};obj.url=(xhr.getResponseHeader('X-MERA-URL')||options.requestUrl);if(/<html/i.test(data)){$head=$(data.match(/<head[^>]*>([\s\S.]*)<\/head>/i)[0]);$body=$(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0]);}else{$head=$body=$(data);}if($body.length===0)return obj;obj.title=rails.findAll($head,'title').last().text();if(options.container){if(options.container==='body'){$fragment=$body;}else{$fragment=rails.findAll($body,options.container).first().contents();}if($fragment.length){obj.contents=$fragment;if(!obj.title)obj.title=$fragment.attr('title')||$fragment.data('title');}}else if(!/<html/i.test(data)){obj.contents=$body;}if(obj.contents){obj.contents=obj.contents.not('title');obj.contents.find('title').remove();}if(obj.title)obj.title=$.trim(obj.title);return obj;},uniqueId:function(){return(new Date).getTime();},cachePush:function(id,value){cacheMapping[id]=value;cacheBackStack.push(id);while(cacheForwardStack.length)delete cacheMapping[cacheForwardStack.shift()];while(cacheBackStack.length>rails.ajaxDefault.maxCacheLength)delete cacheMapping[cacheBackStack.shift()];},cachePop:function(direction,id,value){var pushStack,popStack;cacheMapping[id]=value;if(direction==='forward'){pushStack=cacheBackStack;popStack=cacheForwardStack;}else{pushStack=cacheForwardStack;popStack=cacheBackStack;}pushStack.push(id);if(id=popStack.pop())delete cacheMapping[id];},onMeraPopstate:function(event){var state,container,contents,direction,popstateEvent,options;state=event.state;if(state&&state.container){container=$(state.container);if(container.length){contents=cacheMapping[state.id];if(mera.state){direction=mera.state.id<state.id?'forward':'back';rails.cachePop(direction,mera.state.id,container.clone().contents())}popstateEvent=$.Event('ajax:popstate',{state:state,direction:direction});container.trigger(popstateEvent);options={id:state.id,url:state.url,container:container,push:false,timeout:state.timeout,scrollTo:false};if(contents){container.trigger('ajax:start',[null,options]);if(state.title){document.title=state.title;container.html(contents);mera.state=state;}container.trigger('ajax:end',[null,options]);}else{rails.mjax(options);}container[0].offsetHeight;}else{rails.locationReplace(location.href);}}},mjax:function(options){var target,hash,origin,context,timeoutTimer,xhr;options=$.extend(true,{},$.ajaxSettings,rails.ajaxDefault,options);if($.isFunction(options.url)){options.url=options.url();}target=options.target;hash=rails.getUrlElement(options.url).hash;if(!options.container){origin=options.container;options.c=origin;options.container=rails.meraContainer;}else{options.c=options.container;origin=true;}context=options.context=rails.findContainerFor(options.container);function fire(type,args){var event=$.Event(type,{relatedTarget:target});context.trigger(event,args);return!event.isDefaultPrevented();}options.beforeSend=function(xhr,settings){if(settings.type!=='GET')settings.timeout=0;if(settings.timeout>0){timeoutTimer=setTimeout(function(){if(fire('ajax:timeout',[xhr,options]))xhr.abort('timeout');},settings.timeout);settings.timeout=0;}xhr.setRequestHeader('X-MERA','true');xhr.setRequestHeader('X-MERA-CONTAINER',context.selector);if(!fire('ajax:beforeSend',[xhr,settings,options]))return false;options.requestUrl=rails.getUrlElement(settings.url).href;};options.complete=function(xhr,textStatus){if(timeoutTimer)clearTimeout(timeoutTimer);if(options.customEvent)fire(options.customEvent,[xhr,textStatus,options]);fire('ajax:complete',[xhr,textStatus,options]);fire('ajax:end',[xhr,options]);};options.error=function(xhr,textStatus,errorThrown){var container,allowed;container=rails.extractContainer("",xhr,options);allowed=fire('ajax:error',[xhr,textStatus,errorThrown,options]);if(textStatus!=='abort'&&allowed)rails.locationReplace(container.url);};options.success=function(data,status,xhr){var container,url,target;container=rails.extractContainer(data,xhr,options);if(!container.contents){rails.locationReplace(container.url);return;}mera.state={id:options.id||rails.uniqueId(),url:container.url,title:container.title,container:context.selector,timeout:options.timeout};if(options.push||options.replace){window.history.replaceState(mera.state,container.title,options.push)}if(container.title){document.title=container.title;if(origin)context.html(container.contents);}if(typeof options.scrollTo==='number')$(window).scrollTop(options.scrollTo);if((options.replace||options.push)&&window._gaq)_gaq.push(['_trackPageview']);if(hash!==''){url=rails.getUrlElement(container.url);url.hash=hash;mera.state.url=url.href;window.history.replaceState(mera.state,container.title,url.href);target=$(url.hash);if(target.length)$(window).scrollTop(target.offset().top);}fire('ajax:success',[data,status,xhr,options]);};options.xhrFields={withCredentials:options.credentials};if(!mera.state){mera.state={id:rails.uniqueId(),url:window.location.href,title:document.title,container:context.selector,timeout:options.timeout};window.history.replaceState(mera.state,document.title);}xhr=mera.xhr;if(xhr&&xhr.readyState<4){xhr.onreadystatechange=$.noop;xhr.abort();}mera.options=options;xhr=mera.xhr=rails.ajax(options);if(xhr.readyState>0){if(options.push&&!options.replace){rails.cachePush(mera.state.id,context.clone().contents());if(options.push!==false)window.history.pushState(null,"",options.push);}fire('ajax:start',[xhr,options]);fire('ajax:send',[xhr,options]);}return mera.xhr;},handleRemote:function(element,dataType){if(rails.fire(element,'ajax:before')){var obj=rails.findDataFor(element);var options={type:obj.method?'POST':'GET',dataType:dataType?dataType:'html',container:obj.container,url:obj.url,data:obj.data,push:obj.push,credentials:obj.withCredentials,crossDomain:obj.crossDomain,customEvent:obj.event};return options.url?rails.mjax(options):false;}else{return false;}},handleMethod:function(link,remote){var href=rails.href(link),method=link.data('method'),target=link.attr('target'),csrf_token=$('meta[name=csrf-token]').attr('content'),csrf_param=$('meta[name=csrf-param]').attr('content'),form=$('<form/>',{method:"post",action:href});$('<input>',{name:"_method",value:method,type:"hidden"}).appendTo(form);if(csrf_param&&csrf_token)$('<input>',{name:csrf_param,value:csrf_token,type:"hidden"}).appendTo(form);if(target)form.attr('target',target);form.hide().appendTo('body');return form.submit();},mera:function(opt){var a=$('<a/>',{"data-push":opt.push,"data-container":opt.update,"data-event":opt.customEvent,"data-method":opt.method,"data-cross-domain":opt.crossDomain,"data-with-credentials":opt.withCredentials,href:opt.url});return opt.url?rails.handleRemote(a,opt.dataType):false;},disableFormElements:function(form){form.find(rails.disableSelector).each(function(){var element=$(this),method=element.is('button')?'html':'val';element.data('ujs:enable-with',element[method]());element[method](element.data('disable-with'));element.prop('disabled',true);});},enableFormElements:function(form){form.find(rails.enableSelector).each(function(){var element=$(this),method=element.is('button')?'html':'val';if(element.data('ujs:enable-with'))element[method](element.data('ujs:enable-with'));element.prop('disabled',false);});},allowAction:function(element){var message=element.data('confirm'),answer=false,callback;if(!message){return true;}if(rails.fire(element,'confirm')){answer=rails.confirm(message);callback=rails.fire(element,'confirm:complete',[answer]);}return answer&&callback;},blankInputs:function(form,specifiedSelector,nonBlank){var inputs=$(),input,valueToCheck,selector=specifiedSelector||'input,textarea',allInputs=form.find(selector);allInputs.each(function(){input=$(this);valueToCheck=input.is(':checkbox,:radio')?input.is(':checked'):input.val();if(!valueToCheck===!nonBlank){if(input.is(':radio')&&allInputs.filter('input:radio:checked[name="'+input.attr('name')+'"]').length){return true;}inputs=inputs.add(input);}});return inputs.length?inputs:false;},nonBlankInputs:function(form,specifiedSelector){return rails.blankInputs(form,specifiedSelector,true);},stopEverything:function(e){$(e.target).trigger('ujs:everythingStopped');e.stopImmediatePropagation();return false;},callFormSubmitBindings:function(form,event){var events=form.data('events'),continuePropagation=true;if(events!==undefined&&events['submit']!==undefined){$.each(events['submit'],function(i,obj){if(typeof obj.handler==='function')return continuePropagation=obj.handler(event);});}return continuePropagation;},disableElement:function(element){element.data('ujs:enable-with',element.html());element.html(element.data('disable-with'));element.bind('click.railsDisable',function(e){return rails.stopEverything(e);});},enableElement:function(element){if(element.data('ujs:enable-with')!==undefined){element.html(element.data('ujs:enable-with'));element.data('ujs:enable-with',false);}element.unbind('click.railsDisable');},cookie:{get:function(key){var name=new String();var splitedCookies=document.cookie.split('; ');for(var key in splitedCookies){var cookie=splitedCookies[key].split('=');if(cookie[0]==key){name=decodeURIComponent(cookie[1]);}}return name;},set:function(name,value,days){var today=new Date();var expire=new Date();if(days==null||days==0){days=1;}expire.setTime(today.getTime()+(3600000*24*days));document.cookie=(name+"="+encodeURIComponent(value)+";expires="+expire.toGMTString());},remove:function(key){document.cookie=key+'=; expires=Thu, 01-Jan-70 00:00:01 GMT;';}},cleanSpaces:function(data){if(data!==undefined)return $.trim(data.replace(/ /g,'').replace(/\n/g,''));}};if(rails.fire($(document),'rails:attachBindings')){$.ajaxPrefilter(function(options,originalOptions,xhr){if(!options.crossDomain)rails.CSRFProtection(xhr);});$(document).delegate(rails.linkDisableSelector,'ajax:complete',function(){rails.enableElement($(this));});$(document).delegate(rails.linkClickSelector,'click.rails',function(e){var link=$(this),method=link.data('method'),data=link.data('params');if(!rails.allowAction(link))return rails.stopEverything(e);if(link.is(rails.linkDisableSelector))rails.disableElement(link);if(link.data('remote')){if((e.metaKey||e.ctrlKey)&&(!method||method==='GET')&&!data)return true;var handleRemote=rails.handleRemote(link);if(handleRemote===false){rails.enableElement(link);}else{handleRemote.error(function(){rails.enableElement(link);});}return false;}else if(link.data('method')){rails.handleMethod(link);return false;}});$(document).delegate(rails.inputChangeSelector,'change.rails',function(e){var link=$(this);if(!rails.allowAction(link))return rails.stopEverything(e);rails.handleRemote(link);return false;});$(document).delegate(rails.formSubmitSelector,'submit.rails',function(e){var form=$(this),remote=form.data('remote')!==undefined,blankRequiredInputs=rails.blankInputs(form,rails.requiredInputSelector),nonBlankFileInputs=rails.nonBlankInputs(form,rails.fileInputSelector);if(!rails.allowAction(form))return rails.stopEverything(e);if(blankRequiredInputs&&form.attr("novalidate")==undefined&&rails.fire(form,'ajax:aborted:required',[blankRequiredInputs]))return rails.stopEverything(e);if(remote){if(nonBlankFileInputs){setTimeout(function(){rails.disableFormElements(form);},13);var aborted=rails.fire(form,'ajax:aborted:file',[nonBlankFileInputs]);if(!aborted){setTimeout(function(){rails.enableFormElements(form);},13);}return aborted;}if(!$.support.submitBubbles&&$().jquery<'1.7'&&rails.callFormSubmitBindings(form,e)===false)return rails.stopEverything(e);rails.handleRemote(form);return false;}else{setTimeout(function(){rails.disableFormElements(form);},13);}});$(document).delegate(rails.formInputClickSelector,'click.rails',function(event){var button=$(this);if(!rails.allowAction(button))return rails.stopEverything(event);var name=button.attr('name'),data=name?{name:name,value:button.val()}:null;button.closest('form').data('ujs:submit-button',data);});$(document).delegate(rails.formSubmitSelector,'ajax:beforeSend.rails',function(event){if(this==event.target)rails.disableFormElements($(this));});$(document).delegate(rails.formSubmitSelector,'ajax:complete.rails',function(event){if(this==event.target)rails.enableFormElements($(this));});$(function(){csrf_token=$('meta[name=csrf-token]').attr('content');csrf_param=$('meta[name=csrf-param]').attr('content');$('form input[name="'+csrf_param+'"]').val(csrf_token);if($.inArray('state',$.event.props)<0)$.event.props.push('state');if(rails.supportMera()){$(window).bind('popstate.ajax',rails.onMeraPopstate);window.location.redirect=function(url){return $.rails.mera({url:url});}}});}})(jQuery);
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mera
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,33 +9,19 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-17 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: jquery-rails
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :runtime
23
- prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ! '>='
28
- - !ruby/object:Gem::Version
29
- version: '0'
30
- description:
12
+ date: 2012-10-07 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Simple way how to make project with ajax. Mera handle pushState, updating
15
+ and buttons in browser!
31
16
  email: huttarichard@gmail.com
32
17
  executables: []
33
18
  extensions: []
34
19
  extra_rdoc_files: []
35
20
  files:
36
21
  - lib/assets/javascripts/mera.js
22
+ - lib/assets/javascripts/mera.min.js
37
23
  - lib/mera.rb
38
- homepage:
24
+ homepage: https://github.com/huttarichard/Mera
39
25
  licenses: []
40
26
  post_install_message:
41
27
  rdoc_options: []
@@ -58,5 +44,5 @@ rubyforge_project:
58
44
  rubygems_version: 1.8.24
59
45
  signing_key:
60
46
  specification_version: 3
61
- summary: My Easy Rails Ajax && Ruby on Rails 3.1 +
47
+ summary: My Easy Rails Ajax
62
48
  test_files: []