hobo_jquery 1.4.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,39 @@
1
+ /* hjq-sortable-collection */
2
+ (function($) {
3
+ var methods = {
4
+ init: function(annotations) {
5
+ var options = $.extend({update: methods.update}, this.hjq('getOptions', annotations));
6
+ this.sortable(options);
7
+ },
8
+
9
+ update: function() {
10
+ var that=$(this);
11
+ var annotations=that.data('rapid')['sortable-collection'];
12
+ var roptions = that.hjq('buildRequest', {type: 'post',
13
+ attrs: annotations.ajax_attrs
14
+ });
15
+ roptions.data['authenticity_token']=that.hjq('pageData').form_auth_token.value;
16
+ roptions.data=$.param(roptions.data);
17
+ that.children("*[data-rapid-context]").each(function(i) {
18
+ roptions.data = roptions.data+"&"+annotations.reorder_parameter+"[]="+$(this).hjq('contextId');
19
+ });
20
+
21
+ $.ajax(annotations.reorder_url, roptions);
22
+ return that;
23
+ }
24
+
25
+ };
26
+
27
+
28
+ $.fn.hjq_sortable_collection = function( method ) {
29
+
30
+ if ( methods[method] ) {
31
+ return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
32
+ } else if ( typeof method === 'object' || ! method ) {
33
+ return methods.init.apply( this, arguments );
34
+ } else {
35
+ $.error( 'Method ' + method + ' does not exist on hjq_sortable_collection' );
36
+ }
37
+ };
38
+
39
+ })( jQuery );
@@ -0,0 +1,87 @@
1
+ /* spinner */
2
+ (function($) {
3
+ var default_options = undefined;
4
+
5
+ // old min_time functionality removed -- using an effect on the
6
+ // removal ensures it stays on screen long enough to be visible.
7
+
8
+ var methods = {
9
+ /* without any options, $(foo).hjq_spinner() places a spinner
10
+ to the left of foo until you remove it via
11
+ $(foo).hjq_spinner('remove');
12
+
13
+ options:
14
+ - spinner-next-to: DOM id of the element to place the spinner next to.
15
+ - spinner-at: selector for the element to place the spinner next to.
16
+ - no-spinner: if set, the spinner is not displayed.
17
+ - spinner-options: passed to [jQuery-UI's position](http://jqueryui.com/demos/position/). Defaults are `{my: 'left center', at: 'right center', offset: '5 0'}`
18
+ - message: the message to display inside the spinner
19
+
20
+ If options.message is false-ish, default_message is displayed.
21
+ */
22
+ init: function(options, default_message) {
23
+ var original=$("#ajax-progress");
24
+ if (original.length==0) return this;
25
+
26
+ options = $.extend({}, defaultOptions.call(this), options);
27
+ if(options['no-spinner']) return this;
28
+
29
+ var clone=original.clone();
30
+ this.data('hjq-spinner', clone);
31
+ clone.data('source', this);
32
+
33
+ clone.find("span").text(options.message || default_message || "");
34
+
35
+ var pos_options = $.extend({}, defaultOptions()['spinner-options'], options['spinner-options']);
36
+
37
+ pos_options.of = this;
38
+ if(options['spinner-at']) pos_options.of=$(options['spinner-at']);
39
+ else if(options['spinner-next-to']) pos_options.of=$("#"+options['spinner-next-to']);
40
+
41
+ clone.insertBefore(original).show().position(pos_options);
42
+ return this;
43
+ },
44
+
45
+ remove: function() {
46
+ var clone = this.data('hjq-spinner');
47
+ var that=this;
48
+ if(!clone) {
49
+ $(".ajax-progress").each(function() {
50
+ if($(this).data('source')[0]==that[0]) {
51
+ clone=$(this);
52
+ return false;
53
+ }
54
+ });
55
+ }
56
+ if(!clone) return this;
57
+ clone.hide('fast');
58
+ return this;
59
+ },
60
+ };
61
+
62
+ var defaultOptions = function() {
63
+ if(default_options) return default_options;
64
+ page_options = this.hjq('pageData');
65
+ default_options = {};
66
+ default_options['spinner-next-to'] = page_options['spinner-next-to'];
67
+ default_options['spinner-at'] = page_options['spinner-at'];
68
+ default_options['no-spinner'] = page_options['no-spinner'];
69
+ default_options['spinner-options'] = page_options['spinner-options'] || {
70
+ my: "right bottom",
71
+ at: "left top"
72
+ };
73
+ default_options['message'] = page_options['message'];
74
+ };
75
+
76
+ $.fn.hjq_spinner = function( method ) {
77
+
78
+ if ( methods[method] ) {
79
+ return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
80
+ } else if ( typeof method === 'object' || ! method ) {
81
+ return methods.init.apply( this, arguments );
82
+ } else {
83
+ $.error( 'Method ' + method + ' does not exist on hjq_spinner' );
84
+ }
85
+ };
86
+
87
+ })( jQuery );
@@ -0,0 +1,319 @@
1
+ /* hobo-jQuery initialization & utility functions */
2
+
3
+ (function($) {
4
+ var page_data = {};
5
+
6
+ //used for javascript testing.
7
+ var num_updates = 0;
8
+
9
+ var methods = {
10
+
11
+ init : function() {
12
+ var top = this;
13
+ this.find("[data-rapid-page-data]").each(function() {
14
+ page_data = $(this).data('rapid-page-data');
15
+ });
16
+ this.find("[data-rapid]").each(function() {
17
+ var that = jQuery(this);
18
+ jQuery.each(jQuery(this).data('rapid'), function(tag, annotations) {
19
+ tag = "hjq_"+tag.replace(/-/g, '_');
20
+ if(that[tag]) {
21
+ that[tag](annotations);
22
+ }
23
+ });
24
+ });
25
+ return top;
26
+ },
27
+
28
+ /* return the ID from the typed-id in the data-rapid-context attribute */
29
+ contextId: function() {
30
+ return this.data('rapid-context').split(":")[1];
31
+ },
32
+
33
+ /* given annotations, turns the values in the _events_ object into functions, merges them into _options_ and returns _options_ */
34
+ getOptions: function(annotations) {
35
+ for(var key in annotations.events) {
36
+ if(annotations.events.hasOwnProperty(key)) {
37
+ annotations.options[key] = methods.createFunction.call(this, annotations.events[key]);
38
+ }
39
+ }
40
+ return annotations.options;
41
+ },
42
+
43
+ /* return the global page_data: hobo_parts, form_auth_token, etc. */
44
+ pageData: function() { return page_data; },
45
+
46
+ /* return the number of current updates. Useful for
47
+ javascript/integration testing */
48
+ numUpdates: function() { return num_updates; },
49
+
50
+ /* this function is called on an update of a part via Ajax. */
51
+ update: function(innerHtml) {
52
+ num_updates += 1;
53
+ var that=this;
54
+ var replacement=this.clone().html(innerHtml).hide();
55
+ var hide_o, show_o;
56
+ if(this.data('hjq-ajax')) {
57
+ hide_o = this.data('hjq-ajax')['hide'];
58
+ show_o = this.data('hjq-ajax')['show'];
59
+ }
60
+ methods.hideAndRemove.call(this, hide_o, function () {
61
+ that.before(replacement);
62
+ methods.show.call(replacement, show_o, function() {num_updates -= 1;});
63
+ });
64
+ methods.init.call(replacement);
65
+ return replacement;
66
+ },
67
+
68
+ /* this function is called on ajax update to update part
69
+ context information */
70
+ updatePartContexts: function(contexts) {
71
+ $.extend(page_data.hobo_parts, contexts);
72
+ },
73
+
74
+ /* hide and removes the element. options is an array or
75
+ * comma-separated string corresponding to the jQuery-UI hide
76
+ * arguments: effect, options, speed & callback. The callback
77
+ * argument is an additional callback called after the one in
78
+ * the options hash. Removal is done after both callbacks. */
79
+ hideAndRemove: function(o, callback) {
80
+ methods.hide.call(this, o, callback, true);
81
+ },
82
+
83
+ /* hides the element. options is an array or
84
+ * comma-separated string corresponding to the jQuery-UI hide
85
+ * arguments: effect, options, speed & callback. The callback
86
+ * argument is an additional callback called after the one in
87
+ * the options hash. Removal is done after both callbacks. */
88
+ hide: function(o, callback, andRemove) {
89
+ var that=this;
90
+ var args = o;
91
+ if(args===undefined) args=page_data.hide;
92
+ if(args===undefined) args=[];
93
+ if (typeof args=='string') args=args.split(',');
94
+ else if($.isArray(args)) args=args.slice(0); //shallow clone
95
+ else args=[];
96
+ o_cb = args[3];
97
+ args[3] = function() {
98
+ if(o_cb) methods.createFunction.call(that, o_cb).apply(this, arguments);
99
+ if(callback) callback.apply(this, arguments);
100
+ if(andRemove) that.remove();
101
+ };
102
+ if(args[0]) {
103
+ that.hide.apply(that, args);
104
+ } else {
105
+ that.hide();
106
+ args[3].call(that);
107
+ }
108
+ return this;
109
+ },
110
+ /* show the element. options is an array or
111
+ * comma-separated string corresponding to the jQuery-UI show
112
+ * arguments: effect, options, speed & callback. The callback
113
+ * argument is an additional callback called after the one in
114
+ * the options hash. */
115
+ show: function(o, callback) {
116
+ var that=this;
117
+ var args = o;
118
+ if(args===undefined) args=page_data.show;
119
+ if(args===undefined) args=[];
120
+ if (typeof args=='string') args=args.split(',');
121
+ else if($.isArray(args)) args=args.slice(0); //shallow clone
122
+ else args=[];
123
+ o_cb = args[3];
124
+ args[3] = function() {
125
+ if(o_cb) methods.createFunction.call(that, o_cb).apply(this, arguments);
126
+ if(callback) callback.apply(this, arguments);
127
+ };
128
+ if(args[0]) {
129
+ that.show.apply(that, args);
130
+ } else {
131
+ that.show();
132
+ args[3].call(that);
133
+ }
134
+ return this;
135
+ },
136
+
137
+ /* given a global function name, find the function */
138
+ functionByName: function(name) {
139
+ var descend = window; // find function by name on the root object
140
+ jQuery.each(name.split("."), function() {
141
+ if(descend) descend = descend[this];
142
+ });
143
+ return descend;
144
+ },
145
+
146
+ /* Given a function name or javascript fragment, return a function */
147
+ createFunction: function(script) {
148
+ if(!script) return function() {};
149
+ if($.isFunction(script)) return script;
150
+ var f=methods.functionByName.call(this, script);
151
+ if(f) return f;
152
+ return function() { return eval(script); };
153
+ },
154
+
155
+ /* Build an options object suitable for sending to
156
+ * jQuery.ajax. (Note that the before & confirm callbacks
157
+ * are called from this function, and the spinner is shown)
158
+ *
159
+ * The returned object will include a 'data' value
160
+ * populated with a hash.
161
+ *
162
+ * Options:
163
+ * type: POST, GET
164
+ * attrs: a hash containing the standard Hobo ajax attributes & callbacks
165
+ * extra_options: merged into the hash sent to jQuery.ajax
166
+ * extra_callbacks: the callbacks in attrs are generally specified by the DRYML; this allows the framework to add their own
167
+ * function: passed to Hobo's ajax_update_response
168
+ * preamble: passed to Hobo's ajax_update_response
169
+ * postamble: passed to Hobo's ajax_update_response
170
+ * content_type: passed to Hobo's ajax_update_response
171
+ *
172
+ */
173
+ buildRequest: function(o) {
174
+ var that = this;
175
+ if (!o.attrs) o.attrs = {};
176
+ if (!o.extra_callbacks) o.extra_callbacks = {};
177
+ var options = {};
178
+
179
+ if(o.attrs.before) {
180
+ if(!methods.createFunction.call(that, o.attrs.before).call(this)) {
181
+ return false;
182
+ }
183
+ }
184
+
185
+ var before_evt=jQuery.Event("rapid:ajax:before");
186
+ that.trigger(before_evt, [that]);
187
+ if(before_evt.isPropagationStopped()) {
188
+ return false;
189
+ }
190
+
191
+ if(o.attrs.confirm) {
192
+ if(!confirm(o.attrs.confirm)) {
193
+ return false;
194
+ }
195
+ }
196
+
197
+ options.context = this;
198
+ options.type = o.type || 'GET';
199
+ options.data = {"render_options[preamble]": o.preamble || '',
200
+ "render_options[contexts_function]": 'hjq.ajax.updatePartContexts'
201
+ };
202
+ if(o.postamble) options.data["render_options[postamble]"] = o.postamble;
203
+ if(o.content_type) options.data["render_options[content_type]"] = o.content_type;
204
+ if(o.attrs.errors_ok) options.data["render_options[errors_ok]"] = 1;
205
+ options.dataType = 'script';
206
+ o.spec = jQuery.extend({'function': 'hjq.ajax.update', preamble: ''}, o.spec);
207
+
208
+ var part_data = {};
209
+ if(o.attrs.hide!==undefined) part_data.hide = o.attrs.hide;
210
+ if(o.attrs.show!==undefined) part_data.show = o.attrs.show;
211
+ if($.isEmptyObject(part_data)) part_data = undefined;
212
+
213
+ // we tell our controller which parts to return by sending it a "render" array.
214
+ var ids=methods.getUpdateIds.call(this, o.attrs);
215
+ for(var i=0; i<ids.length; i++) {
216
+ if(part_data) $("#"+ids[i]).data('hjq-ajax', part_data);
217
+ options.data["render["+i+"][part_context]"] = page_data.hobo_parts[ids[i]];
218
+ options.data["render["+i+"][id]"] = ids[i];
219
+ options.data["render["+i+"][function]"] = o['function'] || 'hjq.ajax.update';
220
+ }
221
+
222
+ this.hjq_spinner(o.attrs, "Saving...");
223
+
224
+ var success_dfd = jQuery.Deferred();
225
+ if(o.attrs.success) success_dfd.done(methods.createFunction.call(that, o.attrs.success));
226
+ if(o.extra_callbacks.success) success_dfd.done(methods.createFunction.call(that, o.extra_callbacks.success));
227
+ success_dfd.done(function() {
228
+ if(o.attrs.reset_form) that[0].reset();
229
+ // if we've been removed, all event handlers on us
230
+ // have already been removed and we don't bubble
231
+ // up, so triggering on that won't do any good
232
+ if(that.parents("body").length==0) $(document).trigger('rapid:ajax:success', [that]);
233
+ else that.trigger('rapid:ajax:success', [that]);
234
+ });
235
+ options.success = success_dfd.resolve;
236
+
237
+ var error_dfd = jQuery.Deferred();
238
+ if(o.attrs.error) error_dfd.done(methods.createFunction.call(that, o.attrs.error));
239
+ if(o.extra_callbacks.error) error_dfd.done(methods.createFunction.call(that, o.extra_callbacks.error));
240
+ error_dfd.done(function() {
241
+ if(that.parents("body").length==0) $(document).trigger('rapid:ajax:error', [that]);
242
+ else that.trigger('rapid:ajax:error', [that]);
243
+ });
244
+ options.error = error_dfd.resolve;
245
+
246
+ var complete_dfd = jQuery.Deferred();
247
+ if(o.attrs.complete) complete_dfd.done(methods.createFunction.call(that, o.attrs.complete));
248
+ if(o.extra_callbacks.complete) complete_dfd.done(methods.createFunction.call(that, o.extra_callbacks.complete));
249
+ complete_dfd.done(function() {
250
+ if(that.parents("body").length==0) $(document).trigger('rapid:ajax:complete', [that]);
251
+ else that.trigger('rapid:ajax:complete', [that]);
252
+ that.hjq_spinner('remove');
253
+ if(o.attrs.refocus_form) that.find(":input[type!=hidden]:first").focus();
254
+ });
255
+ options.complete = complete_dfd.resolve;
256
+
257
+ jQuery.extend(options, o.extra_options);
258
+
259
+ return options;
260
+ },
261
+
262
+ // given ajax_attrs (update, updates and/or ajax), return DOM id's.
263
+ getUpdateIds: function(attrs) {
264
+ var ids = attrs.update || [];
265
+ if (typeof ids=='string') ids=ids.split(',');
266
+
267
+ jQuery(attrs.updates).each(function () {
268
+ ids.push(jQuery(this).attr('id'));
269
+ });
270
+
271
+ if(attrs.ajax) {
272
+ for(var el=this; el.length && !page_data.hobo_parts[el.attr("id")]; el=el.parent());
273
+ if(el.length) ids.push(el.attr('id'));
274
+ }
275
+
276
+ // validate
277
+ for (var i=0; i<ids.length; i++) {
278
+ if(!page_data.hobo_parts[ids[i]]) {
279
+ ids.splice(i, 1);
280
+ i -= 1;
281
+ }
282
+ }
283
+
284
+ return ids;
285
+ }
286
+
287
+
288
+ };
289
+
290
+
291
+ $.fn.hjq = function( method ) {
292
+
293
+ if ( methods[method] ) {
294
+ return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
295
+ } else if ( typeof method === 'object' || ! method ) {
296
+ return methods.init.apply( this, arguments );
297
+ } else {
298
+ $.error( 'Method ' + method + ' does not exist on hjq' );
299
+ }
300
+ };
301
+
302
+ })( jQuery );
303
+
304
+
305
+ // to make the Ajax interface cleaner, these provide direct access to
306
+ // a couple of plugin functions.
307
+ var hjq=(function($) {
308
+ return {
309
+ ajax: {
310
+ update: function (dom_id, innerHtml) {
311
+ $("#"+dom_id).hjq('update',innerHtml);
312
+ },
313
+
314
+ updatePartContexts: function(contexts) {
315
+ $(document).hjq('updatePartContexts', contexts);
316
+ }
317
+ }
318
+ };
319
+ })(jQuery);
@@ -0,0 +1,5 @@
1
+ //= require_tree .
2
+
3
+ jQuery(document).ready(function() {
4
+ jQuery(document).hjq();
5
+ });