Skip to content

Commit 1eb80e0

Browse files
committed
adds dnd DropTargetAdapter, preliminary work on editable combobox
1 parent 2c2ce57 commit 1eb80e0

File tree

5 files changed

+10741
-0
lines changed

5 files changed

+10741
-0
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
package java.awt.dnd;
27+
28+
/**
29+
* An abstract adapter class for receiving drop target events. The methods in
30+
* this class are empty. This class exists only as a convenience for creating
31+
* listener objects.
32+
* <p>
33+
* Extend this class to create a <code>DropTargetEvent</code> listener
34+
* and override the methods for the events of interest. (If you implement the
35+
* <code>DropTargetListener</code> interface, you have to define all of
36+
* the methods in it. This abstract class defines a null implementation for
37+
* every method except <code>drop(DropTargetDropEvent)</code>, so you only have
38+
* to define methods for events you care about.) You must provide an
39+
* implementation for at least <code>drop(DropTargetDropEvent)</code>. This
40+
* method cannot have a null implementation because its specification requires
41+
* that you either accept or reject the drop, and, if accepted, indicate
42+
* whether the drop was successful.
43+
* <p>
44+
* Create a listener object using the extended class and then register it with
45+
* a <code>DropTarget</code>. When the drag enters, moves over, or exits
46+
* the operable part of the drop site for that <code>DropTarget</code>, when
47+
* the drop action changes, and when the drop occurs, the relevant method in
48+
* the listener object is invoked, and the <code>DropTargetEvent</code> is
49+
* passed to it.
50+
* <p>
51+
* The operable part of the drop site for the <code>DropTarget</code> is
52+
* the part of the associated <code>Component</code>'s geometry that is not
53+
* obscured by an overlapping top-level window or by another
54+
* <code>Component</code> higher in the Z-order that has an associated active
55+
* <code>DropTarget</code>.
56+
* <p>
57+
* During the drag, the data associated with the current drag operation can be
58+
* retrieved by calling <code>getTransferable()</code> on
59+
* <code>DropTargetDragEvent</code> instances passed to the listener's
60+
* methods.
61+
* <p>
62+
* Note that <code>getTransferable()</code> on the
63+
* <code>DropTargetDragEvent</code> instance should only be called within the
64+
* respective listener's method and all the necessary data should be retrieved
65+
* from the returned <code>Transferable</code> before that method returns.
66+
*
67+
* @see DropTargetEvent
68+
* @see DropTargetListener
69+
*
70+
* @author David Mendenhall
71+
* @since 1.4
72+
*/
73+
public abstract class DropTargetAdapter implements DropTargetListener {
74+
75+
/**
76+
* Called while a drag operation is ongoing, when the mouse pointer enters
77+
* the operable part of the drop site for the <code>DropTarget</code>
78+
* registered with this listener.
79+
*
80+
* @param dtde the <code>DropTargetDragEvent</code>
81+
*/
82+
public void dragEnter(DropTargetDragEvent dtde) {}
83+
84+
/**
85+
* Called when a drag operation is ongoing, while the mouse pointer is still
86+
* over the operable part of the drop site for the <code>DropTarget</code>
87+
* registered with this listener.
88+
*
89+
* @param dtde the <code>DropTargetDragEvent</code>
90+
*/
91+
public void dragOver(DropTargetDragEvent dtde) {}
92+
93+
/**
94+
* Called if the user has modified
95+
* the current drop gesture.
96+
*
97+
* @param dtde the <code>DropTargetDragEvent</code>
98+
*/
99+
public void dropActionChanged(DropTargetDragEvent dtde) {}
100+
101+
/**
102+
* Called while a drag operation is ongoing, when the mouse pointer has
103+
* exited the operable part of the drop site for the
104+
* <code>DropTarget</code> registered with this listener.
105+
*
106+
* @param dte the <code>DropTargetEvent</code>
107+
*/
108+
public void dragExit(DropTargetEvent dte) {}
109+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* jQuery Editable Select
3+
* Indri Muska <indrimuska@gmail.com>
4+
*
5+
* Source on GitHub @ https://github.com/indrimuska/jquery-editable-select
6+
*/
7+
8+
input.es-input { padding-right: 20px !important; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAICAYAAADJEc7MAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAG2YAABzjgAA4DIAAIM2AAB5CAAAxgwAADT6AAAgbL5TJ5gAAABGSURBVHjaYvz//z8DOYCJgUzA0tnZidPK8vJyRpw24pLEpwnuVHRFhDQxMDAwMPz//x+OOzo6/iPz8WFGuocqAAAA//8DAD/sORHYg7kaAAAAAElFTkSuQmCC) right center no-repeat; }
9+
input.es-input.open {
10+
-webkit-border-bottom-left-radius: 0; -moz-border-radius-bottomleft: 0; border-bottom-left-radius: 0;
11+
-webkit-border-bottom-right-radius: 0; -moz-border-radius-bottomright: 0; border-bottom-right-radius: 0; }
12+
.es-list { position: absolute; padding: 0; margin: 0; border: 1px solid #d1d1d1; display: none; z-index: 1000; background: #fff; max-height: 160px; overflow-y: auto;
13+
-moz-box-shadow: 0 2px 3px #ccc; -webkit-box-shadow: 0 2px 3px #ccc; box-shadow: 0 2px 3px #ccc; }
14+
.es-list li { display: block; padding: 5px 10px; margin: 0; }
15+
.es-list li.selected { background: #f3f3f3; }
16+
.es-list li[disabled] { opacity: .5; }
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
/**
2+
* jQuery Editable Select
3+
* Indri Muska <indrimuska@gmail.com>
4+
*
5+
* Source on GitHub @ https://github.com/indrimuska/jquery-editable-select
6+
*/
7+
8+
(function ($) {
9+
// jQuery Editable Select
10+
EditableSelect = function (select, options) {
11+
var that = this;
12+
13+
this.options = options;
14+
this.$select = $(select);
15+
this.$input = $('<input type="text" autocomplete="off">');
16+
this.$list = $('<ul class="es-list">');
17+
this.utility = new EditableSelectUtility(this);
18+
19+
if (['focus', 'manual'].indexOf(this.options.trigger) < 0) this.options.trigger = 'focus';
20+
if (['default', 'fade', 'slide'].indexOf(this.options.effects) < 0) this.options.effects = 'default';
21+
if (isNaN(this.options.duration) && ['fast', 'slow'].indexOf(this.options.duration) < 0) this.options.duration = 'fast';
22+
23+
// create text input
24+
this.$select.replaceWith(this.$input);
25+
this.$list.appendTo(this.options.appendTo || this.$input.parent());
26+
27+
// initalization
28+
this.utility.initialize();
29+
this.utility.initializeList();
30+
this.utility.initializeInput();
31+
this.utility.trigger('created');
32+
}
33+
EditableSelect.DEFAULTS = { filter: true, effects: 'default', duration: 'fast', trigger: 'focus' };
34+
EditableSelect.prototype.filter = function () {
35+
var hiddens = 0;
36+
var search = this.$input.val().toLowerCase().trim();
37+
38+
this.$list.find('li').addClass('es-visible').show();
39+
if (this.options.filter) {
40+
hiddens = this.$list.find('li').filter(function (i, li) { return $(li).text().toLowerCase().indexOf(search) < 0; }).hide().removeClass('es-visible').length;
41+
if (this.$list.find('li').length == hiddens) this.hide();
42+
}
43+
};
44+
EditableSelect.prototype.show = function () {
45+
this.$list.css({
46+
top: this.$input.position().top + this.$input.outerHeight() - 1,
47+
left: this.$input.position().left,
48+
width: this.$input.outerWidth()
49+
});
50+
51+
if (!this.$list.is(':visible') && this.$list.find('li.es-visible').length > 0) {
52+
var fns = { default: 'show', fade: 'fadeIn', slide: 'slideDown' };
53+
var fn = fns[this.options.effects];
54+
55+
this.utility.trigger('show');
56+
this.$input.addClass('open');
57+
this.$list[fn](this.options.duration, $.proxy(this.utility.trigger, this.utility, 'shown'));
58+
}
59+
};
60+
EditableSelect.prototype.hide = function () {
61+
var fns = { default: 'hide', fade: 'fadeOut', slide: 'slideUp' };
62+
var fn = fns[this.options.effects];
63+
64+
this.utility.trigger('hide');
65+
this.$input.removeClass('open');
66+
this.$list[fn](this.options.duration, $.proxy(this.utility.trigger, this.utility, 'hidden'));
67+
};
68+
EditableSelect.prototype.select = function ($li) {
69+
if (!this.$list.has($li) || !$li.is('li.es-visible:not([disabled])')) return;
70+
this.$input.val($li.text());
71+
if (this.options.filter) this.hide();
72+
this.filter();
73+
this.utility.trigger('select', $li);
74+
};
75+
EditableSelect.prototype.add = function (text, index, attrs, data) {
76+
var $li = $('<li>').html(text);
77+
var $option = $('<option>').text(text);
78+
var last = this.$list.find('li').length;
79+
80+
if (isNaN(index)) index = last;
81+
else index = Math.min(Math.max(0, index), last);
82+
if (index == 0) {
83+
this.$list.prepend($li);
84+
this.$select.prepend($option);
85+
} else {
86+
this.$list.find('li').eq(index - 1).after($li);
87+
this.$select.find('option').eq(index - 1).after($option);
88+
}
89+
this.utility.setAttributes($li, attrs, data);
90+
this.utility.setAttributes($option, attrs, data);
91+
this.filter();
92+
};
93+
EditableSelect.prototype.remove = function (index) {
94+
var last = this.$list.find('li').length;
95+
96+
if (isNaN(index)) index = last;
97+
else index = Math.min(Math.max(0, index), last - 1);
98+
this.$list.find('li').eq(index).remove();
99+
this.$select.find('option').eq(index).remove();
100+
this.filter();
101+
};
102+
EditableSelect.prototype.clear = function () {
103+
this.$list.find('li').remove();
104+
this.$select.find('option').remove();
105+
this.filter();
106+
};
107+
EditableSelect.prototype.destroy = function () {
108+
this.$list.off('mousemove mousedown mouseup');
109+
this.$input.off('focus blur input keydown');
110+
this.$input.replaceWith(this.$select);
111+
this.$list.remove();
112+
this.$select.removeData('editable-select');
113+
};
114+
115+
// Utility
116+
EditableSelectUtility = function (es) {
117+
this.es = es;
118+
}
119+
EditableSelectUtility.prototype.initialize = function () {
120+
var that = this;
121+
that.setAttributes(that.es.$input, that.es.$select[0].attributes, that.es.$select.data());
122+
that.es.$input.addClass('es-input').data('editable-select', that.es);
123+
that.es.$select.find('option').each(function (i, option) {
124+
var $option = $(option).remove();
125+
that.es.add($option.text(), i, option.attributes, $option.data());
126+
if ($option.attr('selected')) that.es.$input.val($option.text());
127+
});
128+
that.es.filter();
129+
};
130+
EditableSelectUtility.prototype.initializeList = function () {
131+
var that = this;
132+
that.es.$list
133+
.on('mousemove', 'li:not([disabled])', function () {
134+
that.es.$list.find('.selected').removeClass('selected');
135+
$(this).addClass('selected');
136+
})
137+
.on('mousedown', 'li', function (e) {
138+
if ($(this).is('[disabled]')) e.preventDefault();
139+
else that.es.select($(this));
140+
})
141+
.on('mouseup', function () {
142+
that.es.$list.find('li.selected').removeClass('selected');
143+
});
144+
};
145+
EditableSelectUtility.prototype.initializeInput = function () {
146+
var that = this;
147+
switch (this.es.options.trigger) {
148+
default:
149+
case 'focus':
150+
that.es.$input
151+
.on('focus', $.proxy(that.es.show, that.es))
152+
.on('blur', $.proxy(that.es.hide, that.es));
153+
break;
154+
case 'manual':
155+
break;
156+
}
157+
that.es.$input.on('input keydown', function (e) {
158+
switch (e.keyCode) {
159+
case 38: // Up
160+
var visibles = that.es.$list.find('li.es-visible:not([disabled])');
161+
var selectedIndex = visibles.index(visibles.filter('li.selected'));
162+
that.highlight(selectedIndex - 1);
163+
e.preventDefault();
164+
break;
165+
case 40: // Down
166+
var visibles = that.es.$list.find('li.es-visible:not([disabled])');
167+
var selectedIndex = visibles.index(visibles.filter('li.selected'));
168+
that.highlight(selectedIndex + 1);
169+
e.preventDefault();
170+
break;
171+
case 13: // Enter
172+
if (that.es.$list.is(':visible')) {
173+
that.es.select(that.es.$list.find('li.selected'));
174+
e.preventDefault();
175+
}
176+
break;
177+
case 9: // Tab
178+
case 27: // Esc
179+
that.es.hide();
180+
break;
181+
default:
182+
that.es.filter();
183+
that.highlight(0);
184+
break;
185+
}
186+
});
187+
};
188+
EditableSelectUtility.prototype.highlight = function (index) {
189+
var that = this;
190+
that.es.show();
191+
setTimeout(function () {
192+
var visibles = that.es.$list.find('li.es-visible');
193+
var oldSelected = that.es.$list.find('li.selected').removeClass('selected');
194+
var oldSelectedIndex = visibles.index(oldSelected);
195+
196+
if (visibles.length > 0) {
197+
var selectedIndex = (visibles.length + index) % visibles.length;
198+
var selected = visibles.eq(selectedIndex);
199+
var top = selected.position().top;
200+
201+
selected.addClass('selected');
202+
if (selectedIndex < oldSelectedIndex && top < 0)
203+
that.es.$list.scrollTop(that.es.$list.scrollTop() + top);
204+
if (selectedIndex > oldSelectedIndex && top + selected.outerHeight() > that.es.$list.outerHeight())
205+
that.es.$list.scrollTop(that.es.$list.scrollTop() + selected.outerHeight() + 2 * (top - that.es.$list.outerHeight()));
206+
}
207+
});
208+
};
209+
EditableSelectUtility.prototype.setAttributes = function ($element, attrs, data) {
210+
$.each(attrs || {}, function (i, attr) { $element.attr(attr.name, attr.value); });
211+
$element.data(data);
212+
};
213+
EditableSelectUtility.prototype.trigger = function (event) {
214+
var params = Array.prototype.slice.call(arguments, 1);
215+
var args = [event + '.editable-select'];
216+
args.push(params);
217+
this.es.$select.trigger.apply(this.es.$select, args);
218+
this.es.$input.trigger.apply(this.es.$input, args);
219+
};
220+
221+
// Plugin
222+
Plugin = function (option) {
223+
var args = Array.prototype.slice.call(arguments, 1);
224+
return this.each(function () {
225+
var $this = $(this);
226+
var data = $this.data('editable-select');
227+
var options = $.extend({}, EditableSelect.DEFAULTS, $this.data(), typeof option == 'object' && option);
228+
229+
if (!data) data = new EditableSelect(this, options);
230+
if (typeof option == 'string') data[option].apply(data, args);
231+
});
232+
}
233+
$.fn.editableSelect = Plugin;
234+
$.fn.editableSelect.Constructor = EditableSelect;
235+
236+
})(jQuery);

0 commit comments

Comments
 (0)