Ajax Search Framework

From VYRE

Jump to: navigation, search

The Ajax Search Framework is built on top of VYRE Unify's content and user gateways. The framework allows you to control how to search content repositories and user realms.

Ajax Search Framework
type: Javascript Framework
module: Publishing module

Contents

Getting Started

The ajax framework will be included in VYRE Unify 4.3.1.7 and above.

This section will go through the basics of setting up the framework and the page for use

Including the Javascript files

[Note]

Note

You don't need to add the following scripts to your page if your page is used within the Foresight framework as the scripts are already included.

The framework has been coded in javascript, in order to perform searches we need to import these scripts onto the page for use.

 <!--The main Search framework-->
 
 <script type="text/javascript" src="/javascript/pub_module/search_jax.js"></script>
 
 <!--JSON utility-->
 <script type="text/javascript" src="/javascript/pub_module/JSONstring.js"></script>  
 
 <!--If you are searching Unify's user realms include this file-->
 <script type="text/javascript" src="/javascript/pub_module/user_jax.js"></script>
 
 <!--If you are searching Unifys data-stores and file-stores include this file-->
 <script type="text/javascript" src="/javascript/pub_module/content_jax.js"></script>

CSS

Some of the frameworks rendering is dependant on CSS styling, you will need to import the appropriate CSS so that pagination and plugins are rendered appropriately.

HTML Containers

Inorder for the framework to render results and other widgets and controls on the page, the framework needs to have certain containers setup. When an instance of a search is initialised and executed the framework will look for these containers to update them with the search. The following containers need to be declared on the page

Loader
The loader container will be displayed when the search is waiting for a response from the server. This container usually contains some funky loading gif.
Sortbar
The framework supports extensions known as plugins, these are self contained widgets that control the state of the search. The sortbar container will be used as the default container for these plugins to be appended to.
Pagination(top)
The framework generates pagination automatically, the framework can render pagination on up to two locations, usually above and below the search results. This container will be used to render the pagination at the top.
searchResults
Search responses from the server come in the form of transformed xml using XSL, the resultant XHTML is rendered in this container.
Pagination(bottom)
This container will render pagination below the search results.
 <div id="loadingDiv" valign="middle" class="hide"></div>
 <div id="sortBar" class="sortBar"></div>
 <div class="paginationContainer ajaxPagination"></div>
 <div id="searchResults" class="searchResults"></div>
 <div class="paginationContainer2 ajaxPagination"></div>
 
 <!--In the xsl to facilitate pagination-->
 <input type="hidden" id="countValue" class="countValue" value="{search-results/size}"/>

Remember to add a hidden input into the xsl you use to render the results, this is so that framework knows how many total results there are for a request to generate the pagination. If the pagination fails to render try applying a container namespace to the containers above. See the section on Container Namespaces for more details.

Basic Search

In this chapter we will discuss how to setup a basic search using the framework. Make sure you have followed the steps in chapter 2.

Logging

A logging module has been implemented for the framework, and is used throughout the code to log warnings,errors and information. The default logging mechanism uses Firebug's console object to print debugging messages.

The logging is disabled by default, but you can enable it with the following code.

 VYRE.Utils.Logger.setLogging(true);


The logger allows different modes of logging;


log
VYRE.Utils.Logger.log("Logging something...");
info
 VYRE.Utils.Logger.info("LSome information");
warn
VYRE.Utils.Logger.warn("Something is not right");
error
VYRE.Utils.Logger.error("Woops.. Something broke:");

VYRE.AjaxSearch Constructor

The search framework is centered around one main class VYRE.AjaxSearch , we need to instantiate this class with settings that the framework will rely upon.

var ajs = new VYRE.AjaxSearch({
    searchType: 'content',
    gatewayId: 1,
    pageId: $page_id,
    portletId: $portlet_id,                     /* since 4.4.0.1 */
    xslPath: '/full/path/to/xsl/resource',      /* since 4.8, for earlier versions use now deprecated xslId */                            
    storeId: 1,
    displayItemId: null,
    realmId: 'initial',
    contextPath: '$context_path',
    loadContentAndMetadata: false,              /* deprecated in 4.6 */
    loadLinkedItems: false,                     /* deprecated in 4.6 */
    loadLinkedContent: false,                   /* deprecated in 4.6 */
    loadLinkedUsers: false,                     /* deprecated in 4.6 */
    loadLocalizations: false,                   /* deprecated in 4.6 */
    showTaxonomyTree: false,                    /* deprecated in 4.6 */
    loadLinkDefinitionIds: '1,2',               /* deprecated in 4.6 */
    globalXmlCfgId: 1234,                       /* alternatively specify this for fine granular XML results -- since Unify 4.6 */
    useCache: true,
    cacheTimeout: 600,
    cacheScope: 'application',
    usingLocalisedPath: true,                   /* support for locale velocity variables since 4.6 */
    localisedPath: '$localised_current_path',   /* since 4.6, used together with 'usingLocalisedPath' */
    customParameters: {                         /* custom xsl parameters since 4.6 */
        name: "Some Name",                      /* becomes <xsl:param name="param_name"/> */
        type: "Grid"
    },
    outputFormat: "json"                        /* optional - since 4.6.3 */
});

The constructor takes in an object which contains a varying amount of properties. Below are explanations of what the properties mean.

searchType
This property will tell the framework to either search for 'content' or for 'user'
gatewayId
The gatewayId which allows you to view specific content or user realms, make sure you have created this before configuring. This can be done in publishing -> gateways
gatewayName
The gatewayName which allows you to view specific content or user realms, make sure you have created this before configuring. This can be done in publishing -> gateways. Since 4.8.0.1
pageId
Inorder for the XSL to know information about the current path we need to pass this when we make the request. Use the velocity variable $page_id to do this.
portletId
Inorder for the XSL to know information about the portlet render attributes we need to pass this when we make the request. Use the velocity variable $portlet_id to do this. This functionality was introduced in Unify 4.4.0.1. If you are using a previous version this feature will not be available.
xslId
This the legacy id of the XSL file that will be used to transform the search result. Deprecated since Unify 4.8.
xslPath
Full path to XSL for search results transformation. Since Unify 4.8.
storeId
specifies the storeId(s) of the store(s) that will be search upon. If you are searching more than one store make sure you delimit the stores with a comma. e.g. "1,3,5"
contentStoreNames
specifies the name of the store(s) that will be search upon. If you are searching more than one store make sure you delimit the stores with a comma. e.g. "news,article,pictures"
displayItemId
In order for the XSL to reference the current item id on an item display page we need to pass this along with the ajax request. We can do this using the velocity variable $current_item_id
contextPath
In order for the XSL to know the context path, we need to pass this along with the ajax request. We can do this by using the velocity variable $context_path
showTaxonomyTree
in Unify versions before Unify 4.5, this value could only be initialized with true or false.
in Unify versions after Unify 4.5, this value can be set more in a more flexible manner. For more details, see Ajax Search Framework Taxonomy Setting.
In either case, default value is false (if unset).
searchIndex
Specifies whether to search for active or working versions.
loadLinkDefinitionIds
specifies the link definition Id(s), if the search brings back linked items, specify what linked items to bring back. If nothing is defined all link definition will be followed, but if defined use a string with comma sepperated list of Id's. e.g. "1,2,3"
useCache
Set to true to use cache up the results of the request, default value is false. This functionality was introduced in Unify 4.5. If you are using a previous version this feature will not be available.
cacheScope
Scope of the cache, either per user or for the whole application, default is application. This works in the same way as user based caching in page cache.
cacheTimeout
Time to store the cache in seconds, defaults to one hour. Not needed if cacheCron is used.
cacheCron
Cron expression to determine when to flush the cache. Not needed if cacheTimeout is used.
usingLocalisedPath
Set it to true to enable localisation related velocity variables. This functionality was introduced in Unify 4.6. If you are using a previous version this feature will not be available.
localisedPath
This is used altogether with usingLocalisedPath, this variable is used to pass the current localised path, and thus should be set to $localised_current_path. This will be used to calculated the velocity locale related variables used in the search. This functionality was introduced in Unify 4.6. If you are using a previous version this feature will not be available.
globalXmlCfgId
Set this value in order to use relevant Global XML configuration. If this parameter is set, other XML-related parameters (loadContentAndMetadata, loadLinkedItems, loadLinkedContent, loadLinkedUsers, loadLocalizations, showTaxonomyTree, loadLinkDefinitionIds) will be ignored. This functionality was introduced in Unify 4.6. If you are using a previous version this feature will not be available.
globalXmlCfgPath
Set this value in order to use relevant Global XML configuration.
customParameters
This is a map of parameter names to parameter values that should be passed into the XSL that is being used for rendering. To use the parameters in XSL, the name will be prefixed with "param_". For example, to use the parameter type in XSL, <xsl:param name="param_type"/> should be used.
outputFormat
optional - will output the response in a json format, in use with item ajax framework This functionality was introduced in Unify 4.6.3. If you are using a previous version this feature will not be available.

Performing the Search

Once all the containers and object instantiation has been done we can invoke the search, which will send a request to the server, the response will then be rendered in the searchResults container.

[Note]

Note

The default saved seach is set to active:true and the results per page is defaulted to 10.


 ajs.search();  // performs search
 ajs.sortedSearch(); //defaults to page 1 of the result set and then searches


Sorting

The framework allows the ability to change how the results are sorted, we need to pass the field that the results will be sorted by. The results will then be sorted by lucene serverside before we recieve the response. The main sort fields we can use are as follows.

ajs.setSortField("creationDate");   // sort by when items or users were first created
ajs.setSortField("lastModDate");    // sort by when items or users were first modified
ajs.setSortField("viewCount");      // sort by views (item search only)
ajs.setSortField("score");          // sort by relevance
ajs.setSortField("ratingAverage");  // sort by item's average rating 
ajs.setSortField("name");           // sort by name field (item search only)
ajs.setSortField("username");       // sort by username (user search only)
ajs.setSortField("email");          // sort by email (user search only)
ajs.setSortField("size_l");         // sort by file size -- file store only, Unify v4.8+
ajs.setSortField("sort_creatorFamilyName_s");       // sort by creator family name, item search only; since Unify 4.6.2
ajs.setSortField("sort_creatorFullName_s");         // sort by creator full name, item search only; since Unify 4.6.2
ajs.setSortField("sort_creatorGivenName_s");        // sort by creator given name, item search only; since Unify 4.6.2
ajs.setSortField("sort_creatorUserName_s");         // sort by creator user name, item search only; since Unify 4.6.2
ajs.setSortField("sort_lastModifierFamilyName_s");  // sort by last modifier family name, item search only; since Unify 4.6.2
ajs.setSortField("sort_lastModifierFullName_s");    // sort by last modifier full name, item search only; since Unify 4.6.2
ajs.setSortField("sort_lastModifierGivenName_s");   // sort by last modifier given name, item search only; since Unify 4.6.2
ajs.setSortField("sort_lastModifierUserName_s");    // sort by last modifier user name, item search only; since Unify 4.6.2
ajs.setSortField("sort_givenname");     // sort by given name, user search only
ajs.setSortField("sort_familyname");   // sort by family name, user search only
ajs.setSortField("sort_fullname");     // sort by full name, user search only
ajs.setSortField("sort_X");     // replace X with user profile property definition name, user search only

Unify allows the ability to make custom attributes sortable, we can pass these as sort fields to the framework using the following format:

ajs.setSortField("sort_att123");   // sort by attribute 123 alphabetically
ajs.setSortField("sort_att123_l"); // sort by attribute 123 numerically as an integer
ajs.setSortField("sort_att123_d"); // sort by attribute 123 numerically as a double

We can set the sorting locale for our ajax search (it can be different than the site/page locale):

ajs.setSortLocale("is"); //sort using Icelandic locale

[Note]

Note

the default sort field is score


The framework ships with plugins/widgets that can manipulate sorting using more user friendly interaction patterns. VYRE.Plugins.SortPlugin, VYRE.Plugins.SortSelect, VYRE.Plugins.TablerSorter are plugins which manipulate the sort field and sort direction of the search. These plugins will be explained later.

Sort Direction

As well as the ability to specify a sort field to sort by, we can also specify the sort direction.

 ajs.setDescending(true);// results will be sorted descending


[Note]

Note

The default sort direction is ascending


Results Per Page

We can specify how many items we want displayed per page using the framework, the pagination will be rendered automatically based on this value.

ajs.setResultsPerPage(50);// 50 results per page
ajs.setResultsPerPage(-1);//all items will be returned on a single page

The plugin used to make changing the results per page more user friendly is the VYRE.Plugins.CountPlugin.

Advanced Search

This chapter will explain further functionality that can be used when configuring an instance of the search.


Basic Search

To get a basic search input, with search and reset buttons add the following code

At the top

<input type="text" id="ajaxSearchInput"/>
<input type="button" id="ajaxSearchButton" value="Search"/>
<input type="button" id="ajaxResetButton" value="Reset"/>

In the javascript

ajs.registerSubmit("ajaxSearchButton");
ajs.registerReset("ajaxResetButton");
ajs.addPlugin(new VYRE.Plugins.FilterPlugin(new FilterPluginField("ajaxSearchInput", "","text"),true));

Saved Searches

The content and user gateways allow saved searches to be sent as part of the request to filter down result sets. To set the base saved search we use the setSavedSearch() method.

 ajs.setSavedSearch("active:true"); // bring back all active items
 ajs.setSavedSearch("active:true AND att34:1 AND ITEM_LINK_DEF12($current_item_id)");// all items linked through link def 12 with the attribute34 being true.

[Note]

Note

You will need to convert your saved searches to use "AND/OR/NOT" syntax instead of "+ -". Note UPPERCASE not lowercase. Also, must start with active:true to prevent incorrect values being brought back.

Cookie Managment

The framework allows the ability to save the state of a search in a cookie for when the page is next loaded. This includes management of plugin state through MVC architecture. The cookie's information is stored by serialising the state of a search to a string using JSON(Javascript Object Notation) .

 // This turns on the cookie functionality, and sets the key/name for the cookie to be stored
 ajs.setCookieName("ajsSearch");
 
 // Reads a partial state of the stored search. It persists all information which DOES NOT filter the resultset down.
 ajs.setLightweightCookie(true);
 
 //Reads the entire state of the search which includes information that can filter the resultset.
 ajs.setLightweightCookie(false);
 
 // Sets the expiration(in days) of the cookie. The cookie is a session cookie by default.
 ajs.setCookieExpiration(2);
 
 // The actual operation of reading and persisting data from a cookie
 ajs.readCookie();


[Note]

Note

When developing Ajax Search Result pages becareful when using cookies, if you are making many changes to the configuration of a search the changes may not persist immediately if you have cookies enabled.

Registering Taxonomies

The framework can be used in conjuction with taxonomies rendered on the page. It relies on the use of the Search portlet. Using taxonomies with the framework requires a few steps.


  1. Add an Search portlet to the page and configure the taxonomy.
  2. Make sure that the option to perform a search on selecting a node is unchecked as this will reload the page uneccesseryily.
  3. Find out the portlet namespace for the Search portlet you used, this will be in the format of p<portletId>I (e.g. p765I)
  4. ajs.registerTaxonomy("p765I");//Registers the taxonomy located in portlet p765I
  5. To change the connector use ajs.taxonomyController.setConnector('OR');
 VYRE.Utils.clearFormAction("p765I"); //nullifies the form action for the advanced search portlet(p765I) so form submits don't occur.


The state of the taxonomy works with the cookie functionality, however only non lightweight cookies will persist the state of a taxonomy as this filters down the result set.


[Note]

Note

The taxonomies ability to automatically remove categories which bring back 0 results cannot be used in conjuction with the framework as this is a serverside operation requiring a form submittion.

Submit and Reset Buttons

The framework allows the registration of submit and reset buttons, this works by passing the id of the button to a method in the framework.

 <input type="button" value="Search" id="ajaxSearchButton"/>
 
 <input type="button" value="Reset" id="ajaxResetButton"/>
 ajs.registerSubmit("ajaxSearchButton");
 ajs.registerReset("ajaxResetButton");


[Note]

Note

The html elements need to be rendered before the javascript is registered, and you are able to register as many buttons as you like to submit or reset.

Lucene Attributes

The framework takes advantage of the key:value nature of lucene by storing attribute objects in a collection which then are appended to the saved search inorder to filter results.

E.g. if we had a base saved search of "active:true" and we wanted filter the results further to the following "active:true and creator:$current_user" we would do the following

 ajs.setSavedSearch("active:true");// sets the base saved search
 ajs.attributes.set(new VYRE.Attribute("creator","$current_user"));//sets the attribute for the creator

By having attributes in a collection we have much better control on the key value pairings meaning we change the value of an attribute without some long winded string manipulation. The framework makes extensive use of the collection class VYRE.Utils.ArrayList which contains critical methods that the default Array implementation doesn't.


  1. add(someObject); //adds object to collection
  2. get(index); //gets object at specified index
  3. set(someObject); // sets the object(if it exists, using implemented equals method) otherwise it adds it
  4. size(); //returns size of the collection
  5. remove(object); // removes the object(relies on implement equals method)
  6. contains(object) // return whether the object exists(relies on implemented equals method)
  7. each(function (item,index){}); //invokes a specified function over the entire collection passing in the object and index.
  8. fromArray() and toArray() ..allows the collection to be set and get to an Array object.

To remove a free text search use set with no value in the pair

ajs.attributes.set(new VYRE.Attribute("",""));

Pagination

The framework should generate the pagination if the correct containers are present and if the count value is added to the xsl. There are some properties of the pagination that can be changed to tweak the presentation of the pagination. This is so the framework can cater for varying clients needs.


Range

This attribute can be changed to specify how broad the pagination is, the bigger the number the more page links will show.

 ajs.paginationElements.range = 3;// 1-5 is most common ranges, defaulted = 3;


Rendering Criteria

The boolean property "alwaysRender" is used when you want to control if the pagination should render if there is only 1 page or there are no results.

 ajs.paginationElements.alwaysRender = false; // defaulted to true

Copy Text

The framework alows the ability to change the text for the divider, next and previous links. There is also the ability to use images rather than text, this was introduced for certain clients.

 //text examples
 ajs.paginationElements.nextLink = "Next";
 ajs.paginationElements.divider = "----";
 ajs.paginationElements.previousLink = "Previous";
 
 //Image examples
 ajs.paginationElements.nextLink = VYRE.Utils.makeImage("/other_files/general/pag-next.gif");
 ajs.paginationElements.divider = VYRE.Utils.makeImage("/other_files/general/divider.gif");
 ajs.paginationElements.previousLink = VYRE.Utils.makeImage("/other_files/general/pag-previous.gif");

Callback functions

Since each ajax request takes an unknown amount of time to be performed, there needs to be a mechanism to trigger callback functions so that frontend programmers can invoke code after the response has been recieved rather than during. There is a VYRE.Utils.ArrayList collection which stores these functions.

//callback using a predefined function
function hello() {
    alert("hello");
}
 
ajs.callBackFunctions.add(hello); // add call back using function reference, note not called using hello(), but just hello


// add call back using anonymous function
ajs.callBackFunctions.add(function () {
   alert("Anonymous hello");
});

Getting AJAX Search result as a JSON Object

In order to get the results of an AJAX Search as a JSON Object for further manipulation via Javascript or jQuery we can use a callback function.

// Consider AjaxSearch Constructor declared previously
 
var object; // Our JSON object
 
// Callback function
result = function (data) { 
    object = JSON.parse(data); // content of data can be parsed into JSON
};
 
ajs.callBackFunctions.add(result);
ajs.search();
 
// Now the JSON object contains the result of our query

Container Namespace

The framework has a feature which makes it easier to help manage containers when you have several instances of the search framework on a single page. This functionality now means you dont need to come up with different ids for containers in different instances of the search. Instead what used to be Ids are now treated as class names, and the only thing that needs to be changed is the containing Id.

 <div id="containerNamespace1">
 
   <div class="loadingDiv" valign="middle" class="hide"></div>
   <div class="sortBar"></div>
   <div class="paginationContainer ajaxPagination"></div>
   <div class="searchResults"></div>
   <div class="paginationContainer2 ajaxPagination"></div>
 
 </div>
 
 
 <!-- in the xsl -->
 <input type="hidden" value="{search-results/size}" class="countValue"/>
 ajs.setContainerNamespace("containerNamespace1");

notice how the id attribute have now been changed to a class attribute, and the containers are now contained in a single div with a unique id which will be set as the containerNamespace in the search framework. Remember to also modify the xsl to use a class for the countValue hidden input.

Plugins

The framework has a plugin architecture which allows custom widgets/plugins which can manipulate and react to the state of the ajax search instance to be added to the page. The architecture is based on MVC(model-view-controller) and decoupled from the main framework, this is to allow new plugins to be added for varying client needs without changing the sourcecode of the other classes.

Architecture

A plugin is a relatively simple class, requiring only three functions to work:

  • getHTML - this is called once when the plugin is first added to the AjaxSearch. This function can be used to generate and pass back to the AjaxSearch any HTML elements that the plugin needs. The AjaxSearch object is passed to this function.
  • initialise - this is called once the plugin has been successfully added to the AjaxSearch.
  • loadConfig - this is called during the result handling stage of an AJAX search. After a search is returned from the server and the results have been displayed, this method will be called on every plugin.

From 4.6.2 onwards any other optional function is also supported:

  • preSearch - this is called just before a search is requested from the server. It will be called once per search request.

Hello World

The following is a simple plugin designed to give you an idea on how they work.

VYRE.Plugins.HelloworldPlugin = function () {   
    this.ajaxSearch = null;
};
 
VYRE.Plugins.HelloworldPlugin.prototype = {
    getHTML: function(ajaxSearch) {
        console.log("This method is only called once.");
 
        this.ajaxSearch = ajaxSearch; // can keep an internal reference to the ajaxSearch if required.
 
        return null; // this can return a HTML element
    },
 
    initialise: function() {
        console.log("This is called when the plugin is first loaded, but after the call to getHTML");
        console.log("Notice that there are no parameters to this method");
    },
 
    loadConfig : function(config) {
        console.log("Called after every search request is returned from the server");
    },
 
    preSearch : function(config) {
        console.log("Called just before a search is requested from the server");
    }
};

Shipped Plugins

Below are all of the plugins that are shipped with the AJAX Search Framework together with instructions on their uses.

Count Plugin

The count plugin is added so the user can change how many results per page they want. This a visual plugin that gets appended to the sortbar container.

   ajs.addPlugin(new VYRE.Plugins.CountPlugin([5,15,30,45],'Items per page: ',0));

The CountPlugin is added to the frameworks collection of plugins, it will obtain the html from the getHTML() method of the plugin and then append it to the container. The parameters that the plugin needed are;


  • [5,15,30,45] - Array of user specifible counts.
  • 'Items per page:' - label for the plugin
  • 0 - default index for the count, (e.g. 0 = 5 items per page, 2 = 30 items per page)


SortPlugin

The sort plugin is used to allow users to control the sort field and sort direction through a visual widget.

 ajs.addPlugin(new VYRE.Plugins.SortPlugin([false,true,false,true],
                                            ["lastModDate","lastModDate","name","name"],
                                            1));

The sort plugin accepts 3 arguments which are;


  • [false,true,false,true] - Array of sort directions(4)
  • ["lastModDate","lastModDate","name","name"] -Array of sort fields(4)
  • 1 -Index of default selection (index :0-3)

Please note: The resulting "visual" widget will need to have CSS applied to the "up" and "down" div classes in order for controls to be visible.

TablerSorter Plugin

The table sorter plugin allows users to sort by table headers. This plugin needs to be registered as an "invokeLaterPlugin", this is because the plugin needs to attach event handlers to the headers everytime the results have been rendered. All the other plugins attach their event handlers only once during the initial setup stage.

   ajs.addInvokeLaterPlugin(new VYRE.Plugins.TableSorter([new Header(0,"name"),new Header(2,"lastModDate"),new Header(5,"sort_att321")],"ajaxTable"));

We use the addInvokerLaterPlugin() method as this is a different type of plugin. Here are the auguments that the TablerSorter object accept.


  • [new Header(0,"name"),new Header(2,"lastModDate"),new Header(5,"sort_att321")] - Array of headers, which are composed of an header index and the sortField the column is sorted by.
  • "ajaxTable" - this is the id (or class if using containerNamespace) of the table in the xsl.

When this plugin is initialised, all sortable headers are given the className of "sortable", if a header is in its down state the className is "down" and if in an up state the classname is "up". You will need to use css to highlight the different states.

A new feature added recently was the ability to specify the default sort direction of a header. E.g. you might want a header based on creationDate to be sorted descending when its first clicked, you can do this by providing an additional boolean parameter when creating a new Header object.

 new Header(3,"creationDate",true);//when this is header is first clicked the sort direction is descending.

ListPlugin

This plugin allows users to switch the XSL file which is used to render the results on the fly using a visual widget. This is useful for asset pages where it is nice to give the option for either a grid view or a list view.

 ajs.addPlugin(new VYRE.Plugins.ListPlugin([new View("Grid",408),new View("List",497)],1));

The auguments needed for the ListPlugin are.


  • [new View("Grid",408),new View("List",497)] - An Array of View objects which are composed of a label, and xslId.
  • 1 - Index of which which view is selected on initial load.


FilterPlugin

The filter plugin is used for most of the filtering interactions in the framework and manages lucene key:value pairings using the attributes Collection located in the VYRE.AjaxSearch class. This plugins works in a different way to the other plugins, no HTML is returned by this plugin instead form elements on the page and registered as a FilterPluginField which then is binded to a lucene key:value pairng. Usually an advanced search portlet is used to produce the relevant dropdowns as it can retrieve the presentation rules and list the linked items for us.

   ajs.addPlugin(new VYRE.Plugins.FilterPlugin(new FilterPluginField("SEARCH_ATTRIBUTE_19", "att19","select"),true));

The auguments that the FilterPlugin accept are;


  • FilterPluginField - "SEARCH_ATTRIBUTE_19" refers to id of the form element, "att19" is the lucene attribute the plugin is binded too, "select" is the form input type ("text" and "radio" are the others)
  • The additional augument is a boolean which signifies if a search should be invoked on a click or enter key down event.


Below are some additional examples which show uses of attributes, linked items and linked users in an advanced search portlet.

 //filterplugin based on an attribute with an id of 15
 ajs.addPlugin(new VYRE.Plugins.FilterPlugin(new FilterPluginField("SEARCH_ATTRIBUTE_15", "att15","text"),true));
 
 //filterplugin based on item link definition 56
 ajs.addPlugin(new VYRE.Plugins.FilterPlugin(new FilterPluginField("link_56", "ITEM_LINK_DEF56", "select"),true));
 
 //filterplugin based on user link definition 4
 ajs.addPlugin(new VYRE.Plugins.FilterPlugin(new FilterPluginField("ulink_4", "USER_LINK4","select"),true));


[Note]

Note

Remember that when using the advanced search portlet you will need to clear the form action using the VYRE.Utils.clearFormAction("p<portletId>I") method.


Primary Filter

The primary filter is an instance of a filterplugin but the VYRE.AjaxSearch class holds a reference to this so it can expose it to the url parameter functionality. This is usually applied to the general/keyword search so the framework can accept GET strings in the url and directly map it to this particular plugin.

 ajs.setPrimaryFilter(new VYRE.Plugins.FilterPlugin(new FilterPluginField("ajaxSearchInput", "","text"),true));

The example above sets the primary filter for an instance of the search framework. Notice that in the plugin field the lucene attribute is bound to "" which means that this will be a general search which searches the entire item for matches. Now if the url gets appended with the get request of "?primary=test" the keyword test will be bound to this plugin and automatically filled.

SortSelect Plugin

This plugin is used to control the sort field and sort direction, it is used as an alternative the SortPlugin as it allows more sort fields to be displayed in the space via a drop down box.

 ajs.addPlugin(new VYRE.Plugins.SortSelect([new SortableAttribute("name","Name"),new SortableAttribute("creationDate","Creation Date"),new SortableAttribute("lastModDate","Last Modification Date")],true));

The SortSelect plugin takes in the following arguments.


  • Array of SortableAttibutes, which are composed of a sortField and a label.
  • Boolean to indicate whether a search should be invoked upon onchange of the selectbox.


DateRange Plugin

The data range plugin is used to search between 2 date ranges, it works by registering events with the 2 input boxes generated in an Advanced Search portlet with lowerbound and upperbound dates.

 ajs.addPlugin(new VYRE.Plugins.DateRange(new DateRangeField("att20","ITEM_ATT20low_DATE","ITEM_ATT20high_DATE"),true,true/*isUSDate*/));

The DateRange plugin accepts the following arguments.


  • A DateRangeField which consists of the lucene attribute the plugin is binded to, the id of the lower bound input box and the id of the upperbound inputbox.
  • A Boolean to indicate if a search should be invoked when a both dates have been chosen for lowerbound/upperbound input boxes.
  • An optional boolean to indicate that the date is in US format.

Connector Plugin

The connector plugin is used to change the connector (AND/OR) for lucene search based on taxonomy.

 ajs.addPlugin(new VYRE.Plugins.ConnectorPlugin([new Connector("And","AND"), new Connector("Or","OR")],"Connector: ",0));

The auguments whihc the ConnectorPlugin need are.


  • Array of Connector objects which are composed of an operator ("AND"/ "OR") and a label.
  • A Label to be displayed next to the controls for the widget
  • An index of which connector is selected by default.

RecordSearch Plugin

Introduced in 4.6.2, this plugin is used to record searches which take place through an AjaxSearch.

var recordSearchSettings = {
  ignoreFirstSearch : true,
  ignoreEmptyUserQueries : true,
  userQueryFunction : customUserQuery,
  attributeName : ""  
};
 
ajs.addPlugin(new VYRE.Plugins.RecordSearchPlugin(recordSearchSettings));

All of the setting values are optional with sensible defaults used if they are omitted from the settings. The following is a description of the record search settings:

  • ignoreFirstSearch - Whether or not the first search request made through the AjaxSearch should be ignored. You may not wish to record the first search when pre populating the search results when a page is first loaded (by calling ajs.search() for example). The default value is true.
  • ignoreEmptyUserQueries - Whether searches should be recorded when the value for userQuery is empty. If this is set to true, each time a user search through this AJAX search with an empty userQuery, it will not be recorded. Defaults to true.
  • userQueryFunction - This specifies a function that should be used to work out the value of userQuery that will be sent to the server.
  • attributeName - The name of the attribute that should be used for the userQuery. The userQuery is that value that will be stored in the search record (the record of the search in the database) that represents the query that the user entered in order to get the results. This parameter is not required and defaults to empty string. When this is set and userQueryFunction is not set, the value of userQuery will be retrieved from the lucene query that is being used by the search framework. For example, if the framework is passing a query like "active:true name:bob att234:hello" and the value of attributeName is att234, "hello" will be used as the value of userQuery.


This plugin will be run before each search request is sent to the server. If the search that is being run is the same as the previous one (e.g. the current lucene query is the same as the previous one) the search will not be recorded. This will mean that any display changes that do not involve a change in query (changing the sorting, the number of items per page or paginating through results) will not result in a record being stored. Also, if the value of userQuery is empty, the search will not be recorded.

User Search Example

The framework also supports requests to be made to the user gateway. There are however a few differences when using the framework for the user gateway.


VYRE.AjaxSearch Constructor

The object passed to the constructor is slightly different to that of the content gateway examples.

 var ajs = new VYRE.AjaxSearch({
   searchType:'user',
   gatewayId: 1,
   pageId : $page_id,
   xslPath : '/some/path',
   storeIds:null,
   displayItemId:null,
   realmId:'initial',
   contextPath:'$context_path',
   loadLinkedItems : true,
   loadLinkedContentAndMetadata : true
 });

Unify 4.8.0.1 Example

 var ajs = new VYRE.AjaxSearch({
   searchType:'user',
   gatewayName: "all",
   xslPath : '/some/path',
   realmName:'Default',
   globalXmlCfgPath; "/some/path",
 
   pageId : $page_id,
   displayItemId:null,
   contextPath:'$context_path',
 });
searchType
This is set to 'user', so the framework knows to generate references to objects which handle requests to the user gateway.
gatewayId
The gateway id now needs to be an id of a user gateway rather than a content gateway.
gatewayName
The name of a user gateway. Since 4.8.0.1
realmId
The realmId of the user realm you want to search goes here. The default realm has an id of 'initial'
realmName
The realmName of the user realm you want to search goes here. Since 4.8.0.1
XML Loading
The user gateway has less options to load xml than the content gateway, these are 'loadLinkedItems', 'loadUserPicture', 'loadLinkedItemsCreatorPicture', 'loadLinkedItemsModifierPicture' and 'loadLinkedContentAndMetadata'


After this has been setup, most of the other mechanisms in the framework should work.

Content Export Example

The Ajax framework provides the ability to run export configurations since Unify 4.3.1. A button can be added within a search, so the search results can be exported to a file, providing a valid export configuration id. The sort settings of the search will be preserved when exporting to a file.

An example of a page running an ajax search, and providing a button for exporting the results would be as follows:

 <!--The main Search framework-->
 
 <script type="text/javascript" src="/javascript/pub_module/search_jax.js"></script>
 
 <!--JSON utility-->
 <script type="text/javascript" src="/javascript/pub_module/JSONstring.js"></script>  
 
 <!--If you are searching Unify's user realms include this file-->
 <script type="text/javascript" src="/javascript/pub_module/user_jax.js"></script>
 
 <!--If you are searching Unifys data-stores and file-stores include this file-->
 <script type="text/javascript" src="/javascript/pub_module/content_jax.js"></script>
 
<!-- Button to export search results -->
<input class = "portlet-form-button" type ="button" value = "Export" id= "exportButton"/>
 
<div id = "containerNamespace1">
 
 <div id ="loadingDiv" valign="middle" style="display:none"></div>
 <div id = "sortBar"></div>
 <div class="paginationContainer ajaxPagination"></div>
 <div id ="searchResults" class="searchResults"></div>
 <div class="paginationContainer2 ajaxPagination"></div>
 
</div>
 
<input type="text" id="ajaxSearchInput"/>
<input type="button" id="ajaxSearchButton" value="Search"/>
<input type="button" id="ajaxResetButton" value="Reset"/>
 
 <script type="text/javascript">
 
<!-- The AJAX search to run first -->
var ajs = new VYRE.AjaxSearch({
   searchType: 'content',
   gatewayId: 1,
   pageId: $page_id,
   portletId: $portlet_id,         
   xslId: 187,
   storeId: "1",
   displayItemId: null,
   contextPath: '$context_path',
   loadContentAndMetadata : false,  
   loadLinkedItems : false,         
   loadLinkedContent: false,        
   loadLinkedUsers : false,         
   loadLocalizations : false, 
   globalXmlCfgId : 342,         
 });
 
 
ajs.setContainerNamespace("containerNamespace1");
ajs.registerSubmit("ajaxSearchButton");
ajs.registerReset("ajaxResetButton");
ajs.addPlugin(new VYRE.Plugins.FilterPlugin(new FilterPluginField("ajaxSearchInput", "","text"),true));
 
ajs.search();
 
<!-- Button to run export -->
VYRE.Utils.gE("exportButton").onclick =  function() {
    var searchAdapter = ajs.getSearchAdapter();
    searchAdapter.searcher.contentExport("1",searchAdapter.searchQuery); <!-- pass export id '1' and previous search config args so ordering is preserved -->
	 var searchResults = VYRE.Utils.gE("containerNamespace1");
	 if(searchResults.innerHTML !="undefined") {
        VYRE.Utils.Logger.log("Export finished");
        alert("Export Finished");
    }
 
    document.getElementById("loadingDiv").style.display="block";
  }
 
 
 
</script>

4.8 Example

Below is an example of an ajax configuration in 4.8 without the deprecated values and the minimal code required to get working.

 <!--The main Search framework-->
 
 <script type="text/javascript" src="/javascript/pub_module/search_jax.js"></script>
 
 <!--JSON utility-->
 <script type="text/javascript" src="/javascript/pub_module/JSONstring.js"></script>  
 
 <!--If you are searching Unify's user realms include this file-->
 <script type="text/javascript" src="/javascript/pub_module/user_jax.js"></script>
 
 <!--If you are searching Unifys data-stores and file-stores include this file-->
 <script type="text/javascript" src="/javascript/pub_module/content_jax.js"></script>
 
<!-- Button to export search results -->
<input class = "portlet-form-button" type ="button" value = "Export" id= "exportButton"/>
 
<div id = "containerNamespace1">
 
 <div id ="loadingDiv" valign="middle" style="display:none"></div>
 <div id = "sortBar"></div>
 <div class="paginationContainer ajaxPagination"></div>
 <div id ="searchResults" class="searchResults"></div>
 <div class="paginationContainer2 ajaxPagination"></div>
 
</div>
 
<input type="text" id="ajaxSearchInput"/>
<input type="button" id="ajaxSearchButton" value="Search"/>
<input type="button" id="ajaxResetButton" value="Reset"/>
 
 <script type="text/javascript">
 
<!-- The AJAX search to run first -->
var ajs = new VYRE.AjaxSearch({
   searchType: 'content',
   gatewayName: "all",
 
   xslPath: "Item List/projects/eftar_miah/default",
   contentStoreNames: "project_eff", /* replacement for storeId */
   globalXmlCfgPath : "/projects/eftar_miah/default",
 
   displayItemId: null,
   contextPath: '$context_path',
   /* pageId: $page_id,  optional */
   /* portletId: $portlet_id   optional */  
 });
 
 
ajs.setContainerNamespace("containerNamespace1");
ajs.registerSubmit("ajaxSearchButton");
ajs.registerReset("ajaxResetButton");
ajs.addPlugin(new VYRE.Plugins.FilterPlugin(new FilterPluginField("ajaxSearchInput", "","text"),true));
 
ajs.search();
 
<!-- Button to run export -->
VYRE.Utils.gE("exportButton").onclick =  function() {
    var searchAdapter = ajs.getSearchAdapter();
    searchAdapter.searcher.contentExport("1",searchAdapter.searchQuery); <!-- pass export id '1' and previous search config args so ordering is preserved -->
	 var searchResults = VYRE.Utils.gE("containerNamespace1");
	 if(searchResults.innerHTML !="undefined") {
        VYRE.Utils.Logger.log("Export finished");
        alert("Export Finished");
    }
 
    document.getElementById("loadingDiv").style.display="block";
  }
 
 
 
</script>

Debugging

This section will briefly explain how to debug the framework.


Firebug

I would advise anyone building instances of framework to have firebug installed in firefox. When debugging is turned on, plenty of information is logged into firebug which can help alot when things go wrong. The following are provided in the logs


  • Response time - how long a search takes place in MS
  • Container checks, the framework will tell you if you are missing any containers.
  • Some of the settings in the API will log details when they are used, setResultCount() is an example
  • Lucene query, the query which is sent to the server is always logged, this includeds attributes appended to the base saved search. Always check this when you think the savedsearch is incorrect.
  • Taxonomy, taxonomy categories and selection information will be provided in the logging. There are also error logs for when certain Unify methods haven't been overriden properly.

Example Logging output

 [13:03:32] setting sort range startIndex= 5, endIndex= 9, currentPage= 1s32.js (line 1768)
 [13:03:32] Searching....s32.js (line 1768)
 [13:03:32] Taxonomy String: s32.js (line 1768)
 [13:03:32] LuceneQuery = +active:true AND (att295:active)s32.js (line 1768)
 [13:03:33] Ajax Request duration: 546ms
 [13:03:33] recieved results from server...s32.js (line 1768)
 [13:03:33] Tablesort table cannot be found!s32.js (line 1768)
 [13:03:33] Taxonomy String: s32.js (line 1768)
 [13:03:33] Setting Sort Field: lastModDates32.js (line 1768)
 [13:03:33] Setting descending: trues32.js (line 1768)
 [13:03:33] Setting Result Count: 5s32.js (line 1768)
 [13:03:33] Setting xslId: 103s32.js (line 1768)
 [13:03:33] Setting taxonomy connector: ANDs32.js (line 1768)
 [13:03:33] Taxonomy String: s32.js (line 1768)
 [13:03:33] writing Cookie...


Visual Studio Express( IE Debugging)

TODO

Custom Crossbrowser Logging Module

There is currently a prototype for a custom cross browser debugging module, instructions will appear here.

Auto Completion

you could find more information about how to set up an auto suggestion in this page

Personal tools