hobo 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/bin/hobo +3 -2
  2. data/hobo_files/plugin/CHANGES.txt +299 -2
  3. data/hobo_files/plugin/Rakefile +12 -10
  4. data/hobo_files/plugin/generators/hobo/templates/guest.rb +1 -13
  5. data/hobo_files/plugin/generators/hobo_migration/hobo_migration_generator.rb +11 -7
  6. data/hobo_files/plugin/generators/hobo_rapid/hobo_rapid_generator.rb +1 -0
  7. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_rapid.js +1 -1
  8. data/hobo_files/plugin/generators/hobo_rapid/templates/lowpro.js +405 -0
  9. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/views/application.dryml +1 -1
  10. data/hobo_files/plugin/generators/hobo_user_model/templates/model.rb +1 -9
  11. data/hobo_files/plugin/init.rb +5 -0
  12. data/hobo_files/plugin/lib/active_record/has_many_association.rb +1 -1
  13. data/hobo_files/plugin/lib/extensions.rb +26 -5
  14. data/hobo_files/plugin/lib/extensions/test_case.rb +1 -1
  15. data/hobo_files/plugin/lib/hobo.rb +37 -11
  16. data/hobo_files/plugin/lib/hobo/authenticated_user.rb +7 -2
  17. data/hobo_files/plugin/lib/hobo/authentication_support.rb +7 -6
  18. data/hobo_files/plugin/lib/hobo/composite_model.rb +5 -0
  19. data/hobo_files/plugin/lib/hobo/controller.rb +4 -4
  20. data/hobo_files/plugin/lib/hobo/dryml.rb +5 -5
  21. data/hobo_files/plugin/lib/hobo/dryml/part_context.rb +3 -6
  22. data/hobo_files/plugin/lib/hobo/dryml/template.rb +16 -15
  23. data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +24 -20
  24. data/hobo_files/plugin/lib/hobo/email_address.rb +4 -0
  25. data/hobo_files/plugin/lib/hobo/field_spec.rb +2 -1
  26. data/hobo_files/plugin/lib/hobo/guest.rb +21 -0
  27. data/hobo_files/plugin/lib/hobo/hobo_helper.rb +42 -2
  28. data/hobo_files/plugin/lib/hobo/http_parameters.rb +225 -0
  29. data/hobo_files/plugin/lib/hobo/model.rb +55 -37
  30. data/hobo_files/plugin/lib/hobo/model_controller.rb +151 -151
  31. data/hobo_files/plugin/lib/hobo/model_queries.rb +30 -5
  32. data/hobo_files/plugin/lib/hobo/user_controller.rb +27 -16
  33. data/hobo_files/plugin/lib/hobo/where_fragment.rb +6 -1
  34. data/hobo_files/plugin/tags/rapid.dryml +88 -58
  35. data/hobo_files/plugin/tags/rapid_document_tags.dryml +5 -5
  36. data/hobo_files/plugin/tags/rapid_editing.dryml +3 -3
  37. data/hobo_files/plugin/tags/rapid_forms.dryml +35 -26
  38. data/hobo_files/plugin/tags/rapid_navigation.dryml +13 -12
  39. data/hobo_files/plugin/tags/rapid_pages.dryml +35 -31
  40. data/hobo_files/plugin/tags/rapid_plus.dryml +41 -0
  41. data/hobo_files/plugin/tags/rapid_support.dryml +18 -9
  42. data/hobo_files/plugin/tasks/dump_fixtures.rake +61 -0
  43. metadata +7 -11
  44. data/hobo_files/plugin/spec/fixtures/users.yml +0 -9
  45. data/hobo_files/plugin/spec/spec.opts +0 -6
  46. data/hobo_files/plugin/spec/spec_helper.rb +0 -28
  47. data/hobo_files/plugin/spec/unit/hobo/dryml/template_spec.rb +0 -650
@@ -11,6 +11,7 @@ class HoboRapidGenerator < Hobo::Generator
11
11
 
12
12
  record do |m|
13
13
  m.file "hobo_rapid.js", "public/javascripts/hobo_rapid.js"
14
+ m.file "lowpro.js", "public/javascripts/lowpro.js"
14
15
  m.file "hobo_base.css", "public/stylesheets/hobo_base.css"
15
16
  m.file "hobo_rapid.css", "public/stylesheets/hobo_rapid.css"
16
17
  create_all(m, "themes/default/public", "public/hobothemes/default")
@@ -48,7 +48,7 @@ var Hobo = {
48
48
  if (updates.length > 0) {
49
49
  updates.each(function(dom_id) {
50
50
  if (!hoboParts[dom_id]) { throw "Update of dom-id that is not a part: " + dom_id }
51
- params.push("render["+i+"][part_context]=" + hoboParts[dom_id])
51
+ params.push("render["+i+"][part_context]=" + encodeURIComponent(hoboParts[dom_id]))
52
52
  params.push("render["+i+"][id]=" + dom_id)
53
53
  i += 1
54
54
  })
@@ -0,0 +1,405 @@
1
+ LowPro = {};
2
+ LowPro.Version = '0.4.1';
3
+
4
+ if (!Element.addMethods)
5
+ Element.addMethods = function(o) { Object.extend(Element.Methods, o) };
6
+
7
+ // Simple utility methods for working with the DOM
8
+ DOM = {
9
+ insertAfter : function(element, node, otherNode) {
10
+ element = $(element);
11
+ if (otherNode.nextSibling)
12
+ return element.insertBefore(node, otherNode.nextSibling);
13
+ else
14
+ return element.appendChild(node);
15
+ },
16
+ addBefore : function(element, node) {
17
+ element = $(element);
18
+ return element.parentNode.insertBefore(node, element);
19
+ },
20
+ addAfter : function(element, node) {
21
+ element = $(element);
22
+ return $(element.parentNode).insertAfter(node, element);
23
+ },
24
+ replaceElement : function(element, node) {
25
+ $(element).parentNode.replaceChild(node, element);
26
+ return node;
27
+ },
28
+ prependChild : function(element, node) {
29
+ $(element).insertBefore(node, element.firstChild);
30
+ },
31
+ appendChildren : function(element, children) {
32
+ element = $(element);
33
+ if (!(children instanceof Array))
34
+ children = Array.prototype.slice.call(arguments, 1);
35
+ children.each(function(child) { element.appendChild(child) });
36
+ return children;
37
+ }
38
+ };
39
+
40
+ // Add them to the element mixin
41
+ Element.addMethods(DOM);
42
+
43
+ // DOMBuilder for prototype
44
+ DOM.Builder = {
45
+ IE_TRANSLATIONS : {
46
+ 'class' : 'className',
47
+ 'for' : 'htmlFor'
48
+ },
49
+ cache: {},
50
+ ieAttrSet : function(attrs, attr, el) {
51
+ var trans;
52
+ if (trans = this.IE_TRANSLATIONS[attr]) el[trans] = attrs[attr];
53
+ else if (attr == 'style') el.style.cssText = attrs[attr];
54
+ else if (attr.match(/^on/)) el[attr] = new Function(attrs[attr]);
55
+ else el.setAttribute(attr, attrs[attr]);
56
+ },
57
+ getElement : function(tag) {
58
+ var element = DOM.Builder.cache[tag];
59
+ if (element == null)
60
+ element = DOM.Builder.cache[tag] = document.createElement(tag);
61
+ return element.cloneNode(false);
62
+ },
63
+ tagFunc : function(tag) {
64
+ return function() {
65
+ var attrs, children;
66
+ if (arguments.length>0) {
67
+ if (arguments[0].nodeName ||
68
+ typeof arguments[0] == "string")
69
+ children = arguments;
70
+ else {
71
+ attrs = arguments[0];
72
+ children = Array.prototype.slice.call(arguments, 1);
73
+ };
74
+ }
75
+ return DOM.Builder.create(tag, attrs, children);
76
+ };
77
+ },
78
+ create : function(tag, attrs, children) {
79
+ attrs = attrs || {}; children = children || []; tag = tag.toLowerCase();
80
+ var isIE = navigator.userAgent.match(/MSIE/);
81
+ var el = (isIE && attrs.name) ?
82
+ document.createElement("<" + tag + " name=" + attrs.name + ">") :
83
+ DOM.Builder.getElement(tag);
84
+
85
+ for (var attr in attrs) {
86
+ if (attrs[attr] === true) attrs[attr] = attr;
87
+ if (typeof attrs[attr] != 'function') {
88
+ if (isIE) this.ieAttrSet(attrs, attr, el);
89
+ else el.setAttribute(attr, attrs[attr].toString());
90
+ } else if (attr.match(/^on(.+)$/)) {
91
+ Event.observe(el, RegExp.$1, attrs[attr]);
92
+ };
93
+ }
94
+
95
+ for (var i=0; i<children.length; i++) {
96
+ if (typeof children[i] == 'string')
97
+ children[i] = document.createTextNode(children[i]);
98
+ el.appendChild(children[i]);
99
+ }
100
+ return $(el);
101
+ }
102
+ };
103
+
104
+ // Automatically create node builders as $tagName.
105
+ (function() {
106
+ var els = ("p|div|span|strong|em|img|table|tr|td|th|thead|tbody|tfoot|pre|code|" +
107
+ "h1|h2|h3|h4|h5|h6|ul|ol|li|form|input|textarea|legend|fieldset|" +
108
+ "select|option|blockquote|cite|br|hr|dd|dl|dt|address|a|button|abbr|acronym|" +
109
+ "script|link|style|bdo|ins|del|object|param|col|colgroup|optgroup|caption|" +
110
+ "label|dfn|kbd|samp|var").split("|");
111
+ var el, i=0;
112
+ while (el = els[i++])
113
+ window['$' + el] = DOM.Builder.tagFunc(el);
114
+ })();
115
+
116
+ DOM.Builder.fromHTML = function(html) {
117
+ var root;
118
+ if (!(root = arguments.callee._root))
119
+ root = arguments.callee._root = document.createElement('div');
120
+ root.innerHTML = html;
121
+ return root.childNodes[0];
122
+ };
123
+
124
+ String.prototype.toElement = function() {
125
+ return DOM.Builder.fromHTML(this);
126
+ };
127
+
128
+ (function() {
129
+ var old$ = $;
130
+ $ = function(element) {
131
+ if (element && element.toElement && element.match(/^<(.+)>$/))
132
+ return $(element.toElement());
133
+ return old$.apply(this, arguments);
134
+ }
135
+ })();
136
+
137
+
138
+
139
+ // Adapted from DOM Ready extension by Dan Webb
140
+ // http://www.vivabit.com/bollocks/2006/06/21/a-dom-ready-extension-for-prototype
141
+ // which was based on work by Matthias Miller, Dean Edwards and John Resig
142
+ //
143
+ // Usage:
144
+ //
145
+ // Event.onReady(callbackFunction);
146
+ Object.extend(Event, {
147
+ _domReady : function() {
148
+ if (arguments.callee.done) return;
149
+ arguments.callee.done = true;
150
+
151
+ if (Event._timer) clearInterval(Event._timer);
152
+
153
+ Event._readyCallbacks.each(function(f) { f() });
154
+ Event._readyCallbacks = null;
155
+
156
+ },
157
+ onReady : function(f) {
158
+ if (!this._readyCallbacks) {
159
+ var domReady = this._domReady;
160
+
161
+ if (domReady.done) return f();
162
+
163
+ if (document.addEventListener)
164
+ document.addEventListener("DOMContentLoaded", domReady, false);
165
+
166
+ /*@cc_on @*/
167
+ /*@if (@_win32)
168
+ var dummy = location.protocol == "https:" ? "https://javascript:void(0)" : "javascript:void(0)";
169
+ document.write("<script id=__ie_onload defer src='" + dummy + "'><\/script>");
170
+ document.getElementById("__ie_onload").onreadystatechange = function() {
171
+ if (this.readyState == "complete") { domReady(); }
172
+ };
173
+ /*@end @*/
174
+
175
+ if (/WebKit/i.test(navigator.userAgent)) {
176
+ this._timer = setInterval(function() {
177
+ if (/loaded|complete/.test(document.readyState)) domReady();
178
+ }, 10);
179
+ }
180
+
181
+ Event.observe(window, 'load', domReady);
182
+ Event._readyCallbacks = [];
183
+ }
184
+ Event._readyCallbacks.push(f);
185
+ }
186
+ });
187
+
188
+ // Extend Element with observe and stopObserving.
189
+ if (typeof Element.Methods.observe == 'undefined') Element.addMethods({
190
+ observe : function(el, event, callback) {
191
+ Event.observe(el, event, callback);
192
+ },
193
+ stopObserving : function(el, event, callback) {
194
+ Event.stopObserving(el, event, callback);
195
+ }
196
+ });
197
+
198
+ // Replace out existing event observe code with Dean Edwards' addEvent
199
+ // http://dean.edwards.name/weblog/2005/10/add-event/
200
+ Object.extend(Event, {
201
+ _observeAndCache : function(el, type, func) {
202
+ if (!func.$$guid) func.$$guid = Event._guid++;
203
+ if (!el.events) el.events = {};
204
+ var handlers = el.events[type];
205
+ if (!handlers) {
206
+ handlers = el.events[type] = {};
207
+ if (el["on" + type]) {
208
+ handlers[0] = el["on" + type];
209
+ }
210
+ }
211
+ handlers[func.$$guid] = func;
212
+ el["on" + type] = Event._handleEvent;
213
+
214
+ if (!Event.observers) Event.observers = [];
215
+ Event.observers.push([el, type, func, false]);
216
+ },
217
+ stopObserving : function(el, type, func) {
218
+ el = $(el);
219
+ if (el.events && el.events[type]) delete el.events[type][func.$$guid];
220
+
221
+ for (var i = 0; i < Event.observers.length; i++) {
222
+ if (Event.observers[i] &&
223
+ Event.observers[i][0] == el &&
224
+ Event.observers[i][1] == type &&
225
+ Event.observers[i][2] == func) delete Event.observers[i];
226
+ }
227
+ },
228
+ _handleEvent : function(e) {
229
+ var returnValue = true;
230
+ e = e || Event._fixEvent(window.event);
231
+ var handlers = this.events[e.type], el = $(this);
232
+ for (var i in handlers) {
233
+ el.$$handleEvent = handlers[i];
234
+ if (el.$$handleEvent(e) === false) returnValue = false;
235
+ }
236
+ if (returnValue == false) e.preventDefault();
237
+ return returnValue;
238
+ },
239
+ _fixEvent : function(e) {
240
+ e.preventDefault = Event._preventDefault;
241
+ e.stopPropagation = Event._stopPropagation;
242
+ return e;
243
+ },
244
+ _preventDefault : function() { this.returnValue = false },
245
+ _stopPropagation : function() { this.cancelBubble = true },
246
+ _guid : 1
247
+ });
248
+
249
+ // Allows you to trigger an event element.
250
+ Object.extend(Event, {
251
+ trigger : function(element, event, fakeEvent) {
252
+ element = $(element);
253
+ fakeEvent = fakeEvent || { type : event };
254
+ if(element.events && element.events[event]) {
255
+ $H(element.events[event]).each(function(cache) {
256
+ cache[1].call(element, fakeEvent);
257
+ });
258
+ }
259
+ }
260
+ });
261
+
262
+ // Based on event:Selectors by Justin Palmer
263
+ // http://encytemedia.com/event-selectors/
264
+ //
265
+ // Usage:
266
+ //
267
+ // Event.addBehavior({
268
+ // "selector:event" : function(event) { /* event handler. this refers to the element. */ },
269
+ // "selector" : function() { /* runs function on dom ready. this refers to the element. */ }
270
+ // ...
271
+ // });
272
+ //
273
+ // Multiple calls will add to exisiting rules. Event.addBehavior.reassignAfterAjax and
274
+ // Event.addBehavior.autoTrigger can be adjusted to needs.
275
+ Event.addBehavior = function(rules) {
276
+ var ab = this.addBehavior;
277
+ Object.extend(ab.rules, rules);
278
+
279
+ if (!ab.responderApplied) {
280
+ Ajax.Responders.register({
281
+ onComplete : function() {
282
+ if (Event.addBehavior.reassignAfterAjax)
283
+ setTimeout(function() { ab.unload(); ab.load(ab.rules) }, 10);
284
+ }
285
+ });
286
+ ab.responderApplied = true;
287
+ }
288
+
289
+ if (ab.autoTrigger) {
290
+ this.onReady(ab.load.bind(ab, rules));
291
+ }
292
+
293
+ };
294
+
295
+ Object.extend(Event.addBehavior, {
296
+ rules : {}, cache : [],
297
+ reassignAfterAjax : true,
298
+ autoTrigger : true,
299
+
300
+ load : function(rules) {
301
+ for (var selector in rules) {
302
+ var observer = rules[selector];
303
+ var sels = selector.split(',');
304
+ sels.each(function(sel) {
305
+ var parts = sel.split(/:(?=[a-z]+$)/), css = parts[0], event = parts[1];
306
+ $$(css).each(function(element) {
307
+ if (event) {
308
+ $(element).observe(event, observer);
309
+ Event.addBehavior.cache.push([element, event, observer]);
310
+ } else {
311
+ if (!element.$$assigned || !element.$$assigned.include(observer)) {
312
+ if (observer.attach) observer.attach(element);
313
+
314
+ else observer.call($(element));
315
+ element.$$assigned = element.$$assigned || [];
316
+ element.$$assigned.push(observer);
317
+ }
318
+ }
319
+ });
320
+ });
321
+ }
322
+ },
323
+
324
+ unload : function() {
325
+ this.cache.each(function(c) {
326
+ Event.stopObserving.apply(Event, c);
327
+ });
328
+ this.cache = [];
329
+ }
330
+
331
+ });
332
+
333
+ Event.observe(window, 'unload', Event.addBehavior.unload.bind(Event.addBehavior));
334
+
335
+ // A silly Prototype style shortcut for the reckless
336
+ $$$ = Event.addBehavior;
337
+
338
+ // Behaviors can be bound to elements to provide an object orientated way of controlling elements
339
+ // and their behavior. Use Behavior.create() to make a new behavior class then use attach() to
340
+ // glue it to an element. Each element then gets it's own instance of the behavior and any
341
+ // methods called onxxx are bound to the relevent event.
342
+ //
343
+ // Usage:
344
+ //
345
+ // var MyBehavior = Behavior.create({
346
+ // onmouseover : function() { this.element.addClassName('bong') }
347
+ // });
348
+ //
349
+ // Event.addBehavior({ 'a.rollover' : MyBehavior });
350
+ //
351
+ // If you need to pass additional values to initialize use:
352
+ //
353
+ // Event.addBehavior({ 'a.rollover' : MyBehavior(10, { thing : 15 }) })
354
+ //
355
+ // You can also use the attach() method. If you specify extra arguments to attach they get passed to initialize.
356
+ //
357
+ // MyBehavior.attach(el, values, to, init);
358
+ //
359
+ // Finally, the rawest method is using the new constructor normally:
360
+ // var draggable = new Draggable(element, init, vals);
361
+ //
362
+ // Each behaviour has a collection of all its instances in Behavior.instances
363
+ //
364
+ Behavior = {
365
+ create : function(members) {
366
+ var behavior = function() {
367
+ var behavior = arguments.callee;
368
+ if (this == window || $H(this).values().include(behavior)) {
369
+ var args = [];
370
+ for (var i = 0; i < arguments.length; i++)
371
+ args.push(arguments[i]);
372
+
373
+ return function() {
374
+ var initArgs = [this].concat(args);
375
+ behavior.attach.apply(behavior, initArgs);
376
+ };
377
+ } else {
378
+ var args = (arguments.length == 2 && arguments[1] instanceof Array) ?
379
+ arguments[1] : Array.prototype.slice.call(arguments, 1);
380
+
381
+ this.element = $(arguments[0]);
382
+ this.initialize.apply(this, args);
383
+ behavior._bindEvents(this);
384
+ behavior.instances.push(this);
385
+ }
386
+ };
387
+ behavior.prototype.initialize = Prototype.K;
388
+ Object.extend(behavior.prototype, members);
389
+ Object.extend(behavior, Behavior.ClassMethods);
390
+ behavior.instances = [];
391
+ return behavior;
392
+ },
393
+ ClassMethods : {
394
+ attach : function(element) {
395
+ return new this(element, Array.prototype.slice.call(arguments, 1));
396
+ },
397
+ _bindEvents : function(bound) {
398
+ for (var member in bound)
399
+ if (member.match(/^on(.+)/) && typeof bound[member] == 'function')
400
+ bound.element.observe(RegExp.$1, bound[member].bindAsEventListener(bound));
401
+ }
402
+ }
403
+ };
404
+
405
+
@@ -1,7 +1,7 @@
1
1
  <include src="plugins/hobo/tags/rapid"/>
2
2
 
3
3
  <def tag="Page" attrs="title_prefix, title">
4
- <% title ||= human_type + ": " + name(:no_wrapper => true) %>
4
+ <% title ||= type_name + ": " + name(:no_wrapper => true) %>
5
5
  <doctype version="HTML 4.01 Transitional"/>
6
6
  <html>
7
7
  <head param="head">
@@ -1,16 +1,12 @@
1
1
  class <%= class_name %> < ActiveRecord::Base
2
2
 
3
- hobo_model
4
-
5
- include Hobo::AuthenticatedUser
3
+ hobo_user_model :username
6
4
 
7
5
  fields do
8
6
  username :string
9
7
  timestamps
10
8
  end
11
9
 
12
- set_login_attr :username
13
-
14
10
  alias_attribute :to_s, :username
15
11
 
16
12
  # --- Hobo Permissions --- #
@@ -58,8 +54,4 @@ class <%= class_name %> < ActiveRecord::Base
58
54
  true
59
55
  end
60
56
 
61
- def guest?
62
- false
63
- end
64
-
65
57
  end