amplify 1.0.1
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/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
|
+
|