I hacked together a simple MochiKit-based ComboBox and am posting it in
case it could be useful to anyone.  If there's a better way to attach
source here than cut and paste, please let me know.
Thanks,
Eric

(pasted into this buffer below: my_combobox.js, my_combobox.css,
my_combobox_sample.html, visibility.js, and visibility.css)
(If you want a graphic button, this looks for a "combo_box_arrow.png"
(not included))



my_combobox.js
----------------------------
/*
 Simple MochiKit-based ComboBox
 Eric Waldheim
 Cobbled together from bits and pieces of:
   ComboBox By Jared Nuzzolillo
   ComboBox Updated by Erik Arvidsson
   DHTML Widgets by Barney Boisvert
   Dojo ComboBox
*/

if (typeof(My) == 'undefined')
{
   My = {};
}

My.ComboBox = function(id, options)
{
   this.__init__(id, options);
};

My.ComboBox.prototype =
{
        __class__: My.ComboBox,

        __init__: function(id, /* optional */config)
        {
                this.node = $(id);
                this.exposed_options = [];

      this.config = MochiKit.Base.update(
                        {
                                maxListLength:10,
                                options:[],
                                optionStringGetter:itemgetter(0)
                        },
                        config || {});

                this.textedit = INPUT({type:'text', 'class':"cbox-input"});
                var button = BUTTON({class:'cbox-button'},
                                                                  
IMG({src:'combo_box_arrow.png',
                                                                                
 alt:'show options'}));
                this.optionslist = DIV({'class':'cbox-list invisible'});
                appendChildNodes(this.node,
                                                          this.textedit, 
button, this.optionslist);

        connect(button, "onfocus", function () { button.blur(); });
                connect(button, 'onclick', bind(this.toggle, this));
                connect(this.optionslist, "onselectstart", function(){return 
false});
                connect(this.optionslist, "onclick", bind(this.clickOption, 
this));
                connect(this.node, "onkeydown", bind(this.handleKey, this));
                connect(this.node, "onkeyup", bind(this.handleKeyUp, this));
                connect(this.node, "onmousedown", bind(this.mouseDown, this));
        },

        mouseDown: function(event)
        {
                var el = event.target();
                while (el.nodeType != 1) el = el.parentNode;
                var elcl = el.className;
                if (elcl.indexOf("cbox-")!=0)
                {
         makeInvisible(this.optionslist);
                }
                else
                {
                        this.textedit.focus();
                        this.moveCaretToEnd();
                }
        },

        _prevTexteditValue: "",
        handleKey: function(event)
        {
                _prevTexteditValue = this.textedit.value;
                var key  = event.key();
                switch(key.code) {
                case 38: // up arrow
                        this.highlightPrevOption();
                        event.stopPropagation();
                        break;
                case 40: // down arrow
                        if (!isVisible(this.optionslist))
                                this.toggle();
                        else
                                this.highlightNextOption();
                        event.stopPropagation();
                        break;
                case 27: // escape
                        makeInvisible(this.optionslist);
                        event.stopPropagation();
                        break;
                case 9: // KEY_TAB
                case 13: //KEY_ENTER:
                        if (isVisible(this.optionslist) && 
this._highlighted_node)
                        {
                                this.selectOption();
                                makeInvisible(this.optionslist);
                        }
                        event.stopPropagation();
                        break;
                }
        },

        handleKeyUp: function(event)
        {
                if (_prevTexteditValue != this.textedit.value)
                {
                        this.exposed_options = [];
                        this.update();
                        this.build(this.exposed_options);
                }
        },

        selectOption: function()
        {
                var tgt = this._highlighted_node;
                this.textedit.value = tgt.getAttribute("Desc");
                this.value = tgt.getAttribute("Data");
        },

        moveCaretToEnd: function()
        {
                var t = this.textedit;
                if (t.createTextRange) {
                        var range = t.createTextRange();
                        range.collapse(false);
                        range.select();
                } else if (t.setSelectionRange) {
                        t.focus();
                        var length = t.value.length;
                        t.setSelectionRange(length, length);
                }
        },

        update: function()
        {
                var textedit_value = this.textedit.value.toLowerCase();
                var vlen = textedit_value.length
                var options = this.config.options;
                var get = this.config.optionStringGetter;
                for(i=0;i<options.length;i++)
                {
         var opt_substr =
get(options[i]).toLowerCase().substring(0,vlen)
         if (textedit_value == opt_substr)
            this.exposed_options.push(options[i]);
                }
        },

        build: function(options)
        {
                var onmouseover = bind(this.itemMouseOver, this);
                var onmouseout = bind(this.itemMouseOut, this);
                var divs = [];
                for (var i = 0; i < options.length; ++i)
                {
                        var data = options[i];
                        var string = this.config.optionStringGetter(data);
                        var div = DIV({'class':'cbox-item',
                                                                
'onmouseover':onmouseover,
                                                                
'onmouseout':onmouseout
                                                          }, string);
                        div.setAttribute('Desc', string);
                        div.setAttribute('Data', data);
                        divs.push(div);
                }
                replaceChildNodes(this.optionslist, divs);

      makeVisible(this.optionslist);
                var visibleCount = Math.min(options.length,
this.config.maxListLength);
      if (!visibleCount)
                {
                        makeInvisible(this.optionslist);
                        this.blurHighlightedNode();
                        return;
                }
                var item_dims = 
getElementDimensions(this.optionslist.firstChild);
                var textedit_dims = getElementDimensions(this.textedit);
                var h = visibleCount ? (visibleCount * item_dims.h) : 0;
                setElementDimensions(this.optionslist, {w:textedit_dims.w, 
h:h});

                this.highlightNode(divs[0]);
        },

        clickOption: function(event)
        {
                this.highlightNode(event.target());
                this.selectOption();
                makeInvisible(this.optionslist);
        },

        toggle: function()
        {
                if (!this.optionslist || !isVisible(this.optionslist))
                {
         this.update();
         this.build(this.config.options);
                        this.textedit.focus();
                }
                else
                {
         makeInvisible(this.optionslist)
                }
        },

        highlightNode: function(node)
        {
                this.focusOptionNode(node);
                node.scrollIntoView(false);
        },

        focusOptionNode: function(node)
        {
                if (this._highlighted_node != node)
                {
                        this.blurHighlightedNode();
                        this._highlighted_node = node;
                        addElementClass(this._highlighted_node, "cbox-hilite");
                }
        },

        blurHighlightedNode: function()
        {
                if (this._highlighted_node)
                {
                        removeElementClass(this._highlighted_node, 
"cbox-hilite");
                        this._highlighted_node = null;
                }
        },

        highlightNextOption: function()
        {
                if ((!this._highlighted_node) || 
!this._highlighted_node.parentNode)
                {
                        this.focusOptionNode(this.optionsListNode.firstChild);
                }
                else if (this._highlighted_node.nextSibling)
                {
                        
this.focusOptionNode(this._highlighted_node.nextSibling);
                }
                this._highlighted_node.scrollIntoView(false);
        },

        highlightPrevOption: function()
        {
                if (this._highlighted_node && 
this._highlighted_node.previousSibling)
                {
                        
this.focusOptionNode(this._highlighted_node.previousSibling);
                }
                this._highlighted_node.scrollIntoView(false);
        },

        itemMouseOver: function(event)
        {
                this.focusOptionNode(event.target);
        },

        itemMouseOut: function(event)
        {
                this.blurHighlightedNode();
        },

        setOptions: function(d)
        {
                this.config.options = d;
        },

        setText: function(d)
        {
                this.textedit.value = d;
        }

};


document.write('<link rel="STYLESHEET" type="text/css"
href="my_combobox.css">')

------------------------------
my_combobox.css:
-----------------------------
.cbox-button { cursor:pointer; border:0; padding:0; }
.cbox-item { cursor:pointer; background:white; border:1px solid white;
color: black; font-family:verdana; font-size: 9pt; }
.cbox-hilite { background: rgb(234,242,255); border:1px solid
rgb(120,172,255);}
.cbox-input  { border:1px solid rgb(120,172,255) !important;
width:138px !important; vertical-align:baseline; }
.cbox-list { border:1px solid black; background:white; padding:1px;
width:149px; z-index:1000; position:absolute; overflow:auto; }

--------------------------------------------------
my_combobox_sample.html:
--------------------------------------------------
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd";>
<html>
<head>

<link rel="stylesheet" type="text/css" href="visibility.css" />
<link rel="stylesheet" type="text/css" href="my_combobox.css" />

<script type='text/javascript' src='MochiKit/MochiKit.js'></script>
<script type='text/javascript' src='MochiKit/New.js'></script>
<script type='text/javascript' src='MochiKit/Signal.js'></script>
<script type='text/javascript' src='visibility.js'></script>
<script type='text/javascript' src='my_combobox.js'></script>


<script type='text/javascript'>

connect(window, 'onload', init_bu_cbox);

function init_bu_cbox()
{
        var d1 = [["argy",1], ["benluc",2], ["benlieeeeck",3], ["baco",4],
       ["cargo",1], ["senluc",2], ["seeeck",3], ["flaco",4],
       ["targe",1], ["tux",2], ["tick",3], ["taco",4],
       ["true",1], ["train",2], ["tried",3], ["telephone",4],
       ["telepathy",1], ["tink",2], ["tidal",3], ["total",4],
       ["tuna",1], ["timorous",2], ["tidy",3], ["tipsy",4],
       ["marge",1], ["men",2], ["menlieeeeck",3], ["maco",4],
       ["darge",1], ["denluc",2], ["denlieeeeck",3], ["daco",4],
       ["warge",1], ["genluc",2], ["wenlieeeeck",3], ["waco",4],
       ["large",1], ["lenluc",2], ["zoo",3], ["lago",4],
                                ];
        var d2 = [{code: 'a', desc: 'AAA'},
                                 {code: 'b', desc: 'BBB'},
                                 {code: 'c', desc: 'CCC'},
                                 {code: 'x', desc: 'XXX'},
                                 {code: 'y', desc: 'YYY'},
                                 {code: 'z', desc: 'ZZZ'}];

        var flctr_cbox_1 = new My.ComboBox('flctr_cbox_1');
        flctr_cbox_1.setOptions(d1);
        flctr_cbox_1.setText('charge');

        var flctr_cbox_2 = new My.ComboBox('flctr_cbox_2',
                                                                                
                        {options: d2,
                                                                                
                         optionStringGetter: itemgetter('desc')
                                                                                
                        });

        var flctr_cbox_3 = new My.ComboBox('flctr_cbox_3',
                                                                                
                  { maxListLength: 15});
        callLater(3, function() { flctr_cbox_3.setOptions(d1); });
}

</script>
</head>
<body>
        <div id="flctr_cbox_1"></div>
        <br>
        <div id="flctr_cbox_2"></div>
        <br>
        <div id="flctr_cbox_3"></div>
</body>
</html>

------------------------------
visibility.js
------------------------------
function toggleVisible(elem) {
   toggleElementClass("invisible", elem);
}

function makeVisible(elem) {
   removeElementClass(elem, "invisible");
}

function makeInvisible(elem) {
   addElementClass(elem, "invisible");
}

function isVisible(elem) {
   // you may also want to check for
   // getElement(elem).style.display == "none"
   return !hasElementClass(elem, "invisible");
};

----------------------------
visibility.css
----------------------------
.invisible { display: none; }


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"MochiKit" group.
To post to this group, send email to mochikit@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at http://groups.google.com/group/mochikit
-~----------~----~----~----~------~----~------~--~---

Reply via email to