hobo_jquery 1.4.0.pre2
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/.gitmodules +3 -0
- data/LICENSE.txt +22 -0
- data/README.markdown +1 -0
- data/VERSION +1 -0
- data/app/helpers/hobo_jquery_helper.rb +5 -0
- data/hobo_jquery.gemspec +23 -0
- data/lib/hobo_jquery/railtie.rb +6 -0
- data/lib/hobo_jquery.rb +11 -0
- data/taglibs/hobo_jquery.dryml +18 -0
- data/vendor/assets/javascripts/hobo-jquery/hjq-a.js +33 -0
- data/vendor/assets/javascripts/hobo-jquery/hjq-click-editor.js +44 -0
- data/vendor/assets/javascripts/hobo-jquery/hjq-delete-button.js +43 -0
- data/vendor/assets/javascripts/hobo-jquery/hjq-filter-menu.js +6 -0
- data/vendor/assets/javascripts/hobo-jquery/hjq-form.js +64 -0
- data/vendor/assets/javascripts/hobo-jquery/hjq-formlet.js +49 -0
- data/vendor/assets/javascripts/hobo-jquery/hjq-hot-input.js +15 -0
- data/vendor/assets/javascripts/hobo-jquery/hjq-input-many.js +176 -0
- data/vendor/assets/javascripts/hobo-jquery/hjq-live-editor.js +25 -0
- data/vendor/assets/javascripts/hobo-jquery/hjq-live-search.js +13 -0
- data/vendor/assets/javascripts/hobo-jquery/hjq-search-results.js +9 -0
- data/vendor/assets/javascripts/hobo-jquery/hjq-select-many.js +62 -0
- data/vendor/assets/javascripts/hobo-jquery/hjq-sortable-collection.js +39 -0
- data/vendor/assets/javascripts/hobo-jquery/hjq-spinner.js +87 -0
- data/vendor/assets/javascripts/hobo-jquery/hjq.js +319 -0
- data/vendor/assets/javascripts/hobo_jquery.js +5 -0
- data/vendor/assets/javascripts/jquery.form.js +859 -0
- data/vendor/assets/stylesheets/hobo_jquery.css +3 -0
- metadata +104 -0
@@ -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);
|