recordselect 3.0.5 → 3.1.0

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.
@@ -1,419 +0,0 @@
1
- document.observe("dom:loaded", function() {
2
- RecordSelect.document_loaded = true;
3
- document.on('ajax:before', 'div.record-select * li.record a', function(event) {
4
- var link = event.findElement();
5
- if (link) {
6
- if (RecordSelect.notify(link) == false) {
7
- event.stop();
8
- } else {
9
- link.toggleClassName("selected");
10
- }
11
- }
12
- return true;
13
- });
14
- });
15
-
16
- Form.Element.AfterActivity = function(element, callback, delay) {
17
- element = $(element);
18
- if (!delay) delay = 0.25;
19
- new Form.Element.Observer(element, delay, function(element, value) {
20
- // TODO: display loading indicator
21
- if (element.activity_timer) clearTimeout(element.activity_timer);
22
- element.activity_timer = setTimeout(function() {
23
- callback(element.value);
24
- }, delay * 1000 + 50);
25
- });
26
- }
27
-
28
- var RecordSelect = new Object();
29
- RecordSelect.document_loaded = false;
30
-
31
- RecordSelect.notify = function(item) {
32
- var e = Element.up(item, '.record-select-handler');
33
- var onselect = e.onselect || e.getAttribute('onselect');
34
- if (typeof onselect != 'function') onselect = eval(onselect);
35
- if (onselect)
36
- {
37
- try {
38
- onselect(item.parentNode.id.substr(2), (item.down('label') || item).innerHTML.unescapeHTML(), e);
39
- } catch(e) {
40
- alert(e);
41
- }
42
- return false;
43
- }
44
- else return true;
45
- };
46
-
47
- RecordSelect.render_page = function(record_select_id, page) {
48
- var page_element = $$('#' + record_select_id + ' ol')[0];
49
- if (page_element) Element.replace(page_element, page);
50
- };
51
-
52
- RecordSelect.Abstract = Class.create();
53
- Object.extend(RecordSelect.Abstract.prototype, {
54
- /**
55
- * obj - the id or element that will anchor the recordselect to the page
56
- * url - the url to run the recordselect
57
- * options - ??? (check concrete classes)
58
- */
59
- initialize: function(obj, url, options) {
60
- this.obj = $(obj);
61
- this.url = url;
62
- this.options = options;
63
- this.container;
64
- if (this.options.onchange && typeof this.options.onchange != 'function') {
65
- this.options.onchange = eval(this.options.onchange);
66
- }
67
-
68
- if (RecordSelect.document_loaded) this.onload();
69
- else Event.observe(window, 'load', this.onload.bind(this));
70
- },
71
-
72
- /**
73
- * Finish the setup - IE doesn't like doing certain things before the page loads
74
- * --override--
75
- */
76
- onload: function() {},
77
-
78
- /**
79
- * the onselect event handler - when someone clicks on a record
80
- * --override--
81
- */
82
- onselect: function(id, value) {
83
- alert(id + ': ' + value);
84
- },
85
-
86
- /**
87
- * opens the recordselect
88
- */
89
- open: function() {
90
- if (this.is_open()) return;
91
-
92
- new Ajax.Updater(this.container, this.url, {
93
- method: 'get',
94
- evalScripts: true,
95
- asynchronous: true,
96
- onComplete: function() {
97
- this.show();
98
- // needs to be mousedown so the event doesn't get canceled by other code (see issue #26)
99
- Element.observe(document.body, 'mousedown', this.onbodyclick.bindAsEventListener(this));
100
- }.bind(this)
101
- });
102
- },
103
-
104
- /**
105
- * positions and reveals the recordselect
106
- */
107
- show: function() {
108
- var offset = Position.cumulativeOffset(this.obj),
109
- top = Element.getHeight(this.obj) + offset[1],
110
- window_height = document.viewport.getHeight();
111
- this.container.style.left = offset[0] + 'px';
112
- if (top + Element.getHeight(this.container) > window_height)
113
- this.container.style.bottom = (window_height - offset[1]) + 'px';
114
- else this.container.style.top = top + 'px';
115
-
116
- if (this._use_iframe_mask()) {
117
- this.container.insertAdjacentHTML('afterEnd', '<iframe src="javascript:false;" class="record-select-mask" />');
118
- var mask = this.container.next('iframe');
119
- mask.style.left = this.container.style.left;
120
- mask.style.top = this.container.style.top;
121
- }
122
-
123
- this.container.show();
124
-
125
- if (this._use_iframe_mask()) {
126
- var dimensions = this.container.immediateDescendants().first().getDimensions();
127
- mask.style.width = dimensions.width + 'px';
128
- mask.style.height = dimensions.height + 'px';
129
- }
130
- },
131
-
132
- /**
133
- * closes the recordselect by emptying the container
134
- */
135
- close: function() {
136
- if (this._use_iframe_mask()) {
137
- this.container.next('iframe').remove();
138
- }
139
-
140
- this.container.hide();
141
- // hopefully by using remove() instead of innerHTML we won't leak memory
142
- this.container.immediateDescendants().invoke('remove');
143
- },
144
-
145
- /**
146
- * returns true/false for whether the recordselect is open
147
- */
148
- is_open: function() {
149
- return (!this.container.innerHTML.blank())
150
- },
151
-
152
- /**
153
- * when the user clicks outside the dropdown
154
- */
155
- onbodyclick: function(ev) {
156
- if (!this.is_open()) return;
157
- var elem = $(Event.element(ev));
158
- var ancestors = elem.ancestors();
159
- ancestors.push(elem);
160
- if (ancestors.include(this.container) || ancestors.include(this.obj)) return;
161
- this.close();
162
- },
163
-
164
- /**
165
- * creates and initializes (and returns) the recordselect container
166
- */
167
- create_container: function() {
168
- new Insertion.Bottom(document.body, '<div class="record-select-container record-select-handler"></div>');
169
- e = document.body.childNodes[document.body.childNodes.length - 1];
170
- e.onselect = this.onselect.bind(this);
171
- e.style.display = 'none';
172
-
173
- return $(e);
174
- },
175
-
176
- /**
177
- * all the behavior to respond to a text field as a search box
178
- */
179
- _respond_to_text_field: function(text_field) {
180
- // attach the events to start this party
181
- text_field.observe('focus', this.open.bind(this));
182
-
183
- // the autosearch event - needs to happen slightly late (keyup is later than keypress)
184
- text_field.observe('keyup', function() {
185
- if (!this.is_open()) return;
186
- this.container.down('.text-input').value = text_field.value;
187
- }.bind(this));
188
-
189
- // keyboard navigation, if available
190
- if (this.onkeydown) {
191
- text_field.observe('keydown', this.onkeydown.bind(this));
192
- }
193
- },
194
-
195
- _use_iframe_mask: function() {
196
- return this.container.insertAdjacentHTML ? true : false;
197
- }
198
- });
199
-
200
- /**
201
- * Adds keyboard navigation to RecordSelect objects
202
- */
203
- Object.extend(RecordSelect.Abstract.prototype, {
204
- current: null,
205
-
206
- /**
207
- * keyboard navigation - where to intercept the keys is up to the concrete class
208
- */
209
- onkeydown: function(ev) {
210
- var elem;
211
- switch (ev.keyCode) {
212
- case Event.KEY_UP:
213
- if (this.current && this.current.up('.record-select')) elem = this.current.previous();
214
- if (!elem) elem = this.container.getElementsBySelector('ol li.record').last();
215
- this.highlight(elem);
216
- break;
217
- case Event.KEY_DOWN:
218
- if (this.current && this.current.up('.record-select')) elem = this.current.next();
219
- if (!elem) elem = this.container.getElementsBySelector('ol li.record').first();
220
- this.highlight(elem);
221
- break;
222
- case Event.KEY_SPACE:
223
- case Event.KEY_RETURN:
224
- if (this.current) this.current.down('a').onclick();
225
- break;
226
- case Event.KEY_RIGHT:
227
- elem = this.container.down('li.pagination.next');
228
- if (elem) elem.down('a').onclick();
229
- break;
230
- case Event.KEY_LEFT:
231
- elem = this.container.down('li.pagination.previous');
232
- if (elem) elem.down('a').onclick();
233
- break;
234
- case Event.KEY_ESC:
235
- this.close();
236
- break;
237
- default:
238
- return;
239
- }
240
- Event.stop(ev); // so "enter" doesn't submit the form, among other things(?)
241
- },
242
-
243
- /**
244
- * moves the highlight to a new object
245
- */
246
- highlight: function(obj) {
247
- if (this.current) this.current.removeClassName('current');
248
- this.current = $(obj);
249
- obj.addClassName('current');
250
- }
251
- });
252
-
253
- /**
254
- * Used by link_to_record_select
255
- * The options hash should contain a onselect: key, with a javascript function as value
256
- */
257
- RecordSelect.Dialog = Class.create();
258
- RecordSelect.Dialog.prototype = Object.extend(new RecordSelect.Abstract(), {
259
- onload: function() {
260
- this.container = this.create_container();
261
- this.obj.observe('click', this.toggle.bind(this));
262
-
263
- if (this.onkeypress) this.obj.observe('keypress', this.onkeypress.bind(this));
264
- },
265
-
266
- onselect: function(id, value) {
267
- if (this.options.onselect(id, value) != false) this.close();
268
- },
269
-
270
- toggle: function() {
271
- if (this.is_open()) this.close();
272
- else this.open();
273
- }
274
- });
275
-
276
- /**
277
- * Used by record_select_field helper
278
- * The options hash may contain id: and label: keys, designating the current value
279
- * The options hash may also include an onchange: key, where the value is a javascript function (or eval-able string) for an callback routine
280
- * and field_name: key, where value will be set as name of the input field.
281
- */
282
- RecordSelect.Single = Class.create();
283
- RecordSelect.Single.prototype = Object.extend(new RecordSelect.Abstract(), {
284
- onload: function() {
285
- // initialize the container
286
- this.container = this.create_container();
287
- this.container.addClassName('record-select-autocomplete');
288
-
289
- // create the hidden input
290
- new Insertion.After(this.obj, '<input type="hidden" name="" value="" />')
291
- this.hidden_input = this.obj.next();
292
-
293
- // transfer the input name from the text input to the hidden input
294
- this.hidden_input.name = this.obj.name;
295
- this.obj.name = this.options.field_name || '';
296
-
297
- // initialize the values
298
- if (this.options.label) this.set(this.options.id, this.options.label);
299
-
300
- this._respond_to_text_field(this.obj);
301
- if (this.obj.focused) this.open(); // if it was focused before we could attach observers
302
- },
303
-
304
- close: function() {
305
- // if they close the dialog with the text field empty, then delete the id value
306
- if (this.obj.value == '') this.set('', '');
307
-
308
- RecordSelect.Abstract.prototype.close.call(this);
309
- },
310
-
311
- onselect: function(id, value) {
312
- this.set(id, value);
313
- if (this.options.onchange) this.options.onchange.call(this, id, value);
314
- this.obj.fire('recordselect:change', {"id": id, "label": value});
315
- this.close();
316
- },
317
-
318
- /**
319
- * sets the id/label
320
- */
321
- set: function(id, label) {
322
- this.obj.value = label.unescapeHTML();
323
- this.hidden_input.value = id;
324
- }
325
- });
326
-
327
- /**
328
- * Used by record_select_autocomplete helper
329
- * The options hash may contain label: key, designating the current value
330
- * The options hash may also include an onchange: key, where the value is a javascript function (or eval-able string) for an callback routine.
331
- */
332
- RecordSelect.Autocomplete = Class.create();
333
- RecordSelect.Autocomplete.prototype = Object.extend(new RecordSelect.Abstract(), {
334
- onload: function() {
335
- // initialize the container
336
- this.container = this.create_container();
337
- this.container.addClassName('record-select-autocomplete');
338
-
339
- // initialize the values
340
- this.set(this.options.label);
341
-
342
- this._respond_to_text_field(this.obj);
343
- if (this.obj.focused) this.open(); // if it was focused before we could attach observers
344
- },
345
-
346
- close: function() {
347
- // if they close the dialog with the text field empty, then delete the id value
348
- if (this.obj.value == '') this.set('', '');
349
-
350
- RecordSelect.Abstract.prototype.close.call(this);
351
- },
352
-
353
- onselect: function(id, value) {
354
- this.set(value);
355
- if (this.options.onchange) this.options.onchange.call(this, id, value);
356
- this.obj.fire('recordselect:change', {"id": id, "label": value});
357
- this.close();
358
- },
359
-
360
- /**
361
- * sets the id/label
362
- */
363
- set: function(label) {
364
- this.obj.value = label.unescapeHTML();
365
- }
366
- });
367
-
368
- /**
369
- * Used by record_multi_select_field helper.
370
- * Options:
371
- * list - the id (or object) of the <ul> to contain the <li>s of selected entries
372
- * current - an array of id:/label: keys designating the currently selected entries
373
- */
374
- RecordSelect.Multiple = Class.create();
375
- RecordSelect.Multiple.prototype = Object.extend(new RecordSelect.Abstract(), {
376
- onload: function() {
377
- // initialize the container
378
- this.container = this.create_container();
379
- this.container.addClassName('record-select-autocomplete');
380
-
381
- // decide where the <li> entries should be placed
382
- if (this.options.list) this.list_container = $(this.options.list);
383
- else this.list_container = this.obj.next('ul');
384
-
385
- // take the input name from the text input, and store it for this.add()
386
- this.input_name = this.obj.name;
387
- this.obj.name = '';
388
-
389
- // initialize the list
390
- $A(this.options.current).each(function(c) {
391
- this.add(c.id, c.label);
392
- }.bind(this));
393
-
394
- this._respond_to_text_field(this.obj);
395
- if (this.obj.focused) this.open(); // if it was focused before we could attach observers
396
- },
397
-
398
- onselect: function(id, value) {
399
- this.add(id, value);
400
- },
401
-
402
- /**
403
- * Adds a record to the selected list
404
- */
405
- add: function(id, label) {
406
- // return silently if this value has already been selected
407
- var already_selected = this.list_container.getElementsBySelector('input').any(function(i) {
408
- return i.value == id
409
- });
410
- if (already_selected) return;
411
-
412
- var entry = '<li>'
413
- + '<a href="#" onclick="$(this.parentNode).remove(); return false;" class="remove">remove</a>'
414
- + '<input type="hidden" name="' + this.input_name + '" value="' + id + '" />'
415
- + '<label>' + label + '</label>'
416
- + '</li>';
417
- new Insertion.Top(this.list_container, entry);
418
- }
419
- });
@@ -1,31 +0,0 @@
1
- <%
2
- controller ||= params[:controller]
3
- debugger
4
- pagination_url_params = params.merge(:controller => controller, :action => :browse, :search => params[:search], :update => 1)
5
- prev_url = url_for(pagination_url_params.merge(:page => page.prev.number, :escape => false)) if page.prev?
6
- next_url = url_for(pagination_url_params.merge(:page => page.next.number, :escape => false)) if page.next?
7
- -%>
8
- <ol>
9
- <li class="found"><%= rs_(:records_found, :count => page.pager.count,
10
- :model => record_select_config.model.model_name.human(:count => page.pager.count).downcase) %></li>
11
- <% if page.prev? -%>
12
- <li class="pagination previous">
13
- <%= link_to image_tag('record_select/previous.gif', :alt => rs_(:previous)) + " " + rs_(:previous_items,
14
- :count => page.pager.per_page),
15
- {:url => prev_url},
16
- {:href => prev_url, :method => :get, :remote => true} %>
17
- </li>
18
- <% end -%>
19
- <% page.items.each do |record| -%>
20
- <li class="record <%= cycle 'odd', 'even' %>" id="rs<%= record.id -%>">
21
- <%= render_record_in_list(record, controller) %>
22
- </li>
23
- <% end -%>
24
- <% if page.next? -%>
25
- <li class="pagination next">
26
- <%= link_to (rs_(:next_items, :count => page.pager.per_page) + " " + image_tag('record_select/next.gif', :alt => rs_(:next))).html_safe,
27
- {:url => next_url},
28
- {:href => next_url, :method => :get, :remote => true} %>
29
- </li>
30
- <% end -%>
31
- </ol>