Version 4, changed by ScottMcmullan. 09/27/2006. Show version history
jot developer tutorials
Some times you want to view a list or a table or a collection of pages based on some filter or "pivot" or "facet". You want to be able to pick from a list and then view pages based on your selection.
For example here on the JDC, we're moving code examples into individual pages to allow them to be tagged, searched, and discovered in different ways:
So how does this work? The basic idea is to create a Jot page that uses an HTML form to allow users to select one or more filter values. You then perform a Jot search based on these filter arguments in the page's query string.
Let's take a look at the ViewExamples page used here on the JDC. (Note: this code requires the use of an HTML form, so we'll need to use XML mode to edit our page.)
This is the standard HTML form that hard-codes a dropdown list of choices for navigating the JDC examples. Note that the form's action points back to my ViewExamples wiki page.
<form action="wiki:ViewExamples" method="GET">
<select name="tag">
<option value="">View examples by tag...</option>
<option value="search">search</option>
<option value="search">table</option>
<option value="search">form</option>
<option value="all">All Tags</option>
</select>
<input type="submit" value="Go" />
</form>
When the user makes a selection and presses the "Go" button, the tag query string parameter is added to our page. So the page's URL ends up looking like:
http://developer.jot.com/WikiHome/ViewExamples?tag=search
I access the query string parameter with the ${req/args/tag} expression and use it to parameterize my search. I use a filter that returns only those pages with the tag specified by req/args/tag:
<jot:search forFormName="DevDocExampleForm" filter="${it/main/tags = req/args/tag}" set="exampleSet" />
With the set of pages from the search in hand, you can display them any way you want. Common methods include a Jot table or looping over the set and displaying some type of list.
Here's code that uses a loop to display the examples and their text in a simple list:
<jot:loop over="exampleSet">
<br /><br />
<h3><a href="${it/name}">${it/DevDocExampleForm/title}</a></h3>
by <a href="wiki:/${it/createUser}-profile" style="color: #999">${it/createUser}</a><br />
<jot:include node="${it}" />
<br />
</jot:loop>
Here's the full source of ViewExamples. Remember this requires working in XML editing mode. There's a bunch of other stuff in here to make the page a bit prettier. You can play with it by going to the ViewExamples page.
Of particular interest is the way I populate the select box from a search result instead of hard-coding the list. First I search for all example tags using <jot:search forFormName="DevDocExampleForm" collect="it/main/tags" set="exampleTags" />, then construct the option list by looping over exampleTags:
<jot:loop over="exampleTags">
<option value="${it}">${it}</option>
</jot:loop>
Snapshot of ViewExamples
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:jot="http://www.foopee.com/ns/s3/srvtmpl/">
<br />
<jot:search forFormName="DevDocExampleForm" collect="it/main/tags" set="exampleTags" />
<form action="wiki:ViewExamples" method="GET">
<select name="tag">
<option value="">View examples by tag...</option>
<jot:loop over="exampleTags">
<option value="${it}">${it}</option>
</jot:loop>
<option value="all">All Tags</option>
</select>
<input type="submit" value="Go" />
</form>
<br />
<jot:if test="${util:isDefined(req/args/tag)}">
<jot:then>
<jot:if test="${req/args/tag = 'all'}">
<jot:then>
<h2>All Examples</h2>
<jot:search forFormName="DevDocExampleForm" set="exampleSet" />
</jot:then>
<jot:else>
<h2>All Examples Tagged <i>${req/args/tag}</i></h2>
<jot:search forFormName="DevDocExampleForm" filter="${it/main/tags = req/args/tag}" set="exampleSet" />
</jot:else>
</jot:if>
</jot:then>
<jot:else>
<jot:search forFormName="DevDocExampleForm" filter="contains(it/path, page/name)" set="exampleSet" />
</jot:else>
</jot:if>
<jot:loop over="exampleSet">
<ol>
<li><a href="#${it/name}">${it/DevDocExampleForm/title}</a>
<span style="color: #999; font-size: smaller;">by
<a href="wiki:/${it/createUser}-profile" style="color: #999">${it/createUser}</a></span></li>
</ol>
</jot:loop>
<jot:loop over="exampleSet">
<br /><br />
<h3><a name="${it/name}"><a href="${it/name}">${it/DevDocExampleForm/title}</a></a></h3>
<span style="color: #999; font-size: smaller;">by
<a href="wiki:/${it/createUser}-profile" style="color: #999">${it/createUser}</a></span><br />
<jot:include node="${it}" />
<br />
</jot:loop>
<br /><br />
<jot:include node="PostNewExampleForm" />
</html>
To filter on two or more properties, we'll simply extend the technique used above. This time we'll define our search filters in Server-side Javascript, which allows us to create just about any filter logic we can dream up. (In this case, I've kept it simple.)
Here's the complete source code for the SearchTextAndTags example. This code searches using two filters, in this case looking for specific strings in the main/text property AND specific tags in the main/tags property. These are the properties I've chosen for this example -- you can search for any properties you want.
Snapshot of SearchTextAndTags
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:jot="http://www.foopee.com/ns/s3/srvtmpl/">
<br /><h3>Search for pages with specific content and tags</h3>
<form action="wiki:${page/name}" method="GET">
Main text contains: <input name="mainTextValue" />
and tags contain:
<select name="tagValue">
<option value="" />
<option value="search">search</option>
<option value="filter">filter</option>
<option value="table">table</option>
</select>
<input type="submit" value="Search" />
</form>
<jot:if test="${util:isDefined(req/args/mainTextValue) and util:isDefined(req/args/tagValue)}">
<jot:then>
<hr />
<jot:script>
<![CDATA[
//custom search filter, which looks at a page's main/tags stringList property
function filterByTag(pg, tag) {
if (pg && typeof(pg.main) != "undefined" && typeof(pg.main.tags) != "undefined")
return pg.main.tags.toString().indexOf(tag) >= 0;
}
//custom search filter, which searches a page's main/text wiki property
function filterByMainTextContent(pg, str) {
if (pg && typeof(pg.main) != "undefined" && typeof(pg.main.text) != "undefined")
return jot.lib.util.isTextMatch(str, pg);
}
]]>
</jot:script>
<h4>Pages that contain the string "<i>${req/args/mainTextValue}</i>" that are
also tagged <i>${req/args/tagValue}</i>:</h4>
<jot:search forAll="1"
filter="${filterByTag(it, req/args/tagValue) and filterByMainTextContent(it, req/args/mainTextValue)}"
limit="9999"
set="resultSet" />
<jot:table contents="resultSet" />
</jot:then>
</jot:if>
</html>