amplify 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/app/assets/javascripts/amplify/core.js.erb +96 -0
- data/app/assets/javascripts/amplify/index.js.erb +1 -0
- data/app/assets/javascripts/amplify/request.js.erb +337 -0
- data/app/assets/javascripts/amplify/store.js.erb +278 -0
- data/lib/amplify.rb +2 -0
- data/lib/amplify/engine.rb +3 -0
- data/lib/amplify/version.rb +3 -0
- metadata +113 -0
@@ -0,0 +1,96 @@
|
|
1
|
+
/*!
|
2
|
+
* Amplify Core <%= Amplify::VERSION %>
|
3
|
+
*
|
4
|
+
* Copyright 2011 appendTo LLC. (http://appendto.com/team)
|
5
|
+
* Dual licensed under the MIT or GPL licenses.
|
6
|
+
* http://appendto.com/open-source-licenses
|
7
|
+
*
|
8
|
+
* http://amplifyjs.com
|
9
|
+
*/
|
10
|
+
(function( global, undefined ) {
|
11
|
+
|
12
|
+
var slice = [].slice,
|
13
|
+
subscriptions = {};
|
14
|
+
|
15
|
+
var amplify = global.amplify = {
|
16
|
+
publish: function( topic ) {
|
17
|
+
var args = slice.call( arguments, 1 ),
|
18
|
+
subscription,
|
19
|
+
length,
|
20
|
+
i = 0,
|
21
|
+
ret;
|
22
|
+
|
23
|
+
if ( !subscriptions[ topic ] ) {
|
24
|
+
return true;
|
25
|
+
}
|
26
|
+
|
27
|
+
for ( length = subscriptions[ topic ].length; i < length; i++ ) {
|
28
|
+
subscription = subscriptions[ topic ][ i ];
|
29
|
+
ret = subscription.callback.apply( subscription.context, args );
|
30
|
+
if ( ret === false ) {
|
31
|
+
break;
|
32
|
+
}
|
33
|
+
}
|
34
|
+
return ret !== false;
|
35
|
+
},
|
36
|
+
|
37
|
+
subscribe: function( topic, context, callback, priority ) {
|
38
|
+
if ( arguments.length === 3 && typeof callback === "number" ) {
|
39
|
+
priority = callback;
|
40
|
+
callback = context;
|
41
|
+
context = null;
|
42
|
+
}
|
43
|
+
if ( arguments.length === 2 ) {
|
44
|
+
callback = context;
|
45
|
+
context = null;
|
46
|
+
}
|
47
|
+
priority = priority || 10;
|
48
|
+
|
49
|
+
var topicIndex = 0,
|
50
|
+
topics = topic.split( /\s/ ),
|
51
|
+
topicLength = topics.length;
|
52
|
+
for ( ; topicIndex < topicLength; topicIndex++ ) {
|
53
|
+
topic = topics[ topicIndex ];
|
54
|
+
if ( !subscriptions[ topic ] ) {
|
55
|
+
subscriptions[ topic ] = [];
|
56
|
+
}
|
57
|
+
|
58
|
+
var i = subscriptions[ topic ].length - 1,
|
59
|
+
subscriptionInfo = {
|
60
|
+
callback: callback,
|
61
|
+
context: context,
|
62
|
+
priority: priority
|
63
|
+
};
|
64
|
+
|
65
|
+
for ( ; i >= 0; i-- ) {
|
66
|
+
if ( subscriptions[ topic ][ i ].priority <= priority ) {
|
67
|
+
subscriptions[ topic ].splice( i + 1, 0, subscriptionInfo );
|
68
|
+
return callback;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
subscriptions[ topic ].unshift( subscriptionInfo );
|
73
|
+
}
|
74
|
+
|
75
|
+
return callback;
|
76
|
+
},
|
77
|
+
|
78
|
+
unsubscribe: function( topic, callback ) {
|
79
|
+
if ( !subscriptions[ topic ] ) {
|
80
|
+
return;
|
81
|
+
}
|
82
|
+
|
83
|
+
var length = subscriptions[ topic ].length,
|
84
|
+
i = 0;
|
85
|
+
|
86
|
+
for ( ; i < length; i++ ) {
|
87
|
+
if ( subscriptions[ topic ][ i ].callback === callback ) {
|
88
|
+
subscriptions[ topic ].splice( i, 1 );
|
89
|
+
break;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
}
|
93
|
+
};
|
94
|
+
|
95
|
+
}( this ) );
|
96
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require_tree .
|
@@ -0,0 +1,337 @@
|
|
1
|
+
//= require amplify/core
|
2
|
+
/*!
|
3
|
+
* Amplify Request <%= Amplify::VERSION %>
|
4
|
+
*
|
5
|
+
* Copyright 2011 appendTo LLC. (http://appendto.com/team)
|
6
|
+
* Dual licensed under the MIT or GPL licenses.
|
7
|
+
* http://appendto.com/open-source-licenses
|
8
|
+
*
|
9
|
+
* http://amplifyjs.com
|
10
|
+
*/
|
11
|
+
(function( amplify, undefined ) {
|
12
|
+
|
13
|
+
function noop() {}
|
14
|
+
function isFunction( obj ) {
|
15
|
+
return ({}).toString.call( obj ) === "[object Function]";
|
16
|
+
}
|
17
|
+
|
18
|
+
amplify.request = function( resourceId, data, callback ) {
|
19
|
+
// default to an empty hash just so we can handle a missing resourceId
|
20
|
+
// in one place
|
21
|
+
var settings = resourceId || {};
|
22
|
+
|
23
|
+
if ( typeof settings === "string" ) {
|
24
|
+
if ( isFunction( data ) ) {
|
25
|
+
callback = data;
|
26
|
+
data = {};
|
27
|
+
}
|
28
|
+
settings = {
|
29
|
+
resourceId: resourceId,
|
30
|
+
data: data || {},
|
31
|
+
success: callback
|
32
|
+
};
|
33
|
+
}
|
34
|
+
|
35
|
+
var request = { abort: noop },
|
36
|
+
resource = amplify.request.resources[ settings.resourceId ],
|
37
|
+
success = settings.success || noop,
|
38
|
+
error = settings.error || noop;
|
39
|
+
settings.success = function( data, status ) {
|
40
|
+
status = status || "success";
|
41
|
+
amplify.publish( "request.success", settings, data, status );
|
42
|
+
amplify.publish( "request.complete", settings, data, status );
|
43
|
+
success( data, status );
|
44
|
+
};
|
45
|
+
settings.error = function( data, status ) {
|
46
|
+
status = status || "error";
|
47
|
+
amplify.publish( "request.error", settings, data, status );
|
48
|
+
amplify.publish( "request.complete", settings, data, status );
|
49
|
+
error( data, status );
|
50
|
+
};
|
51
|
+
|
52
|
+
if ( !resource ) {
|
53
|
+
if ( !settings.resourceId ) {
|
54
|
+
throw "amplify.request: no resourceId provided";
|
55
|
+
}
|
56
|
+
throw "amplify.request: unknown resourceId: " + settings.resourceId;
|
57
|
+
}
|
58
|
+
|
59
|
+
if ( !amplify.publish( "request.before", settings ) ) {
|
60
|
+
settings.error( null, "abort" );
|
61
|
+
return;
|
62
|
+
}
|
63
|
+
|
64
|
+
amplify.request.resources[ settings.resourceId ]( settings, request );
|
65
|
+
return request;
|
66
|
+
};
|
67
|
+
|
68
|
+
amplify.request.types = {};
|
69
|
+
amplify.request.resources = {};
|
70
|
+
amplify.request.define = function( resourceId, type, settings ) {
|
71
|
+
if ( typeof type === "string" ) {
|
72
|
+
if ( !( type in amplify.request.types ) ) {
|
73
|
+
throw "amplify.request.define: unknown type: " + type;
|
74
|
+
}
|
75
|
+
|
76
|
+
settings.resourceId = resourceId;
|
77
|
+
amplify.request.resources[ resourceId ] =
|
78
|
+
amplify.request.types[ type ]( settings );
|
79
|
+
} else {
|
80
|
+
// no pre-processor or settings for one-off types (don't invoke)
|
81
|
+
amplify.request.resources[ resourceId ] = type;
|
82
|
+
}
|
83
|
+
};
|
84
|
+
|
85
|
+
}( amplify ) );
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
(function( amplify, $, undefined ) {
|
92
|
+
|
93
|
+
var xhrProps = [ "status", "statusText", "responseText", "responseXML", "readyState" ],
|
94
|
+
rurlData = /\{([^\}]+)\}/g;
|
95
|
+
|
96
|
+
amplify.request.types.ajax = function( defnSettings ) {
|
97
|
+
defnSettings = $.extend({
|
98
|
+
type: "GET"
|
99
|
+
}, defnSettings );
|
100
|
+
|
101
|
+
return function( settings, request ) {
|
102
|
+
var xhr,
|
103
|
+
url = defnSettings.url,
|
104
|
+
data = settings.data,
|
105
|
+
abort = request.abort,
|
106
|
+
ajaxSettings = {},
|
107
|
+
mappedKeys = [],
|
108
|
+
aborted = false,
|
109
|
+
ampXHR = {
|
110
|
+
readyState: 0,
|
111
|
+
setRequestHeader: function( name, value ) {
|
112
|
+
return xhr.setRequestHeader( name, value );
|
113
|
+
},
|
114
|
+
getAllResponseHeaders: function() {
|
115
|
+
return xhr.getAllResponseHeaders();
|
116
|
+
},
|
117
|
+
getResponseHeader: function( key ) {
|
118
|
+
return xhr.getResponseHeader( key );
|
119
|
+
},
|
120
|
+
overrideMimeType: function( type ) {
|
121
|
+
return xhr.overrideMideType( type );
|
122
|
+
},
|
123
|
+
abort: function() {
|
124
|
+
aborted = true;
|
125
|
+
try {
|
126
|
+
xhr.abort();
|
127
|
+
// IE 7 throws an error when trying to abort
|
128
|
+
} catch( e ) {}
|
129
|
+
handleResponse( null, "abort" );
|
130
|
+
},
|
131
|
+
success: function( data, status ) {
|
132
|
+
settings.success( data, status );
|
133
|
+
},
|
134
|
+
error: function( data, status ) {
|
135
|
+
settings.error( data, status );
|
136
|
+
}
|
137
|
+
};
|
138
|
+
|
139
|
+
if ( typeof data !== "string" ) {
|
140
|
+
data = $.extend( true, {}, defnSettings.data, data );
|
141
|
+
|
142
|
+
url = url.replace( rurlData, function ( m, key ) {
|
143
|
+
if ( key in data ) {
|
144
|
+
mappedKeys.push( key );
|
145
|
+
return data[ key ];
|
146
|
+
}
|
147
|
+
});
|
148
|
+
|
149
|
+
// We delete the keys later so duplicates are still replaced
|
150
|
+
$.each( mappedKeys, function ( i, key ) {
|
151
|
+
delete data[ key ];
|
152
|
+
});
|
153
|
+
}
|
154
|
+
|
155
|
+
$.extend( ajaxSettings, defnSettings, {
|
156
|
+
url: url,
|
157
|
+
type: defnSettings.type,
|
158
|
+
data: data,
|
159
|
+
dataType: defnSettings.dataType,
|
160
|
+
success: function( data, status ) {
|
161
|
+
handleResponse( data, status );
|
162
|
+
},
|
163
|
+
error: function( _xhr, status ) {
|
164
|
+
handleResponse( null, status );
|
165
|
+
},
|
166
|
+
beforeSend: function( _xhr, _ajaxSettings ) {
|
167
|
+
xhr = _xhr;
|
168
|
+
ajaxSettings = _ajaxSettings;
|
169
|
+
var ret = defnSettings.beforeSend ?
|
170
|
+
defnSettings.beforeSend.call( this, ampXHR, ajaxSettings ) : true;
|
171
|
+
return ret && amplify.publish( "request.before.ajax",
|
172
|
+
defnSettings, settings, ajaxSettings, ampXHR );
|
173
|
+
}
|
174
|
+
});
|
175
|
+
$.ajax( ajaxSettings );
|
176
|
+
|
177
|
+
function handleResponse( data, status ) {
|
178
|
+
$.each( xhrProps, function( i, key ) {
|
179
|
+
try {
|
180
|
+
ampXHR[ key ] = xhr[ key ];
|
181
|
+
} catch( e ) {}
|
182
|
+
});
|
183
|
+
// Playbook returns "HTTP/1.1 200 OK"
|
184
|
+
// TODO: something also returns "OK", what?
|
185
|
+
if ( /OK$/.test( ampXHR.statusText ) ) {
|
186
|
+
ampXHR.statusText = "success";
|
187
|
+
}
|
188
|
+
if ( data === undefined ) {
|
189
|
+
// TODO: add support for ajax errors with data
|
190
|
+
data = null;
|
191
|
+
}
|
192
|
+
if ( aborted ) {
|
193
|
+
status = "abort";
|
194
|
+
}
|
195
|
+
if ( /timeout|error|abort/.test( status ) ) {
|
196
|
+
ampXHR.error( data, status );
|
197
|
+
} else {
|
198
|
+
ampXHR.success( data, status );
|
199
|
+
}
|
200
|
+
// avoid handling a response multiple times
|
201
|
+
// this can happen if a request is aborted
|
202
|
+
// TODO: figure out if this breaks polling or multi-part responses
|
203
|
+
handleResponse = $.noop;
|
204
|
+
}
|
205
|
+
|
206
|
+
request.abort = function() {
|
207
|
+
ampXHR.abort();
|
208
|
+
abort.call( this );
|
209
|
+
};
|
210
|
+
};
|
211
|
+
};
|
212
|
+
|
213
|
+
|
214
|
+
|
215
|
+
var cache = amplify.request.cache = {
|
216
|
+
_key: function( resourceId, url, data ) {
|
217
|
+
data = url + data;
|
218
|
+
var length = data.length,
|
219
|
+
i = 0,
|
220
|
+
checksum = chunk();
|
221
|
+
|
222
|
+
while ( i < length ) {
|
223
|
+
checksum ^= chunk();
|
224
|
+
}
|
225
|
+
|
226
|
+
function chunk() {
|
227
|
+
return data.charCodeAt( i++ ) << 24 |
|
228
|
+
data.charCodeAt( i++ ) << 16 |
|
229
|
+
data.charCodeAt( i++ ) << 8 |
|
230
|
+
data.charCodeAt( i++ ) << 0;
|
231
|
+
}
|
232
|
+
|
233
|
+
return "request-" + resourceId + "-" + checksum;
|
234
|
+
},
|
235
|
+
|
236
|
+
_default: (function() {
|
237
|
+
var memoryStore = {};
|
238
|
+
return function( resource, settings, ajaxSettings, ampXHR ) {
|
239
|
+
// data is already converted to a string by the time we get here
|
240
|
+
var cacheKey = cache._key( settings.resourceId,
|
241
|
+
ajaxSettings.url, ajaxSettings.data ),
|
242
|
+
duration = resource.cache;
|
243
|
+
|
244
|
+
if ( cacheKey in memoryStore ) {
|
245
|
+
ampXHR.success( memoryStore[ cacheKey ] );
|
246
|
+
return false;
|
247
|
+
}
|
248
|
+
var success = ampXHR.success;
|
249
|
+
ampXHR.success = function( data ) {
|
250
|
+
memoryStore[ cacheKey ] = data;
|
251
|
+
if ( typeof duration === "number" ) {
|
252
|
+
setTimeout(function() {
|
253
|
+
delete memoryStore[ cacheKey ];
|
254
|
+
}, duration );
|
255
|
+
}
|
256
|
+
success.apply( this, arguments );
|
257
|
+
};
|
258
|
+
};
|
259
|
+
}())
|
260
|
+
};
|
261
|
+
|
262
|
+
if ( amplify.store ) {
|
263
|
+
$.each( amplify.store.types, function( type ) {
|
264
|
+
cache[ type ] = function( resource, settings, ajaxSettings, ampXHR ) {
|
265
|
+
var cacheKey = cache._key( settings.resourceId,
|
266
|
+
ajaxSettings.url, ajaxSettings.data ),
|
267
|
+
cached = amplify.store[ type ]( cacheKey );
|
268
|
+
|
269
|
+
if ( cached ) {
|
270
|
+
ajaxSettings.success( cached );
|
271
|
+
return false;
|
272
|
+
}
|
273
|
+
var success = ampXHR.success;
|
274
|
+
ampXHR.success = function( data ) {
|
275
|
+
amplify.store[ type ]( cacheKey, data, { expires: resource.cache.expires } );
|
276
|
+
success.apply( this, arguments );
|
277
|
+
};
|
278
|
+
};
|
279
|
+
});
|
280
|
+
cache.persist = cache[ amplify.store.type ];
|
281
|
+
}
|
282
|
+
|
283
|
+
amplify.subscribe( "request.before.ajax", function( resource ) {
|
284
|
+
var cacheType = resource.cache;
|
285
|
+
if ( cacheType ) {
|
286
|
+
// normalize between objects and strings/booleans/numbers
|
287
|
+
cacheType = cacheType.type || cacheType;
|
288
|
+
return cache[ cacheType in cache ? cacheType : "_default" ]
|
289
|
+
.apply( this, arguments );
|
290
|
+
}
|
291
|
+
});
|
292
|
+
|
293
|
+
|
294
|
+
|
295
|
+
amplify.request.decoders = {
|
296
|
+
// http://labs.omniti.com/labs/jsend
|
297
|
+
jsend: function( data, status, ampXHR, success, error ) {
|
298
|
+
if ( data.status === "success" ) {
|
299
|
+
success( data.data );
|
300
|
+
} else if ( data.status === "fail" ) {
|
301
|
+
error( data.data, "fail" );
|
302
|
+
} else if ( data.status === "error" ) {
|
303
|
+
delete data.status;
|
304
|
+
error( data, "error" );
|
305
|
+
}
|
306
|
+
}
|
307
|
+
};
|
308
|
+
|
309
|
+
amplify.subscribe( "request.before.ajax", function( resource, settings, ajaxSettings, ampXHR ) {
|
310
|
+
var _success = ampXHR.success,
|
311
|
+
_error = ampXHR.error,
|
312
|
+
decoder = $.isFunction( resource.decoder )
|
313
|
+
? resource.decoder
|
314
|
+
: resource.decoder in amplify.request.decoders
|
315
|
+
? amplify.request.decoders[ resource.decoder ]
|
316
|
+
: amplify.request.decoders._default;
|
317
|
+
|
318
|
+
if ( !decoder ) {
|
319
|
+
return;
|
320
|
+
}
|
321
|
+
|
322
|
+
function success( data, status ) {
|
323
|
+
_success( data, status );
|
324
|
+
}
|
325
|
+
function error( data, status ) {
|
326
|
+
_error( data, status );
|
327
|
+
}
|
328
|
+
ampXHR.success = function( data, status ) {
|
329
|
+
decoder( data, status, ampXHR, success, error );
|
330
|
+
};
|
331
|
+
ampXHR.error = function( data, status ) {
|
332
|
+
decoder( data, status, ampXHR, success, error );
|
333
|
+
};
|
334
|
+
});
|
335
|
+
|
336
|
+
}( amplify, jQuery ) );
|
337
|
+
|
@@ -0,0 +1,278 @@
|
|
1
|
+
/*!
|
2
|
+
* Amplify Store - Persistent Client-Side Storage <%= Amplify::VERSION %>
|
3
|
+
*
|
4
|
+
* Copyright 2011 appendTo LLC. (http://appendto.com/team)
|
5
|
+
* Dual licensed under the MIT or GPL licenses.
|
6
|
+
* http://appendto.com/open-source-licenses
|
7
|
+
*
|
8
|
+
* http://amplifyjs.com
|
9
|
+
*/
|
10
|
+
(function( amplify, undefined ) {
|
11
|
+
|
12
|
+
var store = amplify.store = function( key, value, options, type ) {
|
13
|
+
var type = store.type;
|
14
|
+
if ( options && options.type && options.type in store.types ) {
|
15
|
+
type = options.type;
|
16
|
+
}
|
17
|
+
return store.types[ type ]( key, value, options || {} );
|
18
|
+
};
|
19
|
+
|
20
|
+
store.types = {};
|
21
|
+
store.type = null;
|
22
|
+
store.addType = function( type, storage ) {
|
23
|
+
if ( !store.type ) {
|
24
|
+
store.type = type;
|
25
|
+
}
|
26
|
+
|
27
|
+
store.types[ type ] = storage;
|
28
|
+
store[ type ] = function( key, value, options ) {
|
29
|
+
options = options || {};
|
30
|
+
options.type = type;
|
31
|
+
return store( key, value, options );
|
32
|
+
};
|
33
|
+
}
|
34
|
+
store.error = function() {
|
35
|
+
return "amplify.store quota exceeded";
|
36
|
+
};
|
37
|
+
|
38
|
+
var rprefix = /^__amplify__/;
|
39
|
+
function createFromStorageInterface( storageType, storage ) {
|
40
|
+
store.addType( storageType, function( key, value, options ) {
|
41
|
+
var storedValue, parsed, i, remove,
|
42
|
+
ret = value,
|
43
|
+
now = (new Date()).getTime();
|
44
|
+
|
45
|
+
if ( !key ) {
|
46
|
+
ret = {};
|
47
|
+
remove = [];
|
48
|
+
i = 0;
|
49
|
+
try {
|
50
|
+
// accessing the length property works around a localStorage bug
|
51
|
+
// in Firefox 4.0 where the keys don't update cross-page
|
52
|
+
// we assign to key just to avoid Closure Compiler from removing
|
53
|
+
// the access as "useless code"
|
54
|
+
// https://bugzilla.mozilla.org/show_bug.cgi?id=662511
|
55
|
+
key = storage.length;
|
56
|
+
|
57
|
+
while ( key = storage.key( i++ ) ) {
|
58
|
+
if ( rprefix.test( key ) ) {
|
59
|
+
parsed = JSON.parse( storage.getItem( key ) );
|
60
|
+
if ( parsed.expires && parsed.expires <= now ) {
|
61
|
+
remove.push( key );
|
62
|
+
} else {
|
63
|
+
ret[ key.replace( rprefix, "" ) ] = parsed.data;
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
while ( key = remove.pop() ) {
|
68
|
+
storage.removeItem( key );
|
69
|
+
}
|
70
|
+
} catch ( error ) {}
|
71
|
+
return ret;
|
72
|
+
}
|
73
|
+
|
74
|
+
// protect against name collisions with direct storage
|
75
|
+
key = "__amplify__" + key;
|
76
|
+
|
77
|
+
if ( value === undefined ) {
|
78
|
+
storedValue = storage.getItem( key );
|
79
|
+
parsed = storedValue ? JSON.parse( storedValue ) : { expires: -1 };
|
80
|
+
if ( parsed.expires && parsed.expires <= now ) {
|
81
|
+
storage.removeItem( key );
|
82
|
+
} else {
|
83
|
+
return parsed.data;
|
84
|
+
}
|
85
|
+
} else {
|
86
|
+
if ( value === null ) {
|
87
|
+
storage.removeItem( key );
|
88
|
+
} else {
|
89
|
+
parsed = JSON.stringify({
|
90
|
+
data: value,
|
91
|
+
expires: options.expires ? now + options.expires : null
|
92
|
+
});
|
93
|
+
try {
|
94
|
+
storage.setItem( key, parsed );
|
95
|
+
// quota exceeded
|
96
|
+
} catch( error ) {
|
97
|
+
// expire old data and try again
|
98
|
+
store[ storageType ]();
|
99
|
+
try {
|
100
|
+
storage.setItem( key, parsed );
|
101
|
+
} catch( error ) {
|
102
|
+
throw store.error();
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
return ret;
|
109
|
+
});
|
110
|
+
}
|
111
|
+
|
112
|
+
// localStorage + sessionStorage
|
113
|
+
// IE 8+, Firefox 3.5+, Safari 4+, Chrome 4+, Opera 10.5+, iPhone 2+, Android 2+
|
114
|
+
for ( var webStorageType in { localStorage: 1, sessionStorage: 1 } ) {
|
115
|
+
// try/catch for file protocol in Firefox
|
116
|
+
try {
|
117
|
+
if ( window[ webStorageType ].getItem ) {
|
118
|
+
createFromStorageInterface( webStorageType, window[ webStorageType ] );
|
119
|
+
}
|
120
|
+
} catch( e ) {}
|
121
|
+
}
|
122
|
+
|
123
|
+
// globalStorage
|
124
|
+
// non-standard: Firefox 2+
|
125
|
+
// https://developer.mozilla.org/en/dom/storage#globalStorage
|
126
|
+
if ( window.globalStorage ) {
|
127
|
+
// try/catch for file protocol in Firefox
|
128
|
+
try {
|
129
|
+
createFromStorageInterface( "globalStorage",
|
130
|
+
window.globalStorage[ window.location.hostname ] );
|
131
|
+
// Firefox 2.0 and 3.0 have sessionStorage and globalStorage
|
132
|
+
// make sure we default to globalStorage
|
133
|
+
// but don't default to globalStorage in 3.5+ which also has localStorage
|
134
|
+
if ( store.type === "sessionStorage" ) {
|
135
|
+
store.type = "globalStorage";
|
136
|
+
}
|
137
|
+
} catch( e ) {}
|
138
|
+
}
|
139
|
+
|
140
|
+
// userData
|
141
|
+
// non-standard: IE 5+
|
142
|
+
// http://msdn.microsoft.com/en-us/library/ms531424(v=vs.85).aspx
|
143
|
+
(function() {
|
144
|
+
// IE 9 has quirks in userData that are a huge pain
|
145
|
+
// rather than finding a way to detect these quirks
|
146
|
+
// we just don't register userData if we have localStorage
|
147
|
+
if ( store.types.localStorage ) {
|
148
|
+
return;
|
149
|
+
}
|
150
|
+
|
151
|
+
// append to html instead of body so we can do this from the head
|
152
|
+
var div = document.createElement( "div" ),
|
153
|
+
attrKey = "amplify";
|
154
|
+
div.style.display = "none";
|
155
|
+
document.getElementsByTagName( "head" )[ 0 ].appendChild( div );
|
156
|
+
if ( div.addBehavior ) {
|
157
|
+
div.addBehavior( "#default#userdata" );
|
158
|
+
|
159
|
+
store.addType( "userData", function( key, value, options ) {
|
160
|
+
div.load( attrKey );
|
161
|
+
var attr, parsed, prevValue, i, remove,
|
162
|
+
ret = value,
|
163
|
+
now = (new Date()).getTime();
|
164
|
+
|
165
|
+
if ( !key ) {
|
166
|
+
ret = {};
|
167
|
+
remove = [];
|
168
|
+
i = 0;
|
169
|
+
while ( attr = div.XMLDocument.documentElement.attributes[ i++ ] ) {
|
170
|
+
parsed = JSON.parse( attr.value );
|
171
|
+
if ( parsed.expires && parsed.expires <= now ) {
|
172
|
+
remove.push( attr.name );
|
173
|
+
} else {
|
174
|
+
ret[ attr.name ] = parsed.data;
|
175
|
+
}
|
176
|
+
}
|
177
|
+
while ( key = remove.pop() ) {
|
178
|
+
div.removeAttribute( key );
|
179
|
+
}
|
180
|
+
div.save( attrKey );
|
181
|
+
return ret;
|
182
|
+
}
|
183
|
+
|
184
|
+
// convert invalid characters to dashes
|
185
|
+
// http://www.w3.org/TR/REC-xml/#NT-Name
|
186
|
+
// simplified to assume the starting character is valid
|
187
|
+
// also removed colon as it is invalid in HTML attribute names
|
188
|
+
key = key.replace( /[^-._0-9A-Za-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u37f-\u1fff\u200c-\u200d\u203f\u2040\u2070-\u218f]/g, "-" );
|
189
|
+
|
190
|
+
if ( value === undefined ) {
|
191
|
+
attr = div.getAttribute( key );
|
192
|
+
parsed = attr ? JSON.parse( attr ) : { expires: -1 };
|
193
|
+
if ( parsed.expires && parsed.expires <= now ) {
|
194
|
+
div.removeAttribute( key );
|
195
|
+
} else {
|
196
|
+
return parsed.data;
|
197
|
+
}
|
198
|
+
} else {
|
199
|
+
if ( value === null ) {
|
200
|
+
div.removeAttribute( key );
|
201
|
+
} else {
|
202
|
+
// we need to get the previous value in case we need to rollback
|
203
|
+
prevValue = div.getAttribute( key );
|
204
|
+
parsed = JSON.stringify({
|
205
|
+
data: value,
|
206
|
+
expires: (options.expires ? (now + options.expires) : null)
|
207
|
+
});
|
208
|
+
div.setAttribute( key, parsed );
|
209
|
+
}
|
210
|
+
}
|
211
|
+
|
212
|
+
try {
|
213
|
+
div.save( attrKey );
|
214
|
+
// quota exceeded
|
215
|
+
} catch ( error ) {
|
216
|
+
// roll the value back to the previous value
|
217
|
+
if ( prevValue === null ) {
|
218
|
+
div.removeAttribute( key );
|
219
|
+
} else {
|
220
|
+
div.setAttribute( key, prevValue );
|
221
|
+
}
|
222
|
+
|
223
|
+
// expire old data and try again
|
224
|
+
store.userData();
|
225
|
+
try {
|
226
|
+
div.setAttribute( key, parsed );
|
227
|
+
div.save( attrKey );
|
228
|
+
} catch ( error ) {
|
229
|
+
// roll the value back to the previous value
|
230
|
+
if ( prevValue === null ) {
|
231
|
+
div.removeAttribute( key );
|
232
|
+
} else {
|
233
|
+
div.setAttribute( key, prevValue );
|
234
|
+
}
|
235
|
+
throw store.error();
|
236
|
+
}
|
237
|
+
}
|
238
|
+
return ret;
|
239
|
+
});
|
240
|
+
}
|
241
|
+
}() );
|
242
|
+
|
243
|
+
// in-memory storage
|
244
|
+
// fallback for all browsers to enable the API even if we can't persist data
|
245
|
+
(function() {
|
246
|
+
var memory = {};
|
247
|
+
|
248
|
+
function copy( obj ) {
|
249
|
+
return obj === undefined ? undefined : JSON.parse( JSON.stringify( obj ) );
|
250
|
+
}
|
251
|
+
|
252
|
+
store.addType( "memory", function( key, value, options ) {
|
253
|
+
if ( !key ) {
|
254
|
+
return copy( memory );
|
255
|
+
}
|
256
|
+
|
257
|
+
if ( value === undefined ) {
|
258
|
+
return copy( memory[ key ] );
|
259
|
+
}
|
260
|
+
|
261
|
+
if ( value === null ) {
|
262
|
+
delete memory[ key ];
|
263
|
+
return null;
|
264
|
+
}
|
265
|
+
|
266
|
+
memory[ key ] = value;
|
267
|
+
if ( options.expires ) {
|
268
|
+
setTimeout(function() {
|
269
|
+
delete memory[ key ];
|
270
|
+
}, options.expires );
|
271
|
+
}
|
272
|
+
|
273
|
+
return value;
|
274
|
+
});
|
275
|
+
}() );
|
276
|
+
|
277
|
+
}( this.amplify = this.amplify || {} ) );
|
278
|
+
|
data/lib/amplify.rb
ADDED
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: amplify
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 21
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 1.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- "Scott Gonz\xC3\xA1lez"
|
14
|
+
- Andrew Wirick
|
15
|
+
- Jonathan Sharp
|
16
|
+
- Douglas Neiner
|
17
|
+
- Ralph Whitbeck
|
18
|
+
- Andrew Powell
|
19
|
+
- Elijah Manor
|
20
|
+
autorequire:
|
21
|
+
bindir: bin
|
22
|
+
cert_chain: []
|
23
|
+
|
24
|
+
date: 2011-06-29 00:00:00 -05:00
|
25
|
+
default_executable:
|
26
|
+
dependencies:
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: jquery-rails
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ~>
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
hash: 15
|
36
|
+
segments:
|
37
|
+
- 1
|
38
|
+
- 0
|
39
|
+
- 12
|
40
|
+
version: 1.0.12
|
41
|
+
type: :runtime
|
42
|
+
version_requirements: *id001
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: sprockets
|
45
|
+
prerelease: false
|
46
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
hash: 62196471
|
52
|
+
segments:
|
53
|
+
- 2
|
54
|
+
- 0
|
55
|
+
- 0
|
56
|
+
- beta
|
57
|
+
- 10
|
58
|
+
version: 2.0.0.beta.10
|
59
|
+
type: :runtime
|
60
|
+
version_requirements: *id002
|
61
|
+
description: AmplifyJS is a set of components designed to solve common web application problems with a simplistic API.
|
62
|
+
email: alassek@lyconic.com
|
63
|
+
executables: []
|
64
|
+
|
65
|
+
extensions: []
|
66
|
+
|
67
|
+
extra_rdoc_files: []
|
68
|
+
|
69
|
+
files:
|
70
|
+
- lib/amplify/engine.rb
|
71
|
+
- lib/amplify/version.rb
|
72
|
+
- lib/amplify.rb
|
73
|
+
- app/assets/javascripts/amplify/core.js.erb
|
74
|
+
- app/assets/javascripts/amplify/index.js.erb
|
75
|
+
- app/assets/javascripts/amplify/request.js.erb
|
76
|
+
- app/assets/javascripts/amplify/store.js.erb
|
77
|
+
has_rdoc: true
|
78
|
+
homepage: http://amplifyjs.com
|
79
|
+
licenses:
|
80
|
+
- MIT
|
81
|
+
- GPL-2
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options: []
|
84
|
+
|
85
|
+
require_paths:
|
86
|
+
- lib
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
hash: 3
|
93
|
+
segments:
|
94
|
+
- 0
|
95
|
+
version: "0"
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
hash: 3
|
102
|
+
segments:
|
103
|
+
- 0
|
104
|
+
version: "0"
|
105
|
+
requirements: []
|
106
|
+
|
107
|
+
rubyforge_project:
|
108
|
+
rubygems_version: 1.3.7
|
109
|
+
signing_key:
|
110
|
+
specification_version: 3
|
111
|
+
summary: A Javascript Component Library
|
112
|
+
test_files: []
|
113
|
+
|