recordselect 3.10.8 → 4.0.0

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