ajax 0.1.2
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/MIT-LICENSE +20 -0
- data/README.rdoc +291 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/app/controllers/ajax_controller.rb +3 -0
- data/app/views/ajax/framework.html.erb +7 -0
- data/config/initializers/ajax.rb +14 -0
- data/lib/ajax.rb +79 -0
- data/lib/ajax/action_controller.rb +154 -0
- data/lib/ajax/action_view.rb +56 -0
- data/lib/ajax/helpers.rb +15 -0
- data/lib/ajax/helpers/request_helper.rb +76 -0
- data/lib/ajax/helpers/robot_helper.rb +31 -0
- data/lib/ajax/helpers/url_helper.rb +47 -0
- data/lib/ajax/railtie.rb +7 -0
- data/lib/ajax/routes.rb +12 -0
- data/lib/ajax/spec/extension.rb +34 -0
- data/lib/ajax/spec/helpers.rb +95 -0
- data/lib/ajax/tasks.rb +1 -0
- data/lib/rack-ajax.rb +60 -0
- data/lib/rack-ajax/decision_tree.rb +60 -0
- data/lib/rack-ajax/parser.rb +115 -0
- data/public/images/loading-icon-large.gif +0 -0
- data/public/images/loading-icon-small.gif +0 -0
- data/public/javascripts/ajax.js +529 -0
- data/public/javascripts/jquery.address-1.1.js +450 -0
- data/public/javascripts/jquery.address-1.1.min.js +11 -0
- data/public/javascripts/jquery.address-1.2.js +528 -0
- data/public/javascripts/jquery.address-1.2.min.js +25 -0
- data/public/javascripts/jquery.address-1.2rc.js +599 -0
- data/public/javascripts/jquery.address-1.2rc.min.js +27 -0
- data/public/javascripts/jquery.json-2.2.js +178 -0
- data/public/javascripts/jquery.json-2.2.min.js +31 -0
- data/rails/init.rb +4 -0
- data/rails/install.rb +23 -0
- data/rails/uninstall.rb +1 -0
- data/spec/ajax/helpers_spec.rb +102 -0
- data/spec/ajax/request_helper_spec.rb +33 -0
- data/spec/integration/ajax_spec.rb +146 -0
- data/spec/rack-ajax/parser_spec.rb +62 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +18 -0
- data/tasks/ajax_tasks.rake +15 -0
- metadata +106 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
/*
|
2
|
+
* jQuery Address Plugin v1.2rc
|
3
|
+
* http://www.asual.com/jquery/address/
|
4
|
+
*
|
5
|
+
* Copyright (c) 2009-2010 Rostislav Hristov
|
6
|
+
* Dual licensed under the MIT or GPL Version 2 licenses.
|
7
|
+
* http://jquery.org/license
|
8
|
+
*
|
9
|
+
* Date: 2010-03-31 11:35:36 +0300 (Wed, 31 Mar 2010)
|
10
|
+
*/
|
11
|
+
(function(c){c.address=function(){var v=function(a){c(c.address).trigger(c.extend(c.Event(a),function(){for(var b={},g=c.address.parameterNames(),h=0,q=g.length;h<q;h++)b[g[h]]=c.address.parameter(g[h]);return{value:c.address.value(),path:c.address.path(),pathNames:c.address.pathNames(),parameterNames:g,parameters:b,queryString:c.address.queryString()}}.call(c.address)))},y=function(a,b,g){if(g||b)c(c.address).bind(a,g||b,g&&b);return c.address},n=function(){var a=d.href.indexOf("#");return a!=-1?
|
12
|
+
W(J(t(d.href.substr(a+1),j))):""},X=function(){return"javascript"},Y=function(a,b){if(i.strict)a=b?a.substr(0,1)!="/"?"/"+a:a:a==""?"/":a;return a},K=function(a,b){return u&&d.protocol=="file:"?b?f.replace(/\?/,"%3F"):f.replace(/%253F/,"?"):a},t=function(a,b){if(i.crawlable&&b)return(a!=""?"!":"")+a;return a.replace(/^\!/,"")},w=function(a,b){return parseInt(a.css(b),10)},Z=function(a){for(var b,g,h=0,q=a.childNodes.length;h<q;h++){if(a.childNodes[h].src)b=String(a.childNodes[h].src);if(g=Z(a.childNodes[h]))b=
|
13
|
+
g}return b},H=function(){if(!L){var a=n(),b=f!=a;if(x&&m<523){if(D!=F.length){D=F.length;if(typeof z[D-1]!=A)f=z[D-1];G(j)}}else if(u&&m<7&&b)d.reload();else if(b){f=a;G(j)}}},G=function(a){v($);v(a?aa:ba);E(ca,10)},ca=function(){var a=(d.pathname+(/\/$/.test(d.pathname)?"":"/")+c.address.value()).replace(/\/\//,"/").replace(/^\/$/,""),b=window[i.tracker];if(typeof b==M)b(a);else if(typeof _gaq!=A&&typeof _gaq.push==M)_gaq.push(["_trackPageview",a]);else if(typeof pageTracker!=A&&typeof pageTracker._trackPageview==
|
14
|
+
M)pageTracker._trackPageview(a);else typeof urchinTracker==M&&urchinTracker(a)},da=function(){var a=l.contentWindow.document;a.open();a.write("<html><head><title>"+k.title+"</title><script>var "+o+' = "'+n()+'";<\/script></head></html>');a.close()},fa=function(){if(!ea){ea=e;if(i.wrap){var a=c("body");wrap=c("body > *").wrapAll('<div style="padding:'+(w(a,"marginTop")+w(a,"paddingTop"))+"px "+(w(a,"marginRight")+w(a,"paddingRight"))+"px "+(w(a,"marginBottom")+w(a,"paddingBottom"))+"px "+(w(a,"marginLeft")+
|
15
|
+
w(a,"paddingLeft"))+'px;" />').parent().wrap('<div id="'+o+'" style="height:100%; overflow:auto;'+(x?window.statusbar.visible&&!/chrome/i.test(O)?"":" resize:both;":"")+'" />');c("html, body").css({height:"100%",margin:0,padding:0,overflow:"hidden"});x&&c('<style type="text/css" />').appendTo("head").text("#"+o+"::-webkit-resizer { background-color: #fff; }")}if(u&&m<8){a=k.getElementsByTagName("frameset")[0];l=k.createElement((a?"":"i")+"frame");if(a){a.insertAdjacentElement("beforeEnd",l);a[a.cols?
|
16
|
+
"cols":"rows"]+=",0";l.src=X()+":"+j;l.noResize=e;l.frameBorder=l.frameSpacing=0}else{l.src=X()+":"+j;l.style.display="none";k.body.insertAdjacentElement("afterBegin",l)}E(function(){c(l).bind("load",function(){var b=l.contentWindow;f=typeof b[o]!=A?b[o]:"";if(f!=n()){G(j);d.hash=K(t(f,e),e)}});typeof l.contentWindow[o]==A&&da()},50)}else if(x){if(m<418){c(k.body).append('<form id="'+o+'" style="position:absolute;top:-9999px;" method="get"></form>');P=k.getElementById(o)}if(typeof d[o]==A)d[o]={};
|
17
|
+
if(typeof d[o][d.pathname]!=A)z=d[o][d.pathname].split(",")}E(function(){v("init");G(j)},1);if(u&&m>7||!u&&"on"+I in p)if(p.addEventListener)p.addEventListener(I,H,false);else p.attachEvent&&p.attachEvent("on"+I,H);else ja(H,50);c("a[rel*=address:]").address()}},ka=function(){if(p.removeEventListener)p.removeEventListener(I,H,false);else p.detachEvent&&p.detachEvent("on"+I,H)},o="jQueryAddress",M="function",A="undefined",I="hashchange",$="change",aa="internalChange",ba="externalChange",e=true,j=false,
|
18
|
+
i={autoUpdate:e,crawlable:j,history:e,strict:e,wrap:j},r=c.browser,m=parseFloat(c.browser.version),ga=r.mozilla,u=r.msie,s=r.opera,x=r.safari,Q=j,p=function(){try{return top.document!==undefined?top:window}catch(a){return window}}(),k=p.document,F=p.history,d=p.location,ja=setInterval,E=setTimeout,J=decodeURI,W=encodeURI,O=navigator.userAgent,l,P,B=Z(document),ha=B?B.indexOf("?"):-1,R=k.title,D=F.length,L=j,ea=j,S=e,ia=e,N=j,z=[],f=n();if(u){m=parseFloat(O.substr(O.indexOf("MSIE")+4));if(k.documentMode&&
|
19
|
+
k.documentMode!=m)m=k.documentMode!=8?7:8;c(document).bind("propertychange",function(){if(k.title!=R&&k.title.indexOf("#"+n())!=-1)k.title=R})}if(Q=ga&&m>=1||u&&m>=6||s&&m>=9.5||x&&m>=312){for(r=1;r<D;r++)z.push("");z.push(f);if(u&&d.hash!=f)d.hash="#"+K(t(f,e),e);if(s)history.navigationMode="compatible";if(B&&ha!=-1){B=B.substr(ha+1).split("&");for(r=0;r<B.length;r++){s=B[r].split("=");if(/^(autoUpdate|crawlable|history|strict|wrap)$/.test(s[0]))i[s[0]]=isNaN(s[1])?/^(true|yes)$/i.test(s[1]):parseInt(s[1],
|
20
|
+
10)!==0;if(/^tracker$/.test(s[0]))i[s[0]]=s[1]}}document.readyState=="complete"&&fa();c(fa);c(window).bind("unload",ka)}else if(!Q&&n()!=""||x&&m<418&&n()!=""&&d.search!=""){k.open();k.write('<html><head><meta http-equiv="refresh" content="0;url='+encodeURI(d.href.substr(0,d.href.indexOf("#")))+'" /></head></html>');k.close()}else ca();return{init:function(a,b){return y("init",a,b)},change:function(a,b){return y($,a,b)},internalChange:function(a,b){return y(aa,a,b)},externalChange:function(a,b){return y(ba,
|
21
|
+
a,b)},baseURL:function(){var a=d.href;if(n()!="")a=a.substr(0,a.indexOf("#"));if(/\/$/.test(a))a=a.substr(0,a.length-1);return a},autoUpdate:function(a){if(a!==undefined){i.autoUpdate=a;return this}return i.autoUpdate},crawlable:function(a){if(a!==undefined){i.crawlable=a;return this}return i.crawlable},history:function(a){if(a!==undefined){i.history=a;return this}return i.history},strict:function(a){if(a!==undefined){i.strict=a;return this}return i.strict},tracker:function(a){if(a!==undefined){i.tracker=
|
22
|
+
a;return this}return i.tracker},wrap:function(a){if(a!==undefined){i.wrap=a;return this}return i.wrap},update:function(){N=e;this.value(f);N=j;return this},title:function(a){if(a!==undefined){a=J(a);E(function(){R=k.title=a;if(ia&&l&&l.contentWindow&&l.contentWindow.document){l.contentWindow.document.title=a;ia=j}if(!S&&ga)d.replace(d.href.indexOf("#")!=-1?d.href:d.href+"#");S=j},50);return this}return k.title},value:function(a){if(a!==undefined){a=W(J(Y(a,e)));if(a=="/")a="";if(f==a&&!N)return;S=
|
23
|
+
e;f=a;if(i.autoUpdate||N){L=e;G(e);z[F.length]=f;if(x)if(i.history){d[o][d.pathname]=z.toString();D=F.length+1;if(m<418){if(d.search==""){P.action="#"+t(f,e);P.submit()}}else if(m<523||f==""){a=k.createEvent("MouseEvents");a.initEvent("click",e,e);var b=k.createElement("a");b.href="#"+t(f,e);b.dispatchEvent(a)}else d.hash="#"+t(f,e)}else d.replace("#"+t(f,e));else if(f!=n())if(i.history)d.hash="#"+K(t(f,e),e);else d.replace("#"+t(f,e));u&&m<8&&i.history&&E(da,50);if(x)E(function(){L=j},1);else L=
|
24
|
+
j}return this}if(!Q)return null;return J(Y(K(f,j),j))},path:function(a){if(a!==undefined){var b=this.queryString(),g=this.hash();this.value(a+(b?"?"+b:"")+(g?"#"+g:""));return this}return this.value().split("#")[0].split("?")[0]},queryString:function(a){if(a!==undefined){var b=this.hash();this.value(this.path()+(a?"?"+a:"")+(b?"#"+b:""));return this}a=this.value().split("?");return a.slice(1,a.length).join("?").split("#")[0]},parameter:function(a,b,g){var h,q;if(b!==undefined){var T=this.parameterNames();
|
25
|
+
q=[];for(h=0;h<T.length;h++){var U=T[h],C=this.parameter(U);if(typeof C=="string")C=[C];if(U==a)C=b===null||b==""?[]:g?C.concat([b]):[b];for(var V=0;V<C.length;V++)q.push(U+"="+C[V])}c.inArray(a,T)==-1&&q.push(a+"="+b);this.queryString(q.join("&"));return this}if(b=this.queryString()){q=b.split("&");b=[];for(h=0;h<q.length;h++){g=q[h].split("=");g[0]==a&&b.push(g[1])}if(b.length!==0)return b.length!=1?b:b[0]}},pathNames:function(){var a=this.path(),b=a.replace(/\/{2,9}/g,"/").split("/");if(a.substr(0,
|
26
|
+
1)=="/"||a.length===0)b.splice(0,1);a.substr(a.length-1,1)=="/"&&b.splice(b.length-1,1);return b},parameterNames:function(){var a=this.queryString(),b=[];if(a&&a.indexOf("=")!=-1){a=a.split("&");for(var g=0;g<a.length;g++){var h=a[g].split("=")[0];c.inArray(h,b)==-1&&b.push(h)}}return b},hash:function(a){if(a!==undefined){this.value(this.value().split("#")[0]+(a?"#"+a:""));return this}a=this.value().split("#");return a.slice(1,a.length).join("#")}}}();c.fn.address=function(v){this.each(function(){if(this.tagName.toLowerCase()==
|
27
|
+
"form")c("form").live("submit",function(){var n=v?v.call(this):c(this).attr("action")+"?"+c(this).serialize();c.address.value(n);return false});else{var y=function(){var n=v?v.call(this):/address:/.test(c(this).attr("rel"))?c(this).attr("rel").split("address:")[1].split(" ")[0]:c(this).attr("href").replace(/^#\!?/,"");c.address.value(n);return false};c(this).click(y).live("click",y)}})}})(jQuery);
|
@@ -0,0 +1,178 @@
|
|
1
|
+
/*
|
2
|
+
* jQuery JSON Plugin
|
3
|
+
* version: 2.1 (2009-08-14)
|
4
|
+
*
|
5
|
+
* This document is licensed as free software under the terms of the
|
6
|
+
* MIT License: http://www.opensource.org/licenses/mit-license.php
|
7
|
+
*
|
8
|
+
* Brantley Harris wrote this plugin. It is based somewhat on the JSON.org
|
9
|
+
* website's http://www.json.org/json2.js, which proclaims:
|
10
|
+
* "NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.", a sentiment that
|
11
|
+
* I uphold.
|
12
|
+
*
|
13
|
+
* It is also influenced heavily by MochiKit's serializeJSON, which is
|
14
|
+
* copyrighted 2005 by Bob Ippolito.
|
15
|
+
*/
|
16
|
+
|
17
|
+
(function($) {
|
18
|
+
/** jQuery.toJSON( json-serializble )
|
19
|
+
Converts the given argument into a JSON respresentation.
|
20
|
+
|
21
|
+
If an object has a "toJSON" function, that will be used to get the representation.
|
22
|
+
Non-integer/string keys are skipped in the object, as are keys that point to a function.
|
23
|
+
|
24
|
+
json-serializble:
|
25
|
+
The *thing* to be converted.
|
26
|
+
**/
|
27
|
+
$.toJSON = function(o)
|
28
|
+
{
|
29
|
+
if (typeof(JSON) == 'object' && JSON.stringify)
|
30
|
+
return JSON.stringify(o);
|
31
|
+
|
32
|
+
var type = typeof(o);
|
33
|
+
|
34
|
+
if (o === null)
|
35
|
+
return "null";
|
36
|
+
|
37
|
+
if (type == "undefined")
|
38
|
+
return undefined;
|
39
|
+
|
40
|
+
if (type == "number" || type == "boolean")
|
41
|
+
return o + "";
|
42
|
+
|
43
|
+
if (type == "string")
|
44
|
+
return $.quoteString(o);
|
45
|
+
|
46
|
+
if (type == 'object')
|
47
|
+
{
|
48
|
+
if (typeof o.toJSON == "function")
|
49
|
+
return $.toJSON( o.toJSON() );
|
50
|
+
|
51
|
+
if (o.constructor === Date)
|
52
|
+
{
|
53
|
+
var month = o.getUTCMonth() + 1;
|
54
|
+
if (month < 10) month = '0' + month;
|
55
|
+
|
56
|
+
var day = o.getUTCDate();
|
57
|
+
if (day < 10) day = '0' + day;
|
58
|
+
|
59
|
+
var year = o.getUTCFullYear();
|
60
|
+
|
61
|
+
var hours = o.getUTCHours();
|
62
|
+
if (hours < 10) hours = '0' + hours;
|
63
|
+
|
64
|
+
var minutes = o.getUTCMinutes();
|
65
|
+
if (minutes < 10) minutes = '0' + minutes;
|
66
|
+
|
67
|
+
var seconds = o.getUTCSeconds();
|
68
|
+
if (seconds < 10) seconds = '0' + seconds;
|
69
|
+
|
70
|
+
var milli = o.getUTCMilliseconds();
|
71
|
+
if (milli < 100) milli = '0' + milli;
|
72
|
+
if (milli < 10) milli = '0' + milli;
|
73
|
+
|
74
|
+
return '"' + year + '-' + month + '-' + day + 'T' +
|
75
|
+
hours + ':' + minutes + ':' + seconds +
|
76
|
+
'.' + milli + 'Z"';
|
77
|
+
}
|
78
|
+
|
79
|
+
if (o.constructor === Array)
|
80
|
+
{
|
81
|
+
var ret = [];
|
82
|
+
for (var i = 0; i < o.length; i++)
|
83
|
+
ret.push( $.toJSON(o[i]) || "null" );
|
84
|
+
|
85
|
+
return "[" + ret.join(",") + "]";
|
86
|
+
}
|
87
|
+
|
88
|
+
var pairs = [];
|
89
|
+
for (var k in o) {
|
90
|
+
var name;
|
91
|
+
var type = typeof k;
|
92
|
+
|
93
|
+
if (type == "number")
|
94
|
+
name = '"' + k + '"';
|
95
|
+
else if (type == "string")
|
96
|
+
name = $.quoteString(k);
|
97
|
+
else
|
98
|
+
continue; //skip non-string or number keys
|
99
|
+
|
100
|
+
if (typeof o[k] == "function")
|
101
|
+
continue; //skip pairs where the value is a function.
|
102
|
+
|
103
|
+
var val = $.toJSON(o[k]);
|
104
|
+
|
105
|
+
pairs.push(name + ":" + val);
|
106
|
+
}
|
107
|
+
|
108
|
+
return "{" + pairs.join(", ") + "}";
|
109
|
+
}
|
110
|
+
};
|
111
|
+
|
112
|
+
/** jQuery.evalJSON(src)
|
113
|
+
Evaluates a given piece of json source.
|
114
|
+
**/
|
115
|
+
$.evalJSON = function(src)
|
116
|
+
{
|
117
|
+
if (typeof(JSON) == 'object' && JSON.parse)
|
118
|
+
return JSON.parse(src);
|
119
|
+
return eval("(" + src + ")");
|
120
|
+
};
|
121
|
+
|
122
|
+
/** jQuery.secureEvalJSON(src)
|
123
|
+
Evals JSON in a way that is *more* secure.
|
124
|
+
**/
|
125
|
+
$.secureEvalJSON = function(src)
|
126
|
+
{
|
127
|
+
if (typeof(JSON) == 'object' && JSON.parse)
|
128
|
+
return JSON.parse(src);
|
129
|
+
|
130
|
+
var filtered = src;
|
131
|
+
filtered = filtered.replace(/\\["\\\/bfnrtu]/g, '@');
|
132
|
+
filtered = filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
|
133
|
+
filtered = filtered.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
|
134
|
+
|
135
|
+
if (/^[\],:{}\s]*$/.test(filtered))
|
136
|
+
return eval("(" + src + ")");
|
137
|
+
else
|
138
|
+
throw new SyntaxError("Error parsing JSON, source is not valid.");
|
139
|
+
};
|
140
|
+
|
141
|
+
/** jQuery.quoteString(string)
|
142
|
+
Returns a string-repr of a string, escaping quotes intelligently.
|
143
|
+
Mostly a support function for toJSON.
|
144
|
+
|
145
|
+
Examples:
|
146
|
+
>>> jQuery.quoteString("apple")
|
147
|
+
"apple"
|
148
|
+
|
149
|
+
>>> jQuery.quoteString('"Where are we going?", she asked.')
|
150
|
+
"\"Where are we going?\", she asked."
|
151
|
+
**/
|
152
|
+
$.quoteString = function(string)
|
153
|
+
{
|
154
|
+
if (string.match(_escapeable))
|
155
|
+
{
|
156
|
+
return '"' + string.replace(_escapeable, function (a)
|
157
|
+
{
|
158
|
+
var c = _meta[a];
|
159
|
+
if (typeof c === 'string') return c;
|
160
|
+
c = a.charCodeAt();
|
161
|
+
return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
|
162
|
+
}) + '"';
|
163
|
+
}
|
164
|
+
return '"' + string + '"';
|
165
|
+
};
|
166
|
+
|
167
|
+
var _escapeable = /["\\\x00-\x1f\x7f-\x9f]/g;
|
168
|
+
|
169
|
+
var _meta = {
|
170
|
+
'\b': '\\b',
|
171
|
+
'\t': '\\t',
|
172
|
+
'\n': '\\n',
|
173
|
+
'\f': '\\f',
|
174
|
+
'\r': '\\r',
|
175
|
+
'"' : '\\"',
|
176
|
+
'\\': '\\\\'
|
177
|
+
};
|
178
|
+
})(jQuery);
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
(function($){$.toJSON=function(o)
|
3
|
+
{if(typeof(JSON)=='object'&&JSON.stringify)
|
4
|
+
return JSON.stringify(o);var type=typeof(o);if(o===null)
|
5
|
+
return"null";if(type=="undefined")
|
6
|
+
return undefined;if(type=="number"||type=="boolean")
|
7
|
+
return o+"";if(type=="string")
|
8
|
+
return $.quoteString(o);if(type=='object')
|
9
|
+
{if(typeof o.toJSON=="function")
|
10
|
+
return $.toJSON(o.toJSON());if(o.constructor===Date)
|
11
|
+
{var month=o.getUTCMonth()+1;if(month<10)month='0'+month;var day=o.getUTCDate();if(day<10)day='0'+day;var year=o.getUTCFullYear();var hours=o.getUTCHours();if(hours<10)hours='0'+hours;var minutes=o.getUTCMinutes();if(minutes<10)minutes='0'+minutes;var seconds=o.getUTCSeconds();if(seconds<10)seconds='0'+seconds;var milli=o.getUTCMilliseconds();if(milli<100)milli='0'+milli;if(milli<10)milli='0'+milli;return'"'+year+'-'+month+'-'+day+'T'+
|
12
|
+
hours+':'+minutes+':'+seconds+'.'+milli+'Z"';}
|
13
|
+
if(o.constructor===Array)
|
14
|
+
{var ret=[];for(var i=0;i<o.length;i++)
|
15
|
+
ret.push($.toJSON(o[i])||"null");return"["+ret.join(",")+"]";}
|
16
|
+
var pairs=[];for(var k in o){var name;var type=typeof k;if(type=="number")
|
17
|
+
name='"'+k+'"';else if(type=="string")
|
18
|
+
name=$.quoteString(k);else
|
19
|
+
continue;if(typeof o[k]=="function")
|
20
|
+
continue;var val=$.toJSON(o[k]);pairs.push(name+":"+val);}
|
21
|
+
return"{"+pairs.join(", ")+"}";}};$.evalJSON=function(src)
|
22
|
+
{if(typeof(JSON)=='object'&&JSON.parse)
|
23
|
+
return JSON.parse(src);return eval("("+src+")");};$.secureEvalJSON=function(src)
|
24
|
+
{if(typeof(JSON)=='object'&&JSON.parse)
|
25
|
+
return JSON.parse(src);var filtered=src;filtered=filtered.replace(/\\["\\\/bfnrtu]/g,'@');filtered=filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']');filtered=filtered.replace(/(?:^|:|,)(?:\s*\[)+/g,'');if(/^[\],:{}\s]*$/.test(filtered))
|
26
|
+
return eval("("+src+")");else
|
27
|
+
throw new SyntaxError("Error parsing JSON, source is not valid.");};$.quoteString=function(string)
|
28
|
+
{if(string.match(_escapeable))
|
29
|
+
{return'"'+string.replace(_escapeable,function(a)
|
30
|
+
{var c=_meta[a];if(typeof c==='string')return c;c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"';}
|
31
|
+
return'"'+string+'"';};var _escapeable=/["\\\x00-\x1f\x7f-\x9f]/g;var _meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};})(jQuery);
|
data/rails/init.rb
ADDED
data/rails/install.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
AJAX_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
2
|
+
|
3
|
+
%w[
|
4
|
+
app/controllers/ajax_controller.rb
|
5
|
+
app/views/ajax/framework.html.erb
|
6
|
+
config/initializers/ajax.rb
|
7
|
+
public/javascripts/ajax.js
|
8
|
+
public/javascripts/jquery.address-1.2rc.js
|
9
|
+
public/javascripts/jquery.address-1.2rc.min.js
|
10
|
+
public/javascripts/jquery.json-2.2.min.js
|
11
|
+
public/images/loading-icon-small.gif
|
12
|
+
].each do |file|
|
13
|
+
if File.exist?(File.join(Rails.root, file))
|
14
|
+
puts "skipped: #{file} exists!"
|
15
|
+
else
|
16
|
+
begin
|
17
|
+
FileUtils.cp(File.join(AJAX_ROOT, file), File.join(Rails.root, file))
|
18
|
+
puts "created: #{file}"
|
19
|
+
rescue Exception => e
|
20
|
+
puts "skipped: #{file} #{e.message}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/rails/uninstall.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Uninstall hook code here
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
context 'Ajax::UrlHelpers' do
|
4
|
+
DOMAINS = %w[musicsocial.com.local altnet.com amusicstreamingservice.com stage.altnet.com rails1.creagency.com.au]
|
5
|
+
|
6
|
+
describe "(URL) hashed_url_from_traditional" do
|
7
|
+
it "should handle a query string" do
|
8
|
+
Ajax.hashed_url_from_traditional('/Beyonce?one=1').should == '/#/Beyonce?one=1'
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should ignore the fragment" do
|
12
|
+
Ajax.hashed_url_from_traditional('/Beyonce?one=1#fragment').should == '/#/Beyonce?one=1'
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should handle no query string" do
|
16
|
+
Ajax.hashed_url_from_traditional('/Beyonce').should == '/#/Beyonce'
|
17
|
+
end
|
18
|
+
|
19
|
+
DOMAINS.each do |domain|
|
20
|
+
it "should work for domain #{domain}" do
|
21
|
+
Ajax.hashed_url_from_traditional("http://#{domain}/playlists").should == "http://#{domain}/#/playlists"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "(URL) hashed_url_from_fragment" do
|
27
|
+
it "should strip double slashes" do
|
28
|
+
Ajax.hashed_url_from_fragment('/Beyonce#/Akon').should == '/#/Akon'
|
29
|
+
Ajax.hashed_url_from_fragment('/Beyonce#Akon').should == '/#/Akon'
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should handle no fragment" do
|
33
|
+
Ajax.hashed_url_from_fragment('/Beyonce').should == '/#/'
|
34
|
+
end
|
35
|
+
|
36
|
+
DOMAINS.each do |domain|
|
37
|
+
it "should work for domain #{domain}" do
|
38
|
+
Ajax.hashed_url_from_fragment("http://#{domain}").should == "http://#{domain}/#/"
|
39
|
+
Ajax.hashed_url_from_fragment("http://#{domain}/").should == "http://#{domain}/#/"
|
40
|
+
Ajax.hashed_url_from_fragment("http://#{domain}/Beyonce/#/playlists").should == "http://#{domain}/#/playlists"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "(boolean) url_is_root?" do
|
46
|
+
it "should detect root urls" do
|
47
|
+
Ajax.url_is_root?('/#/Beyonce?query2').should be(true)
|
48
|
+
Ajax.url_is_root?('/').should be(true)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should detect non-root urls" do
|
52
|
+
Ajax.url_is_root?('/Beyonce').should be(false)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should support full URLs" do
|
56
|
+
Ajax.is_hashed_url?('http://musicsocial.com.local/#/playlists').should be(true)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "(boolean) is_hashed_url?" do
|
61
|
+
it "should return false for fragments that don't start with /" do
|
62
|
+
Ajax.is_hashed_url?('/Beyonce#Akon').should be(false)
|
63
|
+
Ajax.is_hashed_url?('/Beyonce?query#Akon/').should be(false)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should return false for no fragment" do
|
67
|
+
Ajax.is_hashed_url?('/Beyonce?query%23/').should be(false)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should return true if the fragment starts with /" do
|
71
|
+
Ajax.is_hashed_url?('/Beyonce#/Akon').should be(true)
|
72
|
+
Ajax.is_hashed_url?('/#/Akon').should be(true)
|
73
|
+
end
|
74
|
+
|
75
|
+
DOMAINS.each do |domain|
|
76
|
+
it "should work for domain #{domain}" do
|
77
|
+
Ajax.is_hashed_url?("http://#{domain}/#/playlists").should be(true)
|
78
|
+
Ajax.is_hashed_url?("http://#{domain}/playlists").should be(false)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "(URL) traditional_url_from_fragment" do
|
84
|
+
it "should handle slashes" do
|
85
|
+
Ajax.traditional_url_from_fragment('/Beyonce#Akon').should == '/Akon'
|
86
|
+
Ajax.traditional_url_from_fragment('/Beyonce#/Akon').should == '/Akon'
|
87
|
+
Ajax.traditional_url_from_fragment('/Beyonce#/Akon/').should == '/Akon/'
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should handle no fragment" do
|
91
|
+
Ajax.traditional_url_from_fragment('/Beyonce').should == '/'
|
92
|
+
end
|
93
|
+
|
94
|
+
DOMAINS.each do |domain|
|
95
|
+
it "should work for domain #{domain}" do
|
96
|
+
Ajax.traditional_url_from_fragment("http://#{domain}/Beyonce/#playlists").should == "http://#{domain}/playlists"
|
97
|
+
Ajax.traditional_url_from_fragment("http://#{domain}/Beyonce/#/playlists").should == "http://#{domain}/playlists"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
include Ajax::Helpers::RequestHelper
|
4
|
+
|
5
|
+
describe 'Ajax::Helpers::RequestHelpers' do
|
6
|
+
describe 'set_header' do
|
7
|
+
before :each do
|
8
|
+
@headers = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should add headers" do
|
12
|
+
set_header @headers, :tab, '#main .home_tab'
|
13
|
+
@headers['Ajax-Info']['tab'].should == '#main .home_tab'
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should add assets" do
|
17
|
+
set_header @headers, :assets, { :key => ['value'] }
|
18
|
+
@headers['Ajax-Info']['assets'].should == { :key => ['value'] }
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should merge hashes" do
|
22
|
+
set_header @headers, :assets, { :key => ['value1'] }
|
23
|
+
set_header @headers, :assets, { :key => ['value2'] }
|
24
|
+
@headers['Ajax-Info']['assets'].should == { :key => ['value1', 'value2'] }
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should concat arrays" do
|
28
|
+
set_header @headers, :callbacks, ['one']
|
29
|
+
set_header @headers, :callbacks, ['two']
|
30
|
+
@headers['Ajax-Info']['callbacks'].should == ['one', 'two']
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'uri'
|
3
|
+
require 'ajax/spec/helpers'
|
4
|
+
|
5
|
+
include Ajax::Spec::Helpers
|
6
|
+
|
7
|
+
# Test the Rack::Ajax handling of urls according to our block from
|
8
|
+
# <tt>config/initializers/ajax.rb</tt>
|
9
|
+
#
|
10
|
+
# Test Rack middleware using integration tests because the Spec controller tests
|
11
|
+
# do not invoke Rack.
|
12
|
+
context 'Rack::Ajax' do
|
13
|
+
before :all do
|
14
|
+
mock_ajax # Force a return from Rack::Ajax
|
15
|
+
end
|
16
|
+
|
17
|
+
after :all do
|
18
|
+
unmock_ajax
|
19
|
+
end
|
20
|
+
|
21
|
+
context "XMLHttpRequest" do
|
22
|
+
context "hashed url" do
|
23
|
+
it "should rewrite GET request" do
|
24
|
+
xhr(:get, '/?query1#/Beyonce?query2')
|
25
|
+
should_rewrite_to('/Beyonce?query2')
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should not modify POST" do
|
29
|
+
xhr(:post, '/#/user_session/new?param1=1¶m2=2')
|
30
|
+
should_not_modify_request
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "traditional url" do
|
35
|
+
it "should not be modified" do
|
36
|
+
xhr(:get, '/Beyonce')
|
37
|
+
should_not_modify_request
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should not be modified" do
|
41
|
+
xhr(:post, '/user_session/new?param1=1¶m2=2')
|
42
|
+
should_not_modify_request
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "request for root url" do
|
48
|
+
it "should not be modified" do
|
49
|
+
get('/')
|
50
|
+
should_not_modify_request
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should not be modified" do
|
54
|
+
get('/?query_string')
|
55
|
+
should_not_modify_request
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should be rewritten if it is hashed" do
|
59
|
+
get('/?query1#/Beyonce?query2')
|
60
|
+
should_rewrite_to('/Beyonce?query2')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "robot" do
|
65
|
+
before :each do
|
66
|
+
@user = login_robot_user
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should not modify request for root" do
|
70
|
+
get('/')
|
71
|
+
should_not_modify_request
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should not modify traditional requests" do
|
75
|
+
get('/Beyonce')
|
76
|
+
should_not_modify_request
|
77
|
+
end
|
78
|
+
|
79
|
+
context "request hashed" do
|
80
|
+
context "non-root url" do
|
81
|
+
it "should not modify the request" do
|
82
|
+
get('/Akon/?query1#/Beyonce?query2')
|
83
|
+
should_not_modify_request
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "root url" do
|
88
|
+
it "should rewrite to traditional url" do
|
89
|
+
get('/#/Beyonce?query2')
|
90
|
+
should_rewrite_to('/Beyonce?query2')
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "regular user" do
|
97
|
+
it "should not modify request for root" do
|
98
|
+
get('/')
|
99
|
+
should_not_modify_request
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should ignore query string on root url" do
|
103
|
+
get('/?query1#/Beyonce?query2')
|
104
|
+
should_rewrite_to('/Beyonce?query2')
|
105
|
+
end
|
106
|
+
|
107
|
+
context "request hashed" do
|
108
|
+
context "non-root url" do
|
109
|
+
it "should redirect to hashed part at root" do
|
110
|
+
get('/Akon/?query1#/Beyonce?query2')
|
111
|
+
should_redirect_to('/#/Beyonce?query2')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context "root url" do
|
116
|
+
it "should rewrite to traditional url" do
|
117
|
+
get('/#/Beyonce?query2')
|
118
|
+
should_rewrite_to('/Beyonce?query2')
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context "request traditional url" do
|
124
|
+
it "should not be modified" do
|
125
|
+
get('/')
|
126
|
+
should_not_modify_request
|
127
|
+
end
|
128
|
+
it "should not be modified" do
|
129
|
+
get('/?query_string')
|
130
|
+
should_not_modify_request
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should redirect GET request" do
|
134
|
+
get('/Beyonce')
|
135
|
+
should_redirect_to('/#/Beyonce')
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should not modify non-GET request" do
|
139
|
+
%w[post put delete].each do |method|
|
140
|
+
send(method, '/')
|
141
|
+
should_not_modify_request
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|