Filter

Interates through each 'tag_name' element of 'id', for each element, that element is shown if its 'innerHTML' or 'title' attribute contains any of the search terms contained within the pattern.

<input type='text' name='filter' onkeyup='Filter( "some_id", "TR", this.value )'>
function Filter( id, tag_name, pattern )
{
    var element = document.getElementById( id );

    if ( !element )
    {
        alert( "Filter: could not find target element: " + id );
    }
    else
    {
        var terms    = pattern.split( ' ' );
        var elements = element.getElementsByTagName( tag_name );
        var n        = elements.length;

        for ( var i=0; i < n; i++ )
        {
            var e     = elements[i];
            var title = e.getAttribute( "title" );
            var html  = e.innerHTML;

            Toggle.Show( e );

            for ( const index in terms )
            {
                var term = terms[index];

                if ( ! Filter.ElementContainsText( e, term ) )
                {
                    Toggle.Hide( e )
                    break;
                }
            }
        }
    }
}

Filter.ElementContainsText
=
function( e, t )
{
    var contains = false;

    if ( e.children && (0 < e.children.length) )
    {
        for ( const index in e.children )
        {
            var child = e.children[index];

            if ( (contains = Filter.ElementContainsText( child, t )) )
            {
                break;
            }
        }
    }
    else
    if ( Filter.StringContainsText( e.title, t ) )
    {
        contains = true;
    }
    else
    if ( Filter.StringContainsText( e.innerHTML, t ) )
    {
        contains = true;
    }

    return contains;
}

Filter.StringContainsText
=
function( s, t )
{
    var contains = false;

    if ( s )
    {
        if ( "" == t )
        {
            contains = true;
        }
        else
        {
            var lc_s = s.toLowerCase();
            var lc_t = t.toLowerCase();

            contains = (-1 != lc_s.indexOf( lc_t ));
        }
    }

    return contains;
}

Filter Table Body

Filters each TR of the specified table for all of the values contained in the passed form.

Filter.TableBody
=
function( tbody_id, form )
{
    // 1)   Retrieve values frorm any selects/inputs in forms.

    var values = Filter.TableBody.RequiredValues( form ); // Returns text array.

    //  2)  Iterate through tables rows and show/hide matching/unmatching rows.

    var tbody  = document.getElementById( tbody_id );
    var rows   = tbody.getElementsByTagName( "TR" );
    var n      = rows.length;

    for ( var i=0; i < n; i++ )
    {
        var tr = rows[i];

        if ( -1 == tr.className.indexOf( "hidden" ) )
        {
            tr.style.display = Filter.TableBody.ContainsAll( tr, values ) ? "table-row" : "none";
        }
    }
}

Filter.TableBody.RequiredValues
=
function( form )
{
    var values = new Array();
    var n      = form.elements.length;

    for ( var i = 0; i < n; i++ )
    {
        var input = form.elements[i];

        switch ( input.tagName )
        {
        case "SELECT":
            var option = input.options[input.selectedIndex];
            var text   = option.text.toLowerCase();

            if ( option.value && ("" != text) )
            {
                values.push( text );
            }
            break;

        case "INPUT":
            if ( "" != input.value )
            {
                var bits = input.value.split( " " );
                for ( const index in bits )
                {
                    values.push( bits[index].toLowerCase() );
                }
            }
            break;
        }
    }

    return values;
}

Filter.TableBody.ContainsAll
=
function( tr, values )
{
    //  Returns true only if tr contains all values in passed array.

    var contains = true;
    var n        = values.length;

    for ( var i=0; i < n; i++ )
    {
        if (-1 === tr.innerHTML.toLowerCase().indexOf( values[i] ))
        {
            contains = false;
            break;
        }
    }

    return contains;
}