manalang

manalang

  • 05:52:00 pm on February 1, 2006 | # |
    Tags: , , , , , ,

    In the past week I’ve been playing around with PeopleSoft’s built-in search engine (Verity) to come up with a better search experience for users. Riding on the wave of Google Suggest a lot of people have implemented a “live” search feature on their sites. So, I decided to sprinkle a little AJAX on top of PeopleSoft and build the same feature for Enterprise 8.4 and above. Check it out…

    The most unbelievable thing about how I implemented live search on PeopleSoft is that I didn’t customize any delivered code. None. This was possible because of Monkeygrease. Monkeygrease allows me to “inject” JavaScript/CSS/HTML into a page before it’s delivered to the browser. On the back end, I created a simple PeopleSoft iScript to carry out the search and return the results in a <ul> tag… I thought about using JSON, but then that would have added more complexity to the JavaScript.

    Here’s the iScript:

    [WEBLIB_CSS_LSCR.ISCRIPT1.FieldFormula]
    Function FormatPath(&Path As string) Returns string
       Local number &i, &begin, &end;
       Local string &stringToSearch, &stringToCut;
       &stringToSearch = &Path;
       &begin = Find("{", &stringToSearch);
       While &begin > 0
          &end = Find("}", &stringToSearch);
          &stringToCut = Substring(&stringToSearch, &begin, &end - &begin + 1);
          &stringToSearch = Substitute(&stringToSearch, &stringToCut, "");
          &begin = Find("{", &stringToSearch);
          If &i = 1000 Then /* Safety break */
             Break;
          Else
             &i = &i + 1;
          End-If;
       End-While;
       Return Substitute(&stringToSearch, ".", " > ");
    End-Function;
    
    Function IScript_doSearch()
       Local string &q, &node, &partialUrl, &fullUrl, &resultsHtml;
       Local number &resCounter;
       Local ApiObject &portal, &query, &results, &result, &cref;
       Local Request &Request = %Request;
       Local Response &Response = %Response;
    
       REM If no query text avail, return nothing;
       &q = &Request.GetParameter("q");
       If &q = "" Then
          Return;
       End-If;
    
       &portal = %Session.GetPortalRegistry();
       &portal.Open(%Portal);
       &query = &portal.GetSearchQuery();
       &query.Language = %Language;
       &query.QueryText = &q | "*";
       &query.RequestedFields = "CONTENT_PROVIDER,URL,SCORE";
       &query.SortSpecifications = "SCORE desc";
       &results = &query.Execute(1, 20);
    
       If &results  Null Then
          &result = &results.First();
       Else
          &result = Null;
       End-If;
    
       &resCounter = 1;
       While &result  Null
          &node = &result.SearchFields.ItemByName("CONTENT_PROVIDER").Value;
          &partialUrl = &result.SearchFields.ItemByName("URL").Value;
          &fullUrl = &portal.GetAbsoluteContentURL(&node, &partialUrl);
          &cref = &portal.FindCrefByURL(&fullUrl);
          If &cref  Null Then
             If &cref.Authorized And
                   &cref.isVisible And
                   (&cref.URLType = "UPGE" Or
                      &cref.URLType = "UEXT" Or
                      &cref.URLType = "USCR" Or
                      &cref.URLType = "UGEN") Then
                &resultsHtml = &resultsHtml | GetHTMLText(HTML.CSS_LIVE_SEARCH_RESULT, &cref.Label, &cref.AbsolutePortalURL, FormatPath(&cref.Path), &cref.Description);
                If &resCounter = 8 Then
                   Break;
                End-If;
                &resCounter = &resCounter + 1;
             End-If;
          End-If;
          &result = &results.Next();
       End-While;
       &portal.close();
    
       If &resultsHtml  "" Then
          &Response.Write(GetHTMLText(HTML.CSS_LIVE_SEARCH, &resultsHtml));
       End-If;
    End-Function;

    There are two functions in this iScript, FormatPath and IScript_doSearch. FormatPath just formats the path location of the search result item (where it’s stored in the portal registry). The IScript_doSearch is what calls the Verity API to carry out the search. In this function, I filter each result through the portal registry to see if the user has access to the item. This iScript performs amazingly well.

    The iScript above references some HTML objects… here they are:

    [HTML Object: CSS_LIVE_SEARCH]
    <ul>
    %bind(:1)
    </ul>
    [HTML Object: CSS_LIVE_SEARCH_RESULT]
    <li>
    <a href="%bind(:2)" title="%bind(:4)" target="_top">%Bind(:1)</a>
    <div>%bind(:3)</div>
    </li>

    The the only other things I needed to do was code up the JavaScript and CSS to insert into the page. You can view those here: live-search.js and live-search.css. I then “injected” these files via this Monkeygrease rule:

    <rule enabled="true" name="Live Search" url-pattern="(/psp/?([^/]*)?/?([^/]*)?/?([^/]*)?/(h/|s/WEBLIB_EO_PE_LN\.ISCRIPT1\.FieldFormula\.IScript_EPPLN_INFRAME)|/psc/?([^/]*)?/?([^/]*)?/?([^/]*)?/s/WEBLIB_PT_NAV\.ISCRIPT1\.FieldFormula\.IScript_PT_NAV_INFRAME_TITLE).*" insert-at="head-end">
        <![CDATA[
        <script type="text/javascript" src="http://some.server.com/monkeygrease/lib/prototype.js"></script>
        <link rel="stylesheet" href="http://some.server.com/monkeygrease/live-search.css" type="text/css" media="screen" />
        <script type="text/javascript" language="javascript" src="http://some.server.com/monkeygrease/live-search.js"></script>
        ]]>
    </rule>

    As you can see from these Monkeygrease rules, the prototype.js library is required. I used this library to simplify the code… and it did just that.

     

Trackbacks

close Reblog this comment
blog comments powered by Disqus