// Copyright (c) 2009-2010 Emantix
// All rights reserved.
//
// This file contains confidential and proprietary information of Emantix

/******************************************************************************
* com.emantix.Click.js
*******************************************************************************
* Purpose:
*       This file contains Emantix JavaScript code to handle click processing.
* Usage:
*       - The typical scenario for using this file from an HTML file is:
*         <script language='JavaScript' src='com.emantix.Click.js'></script>
* Assumptions:
*       - The file "com.bristle.jslib.Exception.js" has already been loaded.
*       - The file "com.bristle.jslib.Util.js" has already been loaded.
*       - The file "com.bristle.jslib.MsgBox.js" has already been loaded.
*       - The file "com.bristle.jslib.Layout.js" has already been loaded.
*       - The file "com.bristle.jslib.Event.js" has already been loaded.
* Effects:
*       - None.
* Anticipated Changes:
* Notes:
* Implementation Notes:
* Portability Issues:
* Revision History:
*   $Log$
******************************************************************************/

// Create the "namespace" to hold the functions in this file.
// Note:  Don't redefine "com" or other objects that may be defined in other 
//        JavaScript files.  Such definitions step on each other and cause 
//        errors like:
//              "com.bristle.jslib is null or not an object."
//        on the first call to any function in the hierarchy.  This can be
//        very difficult to diagnose because the message points you to the 
//        file containing the first executed function call, not necessarily 
//        the file containing the error.  For example, creating the namespace
//        wrong for com.abc can step on the com portion of the namespace for 
//        com.xyz, and cause errors on calls to com.xyz.pdq.mno.function1().
if  (typeof(com) == "undefined")           { eval("var com = {};"); }
if  (typeof(com.emantix) == "undefined")   { eval("com.emantix = {};"); } 
com.emantix.Click = {};

// These variables are the default settings for Emantix searches.
// They can be overridden in each the HTML file.
com.emantix.Click.strContextWords = "";
                        // Search words that set the page-specific search 
                        // context
com.emantix.Click.strQueryURLPrefix = "http://www.google.com/search";
                        // Prefix of URL used for all searches
com.emantix.Click.strIgnoreThisURL = "";
                        // URL to be ignored during the search
com.emantix.Click.strSearchOnlyThisURL = "";
                        // The only URL to be searched

// These variables maintain the state of the Emantix software and are not 
// typically updated outside of this file.
com.emantix.Click.intSelectedRegionCounter = 0;
com.emantix.Click.strSELECTED_REGION_ID_PREFIX = "emantixSelectedRegion";

com.emantix.Click.mouseHandler =
function(evt)
{
    // Get event which IE does not pass as a param like other browsers do.
    if (com.bristle.jslib.Util.isMissingNullOrUndefined(evt))
    {
         evt = window.event;
    }

    var objMenu = document.getElementById("emantixContext");
    var objTarget = com.bristle.jslib.Event.target(evt);
 
    // Any click when the menu is visible, whether on the menu or not, hides 
    // the menu.
    if (objMenu.style.visibility == 'visible')
    {
        objMenu.style.visibility="hidden";
    }

    if (false);
    else if (com.bristle.jslib.Event.isRightMouseButtonEvent(evt))
    {
        // Note: Can't use shorthand:
        //              this.showMenu(evt); 
        //       here for some reason.
        //       Perhaps because com.emantix.Click.mouseHandler() is called 
        //       as an event handler?
        com.emantix.Click.showMenu(evt);
    }
    else if (com.bristle.jslib.Util.isOrIsInsideHTMLElement(objTarget, "A"))
    {
        // Nothing to do.  Ignore clicks on links whether they are links
        // that we created, or links in the context menu, or other links.
        // Do nothing and allow the browser to follow the link as usual.
    }
    else if (com.bristle.jslib.Util.isAncestorNode(objTarget, objMenu))
    {
        // Nothing to do.  Ignore clicks on the context menu since the
        // menu items are links and will automatically be executed.
    }
    else
    {
        // Note: Can't use shorthand:
        //              this.wrapSelectedText(evt);
        //       here for some reason.
        //       Perhaps because com.emantix.Click.mouseHandler() is called 
        //       as an event handler?
        com.emantix.Click.wrapSelectedText(evt);
    }

    return true;
}

// Catch all MouseUp events, including left and right click, context menu, etc.
// Note: This line must come AFTER the definition of 
//       com.emantix.Click.mouseHandler.  Otherwise "undefined" is assigned
//       to onmouseup.
document.onmouseup = com.emantix.Click.mouseHandler;
// Suppress the regular context menu.
document.oncontextmenu=new Function("return false");


com.emantix.Click.wrapSelectedText =
function(evt)
{
    // Wrap an ANCHOR element around the selected text.
    // Note: This is the technique used for Firefox, Safari, Netscape, 
    //       etc.   Pretty much any browser except Internet Explorer.
    // Note: This should be the first technique tried because the Opera 
    //       browser supports both window.getSelection and document.selection,
    //       but does a better job with window.getSelection, per:
    //              http://www.quirksmode.org/dom/range_intro.html
    if (window.getSelection)
    {
        var objSelection = window.getSelection();
        if (objSelection.getRangeAt 
            && objSelection.rangeCount > 0)
        {
//?? Does the following work for Safari?  If not, replace with the following
//?? as shown in http://www.quirksmode.org/dom/range_intro.html :
//??function getRangeObject(selectionObject) 
//??{
//??    if (selectionObject.getRangeAt)
//??    {
//??        return selectionObject.getRangeAt(0);
//??    }
//??    else
//??    { // Safari!
//??        var range = document.createRange();
//??        range.setStart(selectionObject.anchorNode,selectionObject.anchorOffset);
//??        range.setEnd(selectionObject.focusNode,selectionObject.focusOffset);
//??        return range;
//??    }
//??}
            var objSelectionRange = objSelection.getRangeAt(0);
            // Ignore selections that start and end in different HTML elements.
            // For example, selections that include the end of one paragraph 
            // or list item and the start of another, or part of a bolded or 
            // italics section and also some text that precedes or follows it.
            // Allow selections that completely contain one or more HTML
            // elements, like multiple paragraphs, or a stretch of text that 
            // includes complete bold or italics sections.
            // This is to avoid asking Range.surroundContents() to wrap a 
            // single ANCHOR element around the start or end tag, but not 
            // both, of another element.  Otherwise, it behaves differently
            // in different browsers and even different versions of the same
            // browser.  In some, it ignores the request.  In others, it 
            // tries to fix the problems by inserting end and start tags, 
            // which can do things like ending a paragraph or list item and
            // starting a new one.
            //?? Should do a better job of this, by recognizing the problem
            //?? situations and wrapping each piece of the selected HTML 
            //?? in a separate ANCHOR.  We'd end up with multiple ANCHORs,
            //?? each properly nested inside a single HTML element, and 
            //?? avoid improper nesting (overlapping) of HTML elements.
            var xmlStartNode = objSelectionRange.startContainer;
            var xmlEndNode   = objSelectionRange.endContainer;
            var xmlStartElement 
                = com.bristle.jslib.Util.getParentElementOrSelfElement
                                         (xmlStartNode);
            var xmlEndElement 
                = com.bristle.jslib.Util.getParentElementOrSelfElement
                                         (xmlEndNode);
            if (xmlStartElement == xmlEndElement)
            {
                var objAncestor = objSelectionRange.commonAncestorContainer;
//?? Now have a DOM node, which may or may not be an "Element" object.
//?? It can be operated on as shown below.
//?? Could look inside it to find nested HTML tags and insert multiple 
//?? anchors in and among the tags.  For now, just wrap the entire 
//?? selection in a single anchor.
//??                debugPrint(objAncestor.nodeName);
//??                debugPrint(objAncestor.nodeType);
//??                debugPrint(objAncestor.nodeValue);    

                // Expand the selection range to include full words at the
                // start and end, where the user may have selected partial
                // words.
                objSelectionRange 
                  = com.bristle.jslib.Util.roundRangeToWholeWordsWithDelimitersTrimmed
                        (objSelectionRange);

                // Ignore selections that result in nothing but a single word
                // delimiter.
                if (com.bristle.jslib.Util.rangeIsASingleWordDelimiter
                    (objSelectionRange))
                {
                    return;
                }

                var strAnchorId = this.strSELECTED_REGION_ID_PREFIX
                                + (++(this.intSelectedRegionCounter));
                var objNewAnchor = document.createElement("A");
                objNewAnchor.className = 'emantix-selected-region';
                objNewAnchor.id = strAnchorId;
                objSelectionRange.surroundContents(objNewAnchor);
                if (objSelection.removeRange)
                {
                    // Don't call removeRange() if it doesn't exist, for 
                    // example, in Safari 4 on Mac.
                    objSelection.removeRange(objSelectionRange);
                }
                this.buildSearchPhrasesAndUpdateAllAnchors();
            }
            else
            {
                com.bristle.jslib.Util.showStatusBarMessage
                  ("Select text within a single paragraph", 10);
            }
        }
    }
    // Note: This is the technique used for Internet Explorer.
    else if (document.selection)
    {
        var objSelection = document.selection;
        if (objSelection.createRange)
        {
            var objSelectionTextRange = objSelection.createRange();
            // Ignore selections that start and end in different HTML elements.
            // For example, selections that include the end of one paragraph 
            // or list item and the start of another, or part of a bolded or 
            // italics section and also some text that precedes or follows it.
            // Allow selections that completely contain one or more HTML
            // elements, like multiple paragraphs, or a stretch of text that 
            // includes complete bold or italics sections.
            // This is to avoid wrapping a single ANCHOR element around the 
            // start or end tag, but not both, of another element, which may
            // cause different behavior in different browsers, or even 
            // different versions of the same browser.  The ANCHOR may be 
            // ignored, or it may cause other HTML elements to be rendered
            // incorrectly.  Some browsers may assume the existence of end
            // and start tags that appear to be missing, for example by 
            // displaying the end of a paragraph or list item and the start 
            // of a new one.
            //?? Should do a better job of this, by recognizing the problem
            //?? situations and wrapping each piece of the selected HTML 
            //?? in a separate ANCHOR.  We'd end up with multiple ANCHORs,
            //?? each properly nested inside a single HTML element, and 
            //?? avoid improper nesting (overlapping) of HTML elements.
            var objSelectionStartTextRange
              = objSelectionTextRange.duplicate();
            objSelectionStartTextRange.collapse(true);
            var objSelectionEndTextRange 
              = objSelectionTextRange.duplicate();
            objSelectionEndTextRange.collapse(false);
            if (objSelectionStartTextRange.parentElement() == 
                objSelectionEndTextRange.parentElement())
            {
                var objAncestor = objSelectionTextRange.parentElement();
//?? Now have an "Element" object, which is a DOM node.
//?? It can be operated on as shown below.
//?? Could look inside it to find nested HTML tags and insert multiple 
//?? anchors in and among the tags.  For now, just wrap the entire 
//?? selection in a single anchor.
//??                debugPrint(objAncestor.tagName);  // Element only
//??                debugPrint(objAncestor.nodeName);
//??                debugPrint(objAncestor.nodeType);
//??                debugPrint(objAncestor.nodeValue);

                // Expand the selection range to include full words at the
                // start and end, where the user may have selected partial
                // words.
                objSelectionTextRange 
                  = com.bristle.jslib.Util.roundTextRangeToWholeWordsWithDelimitersTrimmed
                        (objSelectionTextRange);

                // Ignore selections that result in nothing but a single word
                // delimiter.
                if (com.bristle.jslib.Util.textRangeIsASingleWordDelimiter
                    (objSelectionTextRange))
                {
                    return;
                }

                var strAnchorId = this.strSELECTED_REGION_ID_PREFIX 
                                + (++(this.intSelectedRegionCounter));
                var strSelectedHTML = objSelectionTextRange.htmlText;
                // Change any leading space in the selected text to an HTML
                // non-breaking space.  This is a workaround for a bug in 
                // TextRange.pasteHTML() of IE 6 and 7 (and perhaps others), 
                // that it strips leading spaces from the HTML before pasting
                // it.  The bug is fixed in IE 8.
                if (strSelectedHTML.substring(0,1) == " ")
                {
                    strSelectedHTML = "&nbsp;" + strSelectedHTML.substr(1);
                }
                var strNewHTML = "<a class='emantix-selected-region'"
                               +   " id='" + strAnchorId + "'"
                               + ">"
                               + strSelectedHTML
                               + "</a>";
                objSelectionTextRange.pasteHTML(strNewHTML);
                this.buildSearchPhrasesAndUpdateAllAnchors();
                // Clear the selection since we've changed some or all of 
                // the HTML for the text that the user selected.  If we've
                // changed all of the text, the selection is already cleared,
                // so this is unnecessary, but if we've trimmed some word
                // delimiters and only replaced part of the selected text,
                // selection highlighting may still show, which causes two
                // problems:
                // - Looks funny to the user
                // - Causes the new IE8 popup functionality that can 
                //   automatically do a Google or other search to do so
                //   with no search parameters.  It is better to clear the 
                //   selection which prevents the IE8 popup from happening
                //   at all.
                objSelection.empty();
            }
            else
            {
                com.bristle.jslib.Util.showStatusBarMessage
                  ("Select text within a single paragraph", 10);
            }
        }
    }
    else
    {
        com.bristle.jslib.Util.showStatusBarMessage
                  ("This browser not yet supported for selecting text for"
                   + " an Emantix search", 10);
    }
    return;
}

com.emantix.Click.showMenu =
function(evt)
{
    var objMenu = document.getElementById("emantixContext");
    var strSearchPhrases = this.buildSearchPhrases();

    // Populate the context menu.
    // Note: This must be done BEFORE the calculation below of the
    //       position of the menu, since that calculation relies on 
    //       on being able to determine the size of the menu.
    objMenu.innerHTML = this.buildContextMenu(strSearchPhrases);

    var intMenuWidth 
        = com.bristle.jslib.Layout.getOuterWidth(objMenu);
    var intMenuHeight 
        = com.bristle.jslib.Layout.getOuterHeight(objMenu);
    var intDocumentWidth 
        = com.bristle.jslib.Layout.getOuterWidth(document.body);
    var intDocumentHeight 
        = com.bristle.jslib.Layout.getOuterHeight(document.body);
    var intViewportLeft 
        = com.bristle.jslib.Layout.getViewportLeft();
    var intViewportTop 
        = com.bristle.jslib.Layout.getViewportTop();
    var intViewportWidth 
        = com.bristle.jslib.Layout.getViewportWidth();
    var intViewportHeight
        = com.bristle.jslib.Layout.getViewportHeight();
    var intMouseXRelativeToViewport = evt.clientX; 
    var intMouseYRelativeToViewport = evt.clientY; 

    // Compute the position of the right edge of the menu if
    // we put the left edge at the mouse position.  Reduce it
    // as needed to not clip the menu against the right edge
    // of the window.
    // Do the same for the bottom edge of the menu.
    var intScrollbarThickness = 20;
    var intMenuRightRelativeToViewport
        = Math.min(intMouseXRelativeToViewport + intMenuWidth
                  ,intViewportWidth - intScrollbarThickness
                  )
    var intMenuBottomRelativeToViewport
        = Math.min(intMouseYRelativeToViewport + intMenuHeight
                  ,intViewportHeight - intScrollbarThickness
                  )

    // Compute the position of the left edge of the menu, increasing
    // it as needed to not clip the menu against the left edge of the 
    // window.
    // Do the same for the top edge of the menu.
    // Note: If the window width is less than the menu width or the 
    //       window height is less than the menu height, the right 
    //       or bottom edge of the menu will still be clipped, 
    //       which is unavoidable.
    var intMenuLeftRelativeToViewport
        = Math.max(0, intMenuRightRelativeToViewport - intMenuWidth);
    var intMenuTopRelativeToViewport
        = Math.max(0, intMenuBottomRelativeToViewport - intMenuHeight);

    var intMenuLeftRelativeToDocument = 
          intMenuLeftRelativeToViewport + intViewportLeft;
    var intMenuTopRelativeToDocument = 
          intMenuTopRelativeToViewport  + intViewportTop;
    // Note: Must append "px" or nothing happens.  The left and top
    //       values are unchanged.  Why?
    objMenu.style.left=intMenuLeftRelativeToDocument + "px";
    objMenu.style.top=intMenuTopRelativeToDocument + "px";

    this.fadeIn();
}

com.emantix.Click.intFadeIndex = 0;
com.emantix.Click.fadeIn =
function()
{
    var ie5 = (document.getElementById && document.all); 
    var n6  = (document.getElementById && !document.all); 
    if(ie5 || n6)
    {
        document.getElementById('emantixContext').style.visibility = 'visible';
        if(ie5)
        {
            document.getElementById('emantixContext').filters.alpha.opacity 
              = this.intFadeIndex;
        }
        if(n6)
        {
            document.getElementById('emantixContext').style.MozOpacity 
              = this.intFadeIndex/100; 
        }
        this.intFadeIndex += 3;
        goIn = setTimeout("com.emantix.Click.fadeIn()", 1);
        if(this.intFadeIndex >= 100) clearTimeout(goIn);
    }
}

/******************************************************************************
* Return the list of search phrases as a string containing zero or more 
* quoted strings.
******************************************************************************/
com.emantix.Click.buildSearchPhrases =
function()
{
    var strSearchPhrases = "";
    for (var i = 1; i <= this.intSelectedRegionCounter; i++)
    {
        var anchor = document.getElementById
                                (this.strSELECTED_REGION_ID_PREFIX + i);
        //?? Should not be necessary to test this, but sometimes nested 
        //?? anchors in Mac Firefox 3.5.3 (and perhaps other browsers)
        //?? cause problems, especially when their start or end positions
        //?? within the stream of displayed text coincide exactly.
        if (anchor)
        {
            var strTextContent = com.bristle.jslib.Util.getTextContent(anchor);
            strTextContent = com.bristle.jslib.Util.compressWhitespace
                                                        (strTextContent);
            strTextContent = com.bristle.jslib.Util.trim(strTextContent);
            if (strTextContent.length > 0)
            {
                strSearchPhrases += ' "' + strTextContent + '"';
            }
        }
    }
    strSearchPhrases = com.bristle.jslib.Util.ltrim(strSearchPhrases);
    return strSearchPhrases;
}

/******************************************************************************
* Build the list of search phrases from all anchors, and update all anchors
* to refer to the same list.
******************************************************************************/
com.emantix.Click.buildSearchPhrasesAndUpdateAllAnchors =
function()
{
    var strSearchPhrases = this.buildSearchPhrases();
    for (var i = 1; i <= this.intSelectedRegionCounter; i++)
    {
        var anchor = document.getElementById
                                (this.strSELECTED_REGION_ID_PREFIX + i);
        var strConnectURL = this.buildConnectURL
                                (this.strContextWords, strSearchPhrases);
        anchor.href = strConnectURL;
    }
}

/******************************************************************************
* Functions to build the popup context menu and its parts.
******************************************************************************/
com.emantix.Click.buildSiteRestrictions =
function()
{
    if (!com.bristle.jslib.Util.isMissingNullUndefinedOrEmptyString
            (this.strSearchOnlyThisURL))
    {
        return "site:" + this.strSearchOnlyThisURL;
    }
    else if (!com.bristle.jslib.Util.isMissingNullUndefinedOrEmptyString
            (this.strIgnoreThisURL))
    {
        return "-site:" + this.strIgnoreThisURL;
    }
    else
    {
        return "";
    }
}

com.emantix.Click.buildConnectURL =
function(strContextWords, strSearchPhrases)
{
    var strImFeelingLuckyURLParams = "btnI=1&sourceid=navclient";
    var strURL = this.strQueryURLPrefix
               + "?"
               + strImFeelingLuckyURLParams 
               + "&"
               + "q=" + strSearchPhrases 
                      + " " 
                      + strContextWords
                      + " " 
                      + this.buildSiteRestrictions()
               ;
    strURL = encodeURI(strURL);
    return strURL;
}

com.emantix.Click.buildConnectAnchor =
function(strContextWords, strSearchPhrases)
{
    return "<a href='" 
         +           this.buildConnectURL(strContextWords, strSearchPhrases) 
         +         "'"
         +   " class='emantix-function-default'"
         +   " title='Connect to best matching content'"
         +    ">"
         +   "Connect"
         + "</a>"
         ;
}

com.emantix.Click.buildSearchURL =
function(strContextWords, strSearchPhrases)
{
    var strURL = this.strQueryURLPrefix
               + "?"
               + "q=" + strSearchPhrases 
                      + " " 
                      + strContextWords
                      + " " 
                      + this.buildSiteRestrictions()
               ;
    strURL = encodeURI(strURL);
    return strURL;
}

com.emantix.Click.buildSearchAnchor =
function(strContextWords, strSearchPhrases)
{
    return "<a href='" 
         +           this.buildSearchURL(strContextWords, strSearchPhrases)
         +         "'"
         +   " class='emantix-function'"
         +   " title='Go to search results'"
         +    ">"
         +   "Search"
         + "</a>"
         ;
}

com.emantix.Click.buildImageURL =
function(strContextWords, strSearchPhrases)
{
    var strURL = "http://www.bing.com/images/search"
               + "?"
               + "q=" + strSearchPhrases
                      + " " 
                      + strContextWords
               ;
    strURL = encodeURI(strURL);
    return strURL;
}

com.emantix.Click.buildImageAnchor =
function(strContextWords, strSearchPhrases)
{
    return "<a href='" 
         +           this.buildImageURL(strContextWords, strSearchPhrases)
         +         "'"
         +   " class='emantix-function'"
         +   " title='Go to image search results'"
         +    ">"
         +   "Images"
         + "</a>"
         ;
}

com.emantix.Click.buildVideoURL =
function(strContextWords, strSearchPhrases)
{
    var strURL = "http://www.youtube.com/results"
               + "?"
               + "search_query=" + strSearchPhrases
                                 + " " 
                                 + strContextWords
               ;
    strURL = encodeURI(strURL);
    return strURL;
}

com.emantix.Click.buildVideoAnchor =
function(strContextWords, strSearchPhrases)
{
    return "<a href='" 
         +           this.buildVideoURL(strContextWords, strSearchPhrases)
         +         "'"
         +   " class='emantix-function'"
         +   " title='Go to video search results'"
         +    ">"
         +   "Videos"
         + "</a>"
         ;
}

com.emantix.Click.buildExpertURL =
function(strContextWords, strSearchPhrases)
{
    var strURL = "http://www.linkedin.com/commonSearch"
               + "?"
               + "type=people"
               + "&"
               + "keywords=" + strSearchPhrases
                             + " " 
                             + strContextWords
               ;
    strURL = encodeURI(strURL);
    return strURL;
}

com.emantix.Click.buildExpertAnchor =
function(strContextWords, strSearchPhrases)
{
    return "<a href='" 
         +           this.buildExpertURL(strContextWords, strSearchPhrases)
         +         "'"
         +   " class='emantix-function'"
         +   " title='Go to expert search results'"
         +    ">"
         +   "Experts"
         + "</a>"
         ;
}

com.emantix.Click.buildBookURL =
function(strContextWords, strSearchPhrases)
{
    var strURL = "http://www.amazon.com/gp/search"
               //?? How many of these URL params are really necessary?
               //?? What does each do?
               + "?ie=UTF8"
               + "&tag=knowledgeserv" 
               + "&index=blended" 
               + "&linkCode=ur2" 
               + "&camp=1789" 
               + "&creative=9325"
               + "&keywords=" + strSearchPhrases
                              + " " 
                              + strContextWords
               ;
    strURL = encodeURI(strURL);
    return strURL;
}

com.emantix.Click.buildBookAnchor =
function(strContextWords, strSearchPhrases)
{
    return "<a href='" 
         +           this.buildBookURL(strContextWords, strSearchPhrases)
         +         "'"
         +   " class='emantix-function'"
         +   " title='Go to book search results'"
         +    ">"
         +   "Books"
         + "</a>"
         ;
}

com.emantix.Click.buildProductURL =
function(strContextWords, strSearchPhrases)
{
    var strURL = "http://shopping.yahoo.com/search"
               + "?"
               + "p=" + strSearchPhrases
                      + " " 
                      + strContextWords
               ;
    strURL = encodeURI(strURL);
    return strURL;
}

com.emantix.Click.buildProductAnchor =
function(strContextWords, strSearchPhrases)
{
    return "<a href='" 
         +           this.buildProductURL(strContextWords, strSearchPhrases)
         +         "'"
         +   " class='emantix-function'"
         +   " title='Go to product search results'"
         +    ">"
         +   "Products"
         + "</a>"
         ;
}

com.emantix.Click.buildLocateURL =
function(strContextWords, strSearchPhrases)
{
    var strURL = "http://www.yellowpages.com/relevance/New-York-NY/"
               + strSearchPhrases
               + " " 
               + strContextWords
               + "?expansion_factor=1"
               + "&search_mode=any"
               ;
    strURL = encodeURI(strURL);
    return strURL;
}

com.emantix.Click.buildLocateAnchor =
function(strContextWords, strSearchPhrases)
{
    return "<a href='" 
         +           this.buildLocateURL(strContextWords, strSearchPhrases)
         +         "'"
         +   " class='emantix-function'"
         +   " title='Go to business search results'"
         +    ">"
         +   "Businesses"
         + "</a>"
         ;
}

// Custom - copy, paste and edit in html for custom menu items
com.emantix.Click.buildCustom1URL =
function(strContextWords, strSearchPhrases)
{
    var strURL = "http://www.querystring.com?q="
               + strSearchPhrases
               + " " 
               + strContextWords
			   + "other code"
               ;
    strURL = encodeURI(strURL);
    return strURL;
}

com.emantix.Click.buildCustom1Anchor =
function(strContextWords, strSearchPhrases)
{
    return "<a href='" 
         +           this.buildCustom1URL(strContextWords, strSearchPhrases)
         +         "'"
         +   " class='emantix-function'"
         +   " title=''Description of search"
         +    ">"
         +   "Menu Name"
         + "</a>"
         ;
}
// End custom 

com.emantix.Click.buildUnlinkAnchor =
function()
{
    return "<div class='emantix-separator'></div>"   
	     + "<div align='right'>"
	     + "<a href='javascript:location.reload(true)'"
         +   " class='emantix-function'"
         +   " title='Remove all custom hyperlinks from the page'"
         +    ">"
         +   "Remove Links "
         + "</a>"
	     + "</div>" 
         ;
}

com.emantix.Click.buildPropertiesAnchor =
function()
{
    return  "<div class='emantix-separator'></div>" 
	     + "<div align='right'>"
	     + "<span"
         +   " class='emantix-function-disabled'"
         +   " title='Emantix Properties'"
         +    ">"
         +   "Properties "
         + "</span>"  
		  + "</div>" 
         ;
}

com.emantix.Click.buildHomeAnchor =
function()
{
    return "<a href='http://www.emantix.com'"
         +         " target='_blank'"
         +          ">"
         +   "<img src='../images/emantix_rc.gif'"
         +       " width='110'"
         +       " height='30'"
         +       " border='0'"
         +       " title='Learn more at Emantix.com'"
         +       " >"
         + "</a>"
         ;
}


com.emantix.Click.buildContextMenu =
function(strSearchPhrases)
{
    return this.buildConnectAnchor  (this.strContextWords, strSearchPhrases)
	     + this.buildSearchAnchor  (this.strContextWords, strSearchPhrases)
         + this.buildImageAnchor    (this.strContextWords, strSearchPhrases)  
         + this.buildVideoAnchor    (this.strContextWords, strSearchPhrases)
         + this.buildExpertAnchor   (this.strContextWords, strSearchPhrases)  
         + this.buildBookAnchor    (this.strContextWords, strSearchPhrases) 	 
         + this.buildProductAnchor    (this.strContextWords, strSearchPhrases)	 
         + this.buildLocateAnchor (this.strContextWords, strSearchPhrases)
	     // Custom search		 
         + this.buildCustom1Anchor (this.strContextWords, strSearchPhrases)
	     // Custom search		 
         + this.buildCustom2Anchor  (this.strContextWords, strSearchPhrases)
		 // Custom search		 
         + this.buildCustom3Anchor  (this.strContextWords, strSearchPhrases)
  		 + this.buildUnlinkAnchor ()
		 + this.buildPropertiesAnchor ()
         + this.buildHomeAnchor ()
         ;
}

/******************************************************************************
* Display a debug message.  There should be no calls to this routine in 
* production code.  For debugging only.
******************************************************************************/
function debugPrint(strMessage)
{
    com.bristle.jslib.MsgBox.debugPrint(strMessage);
}
