eyeballs 0.3.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/CHANGELOG +15 -0
- data/README.md +293 -0
- data/Rakefile +45 -0
- data/bin/eyeballs +9 -0
- data/config.ru +2 -0
- data/dist/jquery-1.4.2.min.js +154 -0
- data/dist/jquery.livequery.js +226 -0
- data/dist/mustache.js +324 -0
- data/eyeballs.gemspec +86 -0
- data/eyeballs.js.gemspec +83 -0
- data/lib/eyeballs.rb +11 -0
- data/lib/eyeballs/app_detector.rb +29 -0
- data/lib/eyeballs/app_generator.rb +30 -0
- data/lib/eyeballs/cli.rb +14 -0
- data/lib/eyeballs/controller_generator.rb +26 -0
- data/lib/eyeballs/model_generator.rb +26 -0
- data/lib/eyeballs/scaffold_generator.rb +66 -0
- data/spec/app_generator_spec.rb +51 -0
- data/spec/controller_generator_spec.rb +22 -0
- data/spec/model_generator_spec.rb +23 -0
- data/spec/rack_app_detector_spec.rb +25 -0
- data/spec/scaffold_generator_spec.rb +42 -0
- data/spec/spec_helper.rb +42 -0
- data/src/jquery.o_O.couchdb.js +107 -0
- data/src/jquery.o_O.dom.js +37 -0
- data/src/jquery.o_O.js +120 -0
- data/src/jquery.o_O.rails.js +68 -0
- data/src/o_O.js +286 -0
- data/src/o_O.localstorage.js +60 -0
- data/templates/app_root/index.html +26 -0
- data/templates/controller.js +3 -0
- data/templates/model.js +3 -0
- data/templates/scaffold_controller.js +75 -0
- data/templates/scaffold_edit.html.mustache +13 -0
- data/templates/scaffold_index.html +47 -0
- data/templates/scaffold_partial.html.mustache +12 -0
- data/test/unit/qunit.css +119 -0
- data/test/unit/qunit.js +1069 -0
- data/test/unit/test_controller.html +137 -0
- data/test/unit/test_dom.html +81 -0
- data/test/unit/test_dom_with_callbacks.html +121 -0
- data/test/unit/test_form.html +42 -0
- data/test/unit/test_localstorage.html +79 -0
- data/test/unit/test_model.html +136 -0
- data/test/unit/test_model_with_callbacks.html +118 -0
- data/test/unit/test_rails.html +97 -0
- metadata +117 -0
data/src/o_O.js
ADDED
@@ -0,0 +1,286 @@
|
|
1
|
+
var o_O = function(){
|
2
|
+
|
3
|
+
var bind_to;
|
4
|
+
var object_to_bind_to = arguments[2];
|
5
|
+
bind_to = (object_to_bind_to) ? object_to_bind_to : window;
|
6
|
+
|
7
|
+
if(typeof arguments[1] === 'object')
|
8
|
+
{
|
9
|
+
var controller_name = arguments[0];
|
10
|
+
bind_to[controller_name] = o_O.controller.initialize(controller_name, arguments[1]);
|
11
|
+
return bind_to[controller_name];
|
12
|
+
}
|
13
|
+
|
14
|
+
if(typeof arguments[1] === 'function')
|
15
|
+
{
|
16
|
+
|
17
|
+
var model_name = arguments[0];
|
18
|
+
var model_initializer = arguments[1];
|
19
|
+
bind_to[model_name] = o_O.model.initialize(model_name, model_initializer);
|
20
|
+
|
21
|
+
if(typeof o_O.models !== 'object')
|
22
|
+
{
|
23
|
+
o_O.models = {};
|
24
|
+
}
|
25
|
+
o_O.models[model_name] = bind_to[model_name];
|
26
|
+
|
27
|
+
return bind_to[model_name];
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
o_O.model = {
|
32
|
+
adapter: false,
|
33
|
+
initialize: function(model_name, callback){
|
34
|
+
var callback = callback;
|
35
|
+
var class_methods, instance_methods, initializer_methods;
|
36
|
+
var validates_presence_of, validates_length_of;
|
37
|
+
var table_name = model_name.toLowerCase() + 's';
|
38
|
+
|
39
|
+
class_methods = {
|
40
|
+
validations: {presence: [], lengthliness: [], custom: []},
|
41
|
+
methods: {},
|
42
|
+
validates_presence_of: function(field){
|
43
|
+
this.validations.presence.push({field: field});
|
44
|
+
},
|
45
|
+
validates_length_of: function(field, options){
|
46
|
+
options.field = field;
|
47
|
+
this.validations.lengthliness.push(options);
|
48
|
+
},
|
49
|
+
validates: function(validation){
|
50
|
+
this.validations.custom.push(validation)
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
var run_callback = function(callback, method, args){
|
55
|
+
try{
|
56
|
+
if(typeof callback === 'function' && method === 'success')
|
57
|
+
{
|
58
|
+
callback(args);
|
59
|
+
}
|
60
|
+
if(typeof callback === 'object' && typeof callback[method] === 'function')
|
61
|
+
{
|
62
|
+
callback[method](args);
|
63
|
+
}
|
64
|
+
}
|
65
|
+
catch(e)
|
66
|
+
{
|
67
|
+
if(typeof console === 'object')
|
68
|
+
{
|
69
|
+
console.log(e);
|
70
|
+
}
|
71
|
+
else
|
72
|
+
{
|
73
|
+
alert(e);
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
var config = callback(class_methods);
|
79
|
+
instance_methods = {
|
80
|
+
adapter: o_O.model.adapter,
|
81
|
+
destroy: function(callback){
|
82
|
+
run_callback(callback, 'loading', this)
|
83
|
+
if(this.adapter)
|
84
|
+
{
|
85
|
+
this.adapter.destroy(this, function(returned_object){
|
86
|
+
run_callback(callback, 'success', returned_object);
|
87
|
+
});
|
88
|
+
}
|
89
|
+
else
|
90
|
+
{
|
91
|
+
run_callback(callback, 'success', this)
|
92
|
+
}
|
93
|
+
return this;
|
94
|
+
},
|
95
|
+
model_name: model_name,
|
96
|
+
save: function(callback){
|
97
|
+
if(this.valid())
|
98
|
+
{
|
99
|
+
run_callback(callback, 'loading', this);
|
100
|
+
if(this.adapter)
|
101
|
+
{
|
102
|
+
var model = this;
|
103
|
+
this.adapter.save(this, function(returned_object){
|
104
|
+
var initialized_object = o_O.models[model.model_name].initialize(returned_object);
|
105
|
+
initialized_object.new_record = false;
|
106
|
+
run_callback(callback, 'success', initialized_object);
|
107
|
+
});
|
108
|
+
}
|
109
|
+
else
|
110
|
+
{
|
111
|
+
run_callback(callback, 'success', this);
|
112
|
+
}
|
113
|
+
return this;
|
114
|
+
}
|
115
|
+
else
|
116
|
+
{
|
117
|
+
run_callback(callback, 'invalid', this);
|
118
|
+
}
|
119
|
+
},
|
120
|
+
table_name: table_name,
|
121
|
+
to_json: function(){
|
122
|
+
var serialized_object = {};
|
123
|
+
for(var i = 0; i < this.attributes.length; i++);
|
124
|
+
{
|
125
|
+
var index = i - 1;
|
126
|
+
var attribute_name = this.attributes[index];
|
127
|
+
serialized_object[this.attributes[index]] = this[this.attributes[index]];
|
128
|
+
}
|
129
|
+
serialized_object._model_name = this.model_name;
|
130
|
+
return JSON.stringify(serialized_object);
|
131
|
+
},
|
132
|
+
update_attributes: function(attributes, callback){
|
133
|
+
for(var attribute in attributes)
|
134
|
+
{
|
135
|
+
this[attribute] = attributes[attribute];
|
136
|
+
}
|
137
|
+
this.save(callback);
|
138
|
+
},
|
139
|
+
valid: function(){
|
140
|
+
this.errors = [];
|
141
|
+
|
142
|
+
o_O.validations.run(this);
|
143
|
+
|
144
|
+
if(this.errors.length == 0)
|
145
|
+
{
|
146
|
+
return true;
|
147
|
+
}
|
148
|
+
else
|
149
|
+
{
|
150
|
+
return false;
|
151
|
+
}
|
152
|
+
},
|
153
|
+
errors: [],
|
154
|
+
validations: class_methods.validations
|
155
|
+
}
|
156
|
+
for(method in class_methods.methods)
|
157
|
+
{
|
158
|
+
instance_methods[method] = class_methods.methods[method]
|
159
|
+
}
|
160
|
+
|
161
|
+
initializer_methods = {
|
162
|
+
adapter: o_O.model.adapter,
|
163
|
+
all: function(callback){
|
164
|
+
if(this.adapter)
|
165
|
+
{
|
166
|
+
return this.adapter.all(this, callback);
|
167
|
+
}
|
168
|
+
},
|
169
|
+
initialize: function(attributes){
|
170
|
+
if(!attributes) { var attributes = {}; };
|
171
|
+
var initialized_attributes = [];
|
172
|
+
for( var attribute in attributes )
|
173
|
+
{
|
174
|
+
initialized_attributes.push(attribute);
|
175
|
+
}
|
176
|
+
attributes['attributes'] = initialized_attributes;
|
177
|
+
for ( var method in instance_methods ) {
|
178
|
+
attributes[method] = instance_methods[method];
|
179
|
+
}
|
180
|
+
if(!attributes['id'])
|
181
|
+
{
|
182
|
+
attributes['id'] = o_O.uuid();
|
183
|
+
}
|
184
|
+
if(!attributes['new_record'])
|
185
|
+
{
|
186
|
+
attributes['new_record'] = true;
|
187
|
+
}
|
188
|
+
return attributes;
|
189
|
+
},
|
190
|
+
find: function(id, callback){
|
191
|
+
if(this.adapter)
|
192
|
+
{
|
193
|
+
var model = this;
|
194
|
+
return this.adapter.find(this, id, function(returned_object){
|
195
|
+
if(typeof callback === 'function')
|
196
|
+
{
|
197
|
+
found_object = model.initialize(returned_object);
|
198
|
+
if(!found_object['new_record'])
|
199
|
+
{
|
200
|
+
found_object['new_record'] = false;
|
201
|
+
}
|
202
|
+
callback(found_object);
|
203
|
+
}
|
204
|
+
});
|
205
|
+
}
|
206
|
+
},
|
207
|
+
model_name: model_name,
|
208
|
+
table_name: table_name
|
209
|
+
}
|
210
|
+
|
211
|
+
return initializer_methods;
|
212
|
+
}
|
213
|
+
}
|
214
|
+
|
215
|
+
o_O.validations = {
|
216
|
+
run: function(object){
|
217
|
+
this.run_custom_validations(object);
|
218
|
+
this.run_length_validations(object);
|
219
|
+
this.run_presence_validations(object);
|
220
|
+
},
|
221
|
+
run_custom_validations: function(object){
|
222
|
+
for(var i = 0; i < object.validations.custom.length; i++)
|
223
|
+
{
|
224
|
+
object.validations.custom[i](object);
|
225
|
+
}
|
226
|
+
},
|
227
|
+
run_length_validations: function(object){
|
228
|
+
for(var i = 0; i < object.validations.lengthliness.length; i++)
|
229
|
+
{
|
230
|
+
var field = object.validations.lengthliness[i].field;
|
231
|
+
var max = object.validations.lengthliness[i].max
|
232
|
+
var min = object.validations.lengthliness[i].min
|
233
|
+
if(object[field])
|
234
|
+
{
|
235
|
+
if(max && object[field].length > max)
|
236
|
+
{
|
237
|
+
var message = field + ' should be less than ' + max + ' characters';
|
238
|
+
object.errors.push({field: field, type: 'length', message: message});
|
239
|
+
}
|
240
|
+
if(min && object[field].length < min)
|
241
|
+
{
|
242
|
+
var message = field + ' should be greater than ' + min + ' characters';
|
243
|
+
object.errors.push({field: field, type: 'length', message: message});
|
244
|
+
}
|
245
|
+
}
|
246
|
+
}
|
247
|
+
},
|
248
|
+
run_presence_validations: function(object){
|
249
|
+
for(var i = 0; i < object.validations.presence.length; i++)
|
250
|
+
{
|
251
|
+
var field = object.validations.presence[i].field;
|
252
|
+
if(object[field] == '' || object[field] == null)
|
253
|
+
{
|
254
|
+
var message = field + ' should be present';
|
255
|
+
object.errors.push({field: field, type: 'presence', message: message})
|
256
|
+
}
|
257
|
+
}
|
258
|
+
}
|
259
|
+
}
|
260
|
+
|
261
|
+
o_O.config = {}
|
262
|
+
o_O.templates = {}
|
263
|
+
|
264
|
+
o_O._uuid_default_prefix = '';
|
265
|
+
|
266
|
+
o_O._uuidlet = function () {
|
267
|
+
return(((1+Math.random())*0x10000)|0).toString(16).substring(1);
|
268
|
+
};
|
269
|
+
|
270
|
+
o_O.uuid = function (p) {
|
271
|
+
if (typeof(p) == 'object' && typeof(p.prefix) == 'string') {
|
272
|
+
o_O._uuid_default_prefix = p.prefix;
|
273
|
+
} else {
|
274
|
+
p = p || o_O._uuid_default_prefix || '';
|
275
|
+
return(p+o_O._uuidlet()+o_O._uuidlet()+"-"+o_O._uuidlet()+"-"+o_O._uuidlet()+"-"+o_O._uuidlet()+"-"+o_O._uuidlet()+o_O._uuidlet()+o_O._uuidlet());
|
276
|
+
};
|
277
|
+
};
|
278
|
+
|
279
|
+
o_O.alert_errors = function(object){
|
280
|
+
var error_message = '';
|
281
|
+
for(i = 0; i < object.errors.length; i++)
|
282
|
+
{
|
283
|
+
error_message = error_message + object.errors[i].message + "\n";
|
284
|
+
}
|
285
|
+
alert(error_message);
|
286
|
+
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
if(typeof localStorage === 'object')
|
2
|
+
{
|
3
|
+
// We're storing locally, baby!
|
4
|
+
o_O.localstorage = {
|
5
|
+
all: function(model, callback){
|
6
|
+
var all_objects = []
|
7
|
+
for(var record in this.table(model))
|
8
|
+
{
|
9
|
+
all_objects.push(this.table(model)[record]);
|
10
|
+
}
|
11
|
+
if(typeof callback === 'function')
|
12
|
+
{
|
13
|
+
callback(all_objects);
|
14
|
+
}
|
15
|
+
return all_objects;
|
16
|
+
},
|
17
|
+
destroy: function(object, callback){
|
18
|
+
var table = this.table(object)
|
19
|
+
delete table[object.id]
|
20
|
+
localStorage.setItem(object.table_name, JSON.stringify(table))
|
21
|
+
if(typeof callback === 'function')
|
22
|
+
{
|
23
|
+
callback(object)
|
24
|
+
}
|
25
|
+
},
|
26
|
+
save: function(object, callback)
|
27
|
+
{
|
28
|
+
var all = this.table(object)
|
29
|
+
all[object.id] = object;
|
30
|
+
localStorage.setItem(object.table_name, JSON.stringify(all))
|
31
|
+
if(typeof callback === 'function')
|
32
|
+
{
|
33
|
+
callback(object);
|
34
|
+
}
|
35
|
+
},
|
36
|
+
table: function(object)
|
37
|
+
{
|
38
|
+
var all;
|
39
|
+
var stored_all = localStorage.getItem(object.table_name);
|
40
|
+
if(stored_all == null)
|
41
|
+
{
|
42
|
+
return {};
|
43
|
+
}
|
44
|
+
else
|
45
|
+
{
|
46
|
+
return JSON.parse(stored_all);
|
47
|
+
}
|
48
|
+
},
|
49
|
+
find: function(model, id, callback)
|
50
|
+
{
|
51
|
+
var object = this.table(model)[id]
|
52
|
+
object.id = id;
|
53
|
+
if(typeof callback === 'function')
|
54
|
+
{
|
55
|
+
callback(object);
|
56
|
+
}
|
57
|
+
return object;
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
2
|
+
"http://www.w3.org/TR/html4/loose.dtd">
|
3
|
+
<html>
|
4
|
+
<head>
|
5
|
+
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
6
|
+
<title>Welcome to eyeballs.js</title>
|
7
|
+
</head>
|
8
|
+
|
9
|
+
<body>
|
10
|
+
<h2>Welcome to eyeballs.js</h2>
|
11
|
+
|
12
|
+
<p>A world of javascript goodness awaits!</p>
|
13
|
+
|
14
|
+
<p>As you add models and controllers, don't forget to include them!</p>
|
15
|
+
|
16
|
+
<script src="vendor/jquery/jquery-1.4.2.min.js"></script>
|
17
|
+
<script src="vendor/jquery/jquery.livequery.js"></script>
|
18
|
+
<script src="vendor/jquery/mustache.js"></script>
|
19
|
+
<script src="vendor/eyeballs/o_O.js"></script>
|
20
|
+
<script src="vendor/eyeballs/jquery.o_O.js"></script>
|
21
|
+
<script src="vendor/eyeballs/o_O.localstorage.js"></script>
|
22
|
+
<script type="text/javascript" charset="utf-8">
|
23
|
+
o_O.model.adapter = o_O.localstorage;
|
24
|
+
</script>
|
25
|
+
</body>
|
26
|
+
</html>
|
data/templates/model.js
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
o_O('<%= name.capitalize.pluralize -%>Controller', {
|
2
|
+
index: function(){
|
3
|
+
<%= name.capitalize %>.all(function(<%= name.downcase.pluralize %>){
|
4
|
+
for(var id in <%= name.downcase.pluralize %>)
|
5
|
+
{
|
6
|
+
var <%= name.downcase %> = <%= name.downcase.pluralize %>[id];
|
7
|
+
o_O.render('<%= name.downcase.pluralize %>/_<%= name.downcase %>', <%= name.downcase %>, {append: 'div#<%= name.pluralize %>'})
|
8
|
+
}
|
9
|
+
});
|
10
|
+
},
|
11
|
+
new: function(){
|
12
|
+
o_O.render('<%= name.downcase.pluralize %>/new', {}, {before: 'div#<%= name.pluralize %>'})
|
13
|
+
},
|
14
|
+
create: function(){
|
15
|
+
var <%= name.downcase %> = <%= name.capitalize %>.initialize(o_O.params($(this)));
|
16
|
+
var form = $(this);
|
17
|
+
<%= name.downcase %>.save({
|
18
|
+
invalid: function(<%= name.downcase %>){
|
19
|
+
o_O.alert_errors(<%= name.downcase %>);
|
20
|
+
},
|
21
|
+
success: function(<%= name.downcase %>){
|
22
|
+
o_O.render('<%= name.downcase.pluralize %>/_<%= name.downcase %>', <%= name.downcase %>, {prepend: 'div#<%= name.downcase.pluralize %>'});
|
23
|
+
form.find('input[type=text], textarea').val('');
|
24
|
+
}
|
25
|
+
})
|
26
|
+
},
|
27
|
+
edit: function(){
|
28
|
+
<%= name.downcase %>_div = $(this).parents('div.<%= name.downcase %>');
|
29
|
+
review = <%= name.capitalize %>.find(<%= name.downcase %>_div.attr('data-id'), function(<%= name.downcase %>){
|
30
|
+
o_O.get_template('<%= name.downcase.pluralize %>/edit', <%= name.downcase %>, function(data, template){
|
31
|
+
edit_<%= name.downcase %> = Mustache.to_html(template, data);
|
32
|
+
<%= name.downcase %>_div.hide().after(edit_<%= name.downcase %>);
|
33
|
+
});
|
34
|
+
});
|
35
|
+
},
|
36
|
+
cancel_edit: function(){
|
37
|
+
edit_<%= name.downcase %>_div = $(this).parents('div.edit-<%= name.downcase %>');
|
38
|
+
<%= name.downcase %>_div = edit_<%= name.downcase %>_div.prev('div.<%= name.downcase %>:first');
|
39
|
+
edit_<%= name.downcase %>_div.remove();
|
40
|
+
<%= name.downcase %>_div.show();
|
41
|
+
},
|
42
|
+
update: function(){
|
43
|
+
edit_<%= name.downcase %>_div = $(this).parents('div.edit-<%= name.downcase %>');
|
44
|
+
review_div = edit_<%= name.downcase %>_div.prev('div.<%= name.downcase %>:first');
|
45
|
+
var form = $(this)
|
46
|
+
<%= name.capitalize %>.find(form.attr('data-id'), function(<%= name.capitalize %>){
|
47
|
+
if(<%= name.capitalize %>.valid())
|
48
|
+
{
|
49
|
+
<%= name.capitalize %>.update_attributes(o_O.params(form), function(updated_<%= name.downcase %>){
|
50
|
+
o_O.get_template('<%= name.downcase.pluralize %>/_<%= name.downcase %>', updated_<%= name.downcase %>, function(data, template){
|
51
|
+
var template = Mustache.to_html(template, data);
|
52
|
+
edit_<%= name.downcase %>_div.replaceWith(template);
|
53
|
+
<%= name.downcase %>_div.remove();
|
54
|
+
});
|
55
|
+
});
|
56
|
+
}
|
57
|
+
else
|
58
|
+
{
|
59
|
+
o_O.alert_errors(<%= name.downcase %>);
|
60
|
+
}
|
61
|
+
});
|
62
|
+
},
|
63
|
+
destroy: function(){
|
64
|
+
if(confirm('Are You sure?'))
|
65
|
+
{
|
66
|
+
$(this).parents('div.<%= name.downcase %>:first').slideToggle(function(){
|
67
|
+
var div = $(this);
|
68
|
+
<%= name.capitalize %>.find($(this).attr('data-id'), function(<%= name.downcase %>){
|
69
|
+
<%= name.downcase %>.destroy();
|
70
|
+
div.remove();
|
71
|
+
});
|
72
|
+
});
|
73
|
+
}
|
74
|
+
},
|
75
|
+
});
|