Creating a custom Find dialog for MSHTML

The find dialog functionality that comes with the DEC does the trick but if you've moved onto the MSHTML functionality in IE5+ or you want to change the interface in the DEC then you need something custom made.

First, let's put together the code to open the find dialog:

showModelessDialog( "find.html", window,
    "dialogWidth:385px; dialogHeight:165px; scroll:no; status:no; 
    help:no;" ); }

This piece of JavaScript does something pretty simple. It opens find.html into a dialog box. It also passes a reference to the window object to the dialog box.

Note: there are two different types of dialogs in Internet Explorer: Modal and Modeless. A Modal dialog prevents a user from doing anything on the HTML page until they have closed the dialog. Modeless, however, allows the user to still access the main HTML window as well as do things within the dialog. I've used Modeless to allow us to find text in the main window, edit the text in the main window and then go back to the dialog box to search for more words.

The fun really comes in the dialog itself.

<HTML>
    <HEAD>
<TITLE>Find/Replace</TITLE>
<script language="JavaScript">
// on load create a textrange with everything in my 
// editor object tbContentElement 
var rng = dialogArguments.document.all.tbContentElement.
               DOM.selection.createRange();

function window.onunload(){
    dialogArguments.dWin=null; // releases my reference
}

// returns a calculated value for matching case and
// matching whole words
function searchtype(){
    var retval = 0;
  var matchcase = 0;
  var matchword = 0;
  if (document.all.blnMatchCase.checked) matchcase = 4;
  if (document.all.blnMatchWord.checked) matchword = 2;
  retval = matchcase + matchword;
  return(retval);
}

// find the text I want
function findtext(){
  if (document.all.strSearch.value.length < 1) {
    alert("Please enter text in the \"Find what:\" field.");

  } else {
    var searchval = document.all.strSearch.value;
    rng.collapse(false);
    if (rng.findText(searchval, 1000000000, searchtype())) {
      rng.select();
    } else {
      var startfromtop = confirm("Your word was not found.\nWould you 
                                    like to start again from the top?");
      if (startfromtop) {
        rng.expand("textedit"); // selects everything
        rng.collapse(); // collapse at the beginning
        rng.select(); // create the selection
        findtext(); // start again 
      }

    }
  }
}
</script>
</HEAD>
<BODY bgcolor="ThreeDFace">
  <FORM NAME="frmSearch" method="post" action="">
  <TABLE CELLSPACING="0" cellpadding="5" border="0">
  <TR><TD VALIGN="top" align="left" nowrap 
              style="font-family:Arial; font-size:11px;">
    <label for="strSearch" accesskey="n">Fi<u>n</u>d what:</label><br>
    <INPUT TYPE=TEXT SIZE=40 NAME=strSearch 
           id="strSearch" style="width:280px;"><br>
    <INPUT TYPE=Checkbox SIZE=40 NAME=blnMatchCase id="blnMatchCase">
    <label for="blnMatchCase">Match case</label><br>
    <INPUT TYPE=Checkbox SIZE=40 NAME=blnMatchWord ID="blnMatchWord">
    <label for="blnMatchWord">Match whole word only</label>
   </td>
  <td rowspan="2" valign="top">
    <button name="btnFind" accesskey="f" onClick="findtext();"
        style="width:75px; height:22px; font-family:Tahoma; 
               font-size:11px; margin-top:15px"><u>F</u>ind Next</button><br>
    <button name="btnCancel" onClick="window.close();"
        style="width:75px; height:22px; font-family:Tahoma; 
               font-size:11px; margin-top:7px">Close</button><br>
  </td></tr>
</table>
</FORM>
</BODY>
</HTML>

Basically, when you click on the Find Next button it takes the text that is entered into the input and runs the findtext() function. You'll notice that before I use the findText() method I collapse(false)... this ensures that the select moves to the end of a previously found word. This prevents the dialog from never going beyond the one word. The function checks that you've actually entered something in the input and if so, runs the findText() method (read more about the method at MSDN). The third parameter runs a function searchtype() that calculates whether it should match whole words only and/or match case.

The find function moves forward from where the selection is. If it can't find the word then it asks the user whether or not to start at the top. To start from the top we expand the selection to the entire page and then collapse the selection. That way I know the selection is at the beginning of the document.

Without revealing too many of my secrets, it is also possible to add replace and replace all functionality to this dialog with relative ease!

Enjoy!

Published February 22, 2002 · Updated September 17, 2005
Categorized as MSHTML and DEC
Short URL: https://snook.ca/s/111

Conversation

4 Comments · RSS feed
Jaco said on November 10, 2004

i am trying to use the code on for the custom find dialog box but i can't figure out what should be on the page with the find button. can you help me please

Jonathan Snook said on November 10, 2004

The find dialog is designed to be used with an editor. If you look at the first line of the script in the dialog, you'll see that we assign the editor to the rng variable. (More accurately, we create a textrange object from within the editor and assign that). I hope that helps you on your way!

sathish said on January 06, 2005

Any way to hide the close button in showmodelessdialog()?

Jonathan Snook said on January 06, 2005

Nope. The close button is necessary. Otherwise, the possibility exists that there'd be no way to close the window. (like, if the web developer forgot to program a close button or an error occurred on the page that prevented the close button from being rendered.

Sorry, comments are closed for this post. If you have any further questions or comments, feel free to send them to me directly.