Geolocations via Content Manager

Before I go through the trouble of writing more code, I should take a look at what's available.  Hopefully by reviewing each component I can make a list of features missing.  Then I can decide how best to cobble together my final solution.


Accessing Facilities via the Thick Client

When performing a search it is easy to specify that the results include the GPS location in both the view pane and the list pane.  Making the fields visible lets me peruse the data and verify I like the results.  There's no way for me to leverage that data here without a mapping interface.

 
2017-09-24_14-44-29.png

I can use the view pane's GPS Location hyperlink to browse to the location via the map connector.

 
2017-09-24_14-49-37.png

But that's it.  Only potential thing I see here is swapping out the static google map connector for one that embeds an iframe showing results nearby.


Viewing Facilities via Web Client

The out-of-the-box configuration of the Web Client does not support a grid style layout for meta-data in the search results pane.  As you select an individual record in the results, the right-hand view pane exposes a link to the location.  

 
2017-09-24_14-38-28.png

To modify the value you'd either get to the registration form via the update button...

 
2017-09-24_20-00-31.png

Or you click the GPS Location option from the Details drop-down button

 
2017-09-24_15-02-52.png
2017-09-24_15-01-35.png

That's it.  Nothing else to see here! :(


View Facilities via WebDrawer

Webdrawer is a no-thrills interface for the exposure of public records.  Using it implies (at least to me) that you don't care who the user is and you'll just be reading data.  That fits for my scenario, so let's see what's available.

 
2017-09-24_20-06-32.png

Entering "**" into the quick search box and pressing enter should result in all facility boxes being returned (I have nothing else in the dataset).  The search results page shows my boxes, but nothing useful to mapping.  

 
2017-09-24_20-07-44.png

Clicking a facility box yields no mapping fields or data either.  I tried expanding and collapsing all of the regions but no dice.

 
2017-09-24_20-09-32.png

 A quick check of the Webdrawer installation manual and the HPE support site turns up no hits for various relevant keywords. So I visited the ServiceAPI's Property and Field Definition page and see that "RecordGpsLocation" is the property to include in route details.  I add it to both the routes for the search results (WDRecordList) and record details (WDRecordDetails) templates.

 
Note that this is the webdrawer configuration file of a remote server

Note that this is the webdrawer configuration file of a remote server

Modifying the configuration file should result in an automatic reload of the IIS application.  A refresh of my search results page gives me the result shown.

 
2017-09-24_20-27-56.png

A refresh of my record details page does not result in seeing the property.  That's because I added it to the route (which funnels the data in the template), but I did not include it in any of the custom property sets used to group items into the accordion views.  Adding the property to the custom record identification property set should solve the issue.

 
2017-09-24_20-30-00.png

Refreshing the page gave me a quick laugh.  I wish the GPS location was a hyperlink!

 
2017-09-24_20-33-03.png

I'm sure there's a better way to handle this, but I found it easiest to go into the propertyRow partial template and wrap the property value output in a condition.  If the value starts with "https://www.google.com/maps" then replace the output with a valid link.  Otherwise use the normal condition.  Definitely not an ideal solution.

 
2017-09-24_20-43-04.png

Now a reload of the page gives me a usable link.  

 
2017-09-24_20-49-41.png

What's missing?

I have no way, out-of-the-box, to mark search results within the extent of one map.  So re-creating my goal is not possible without more code.  That's ok though.  I've got this! :)

Creating the Word List for Webdrawer

In my previous post I showed what a "Word Explorer" could look like within Webdrawer.  It took about an hour and a half to create, but I'll save you that time and explain it here in detail.  If you do end up using this concept please let me know!  

Outline of required changes:

  1. Add new route in the configuration file
  2. Create the WDWordList template
  3. Update the Webdrawer Layout
  4. Update the search results page

It's really that simple! :)

First things first, make sure you're using a non-production instance of Webdrawer and that it's fully functional.  I did all of this within a brand new instance (so there's no chance of messing up something I might need later).  That also means I have very little in terms of content, but that doesn't matter to me.


Add new route in configuration file

Navigate to the installation path of Webdrawer and edit the hptrim.config file in the root.

2017-09-13_8-28-07.png

Within the configuration file, locate and duplicate the existing WDRecordList route.  Then update the new route so that it has a name of "Words", uses the template "WDWordList", includes only the RecordTitle & RecordNotes properties, and has a pageSize of 100,000.  These changes means a new "/Words" path is available to users, which will expose the Title & Notes of up to 100,000 records in a given record search.

2017-09-13_8-28-07.png

Save your changes and you're done with this step.


Create the WDWordList template

Navigate into the Views sub-folder and create a new file named "WDWordList.cshtml".  This new file will generate the Word List to be displayed to the right of the search results.  We're going to include it within an iframe on the search results page.  

Here is the content of my WDWordList file:

@using HP.HPTRIM.Service
@using Resources;
@using HP.HPTRIM.Web.Configuration;
@using HP.HPTRIM.ServiceModel;
@using System.Linq;
@using System.Collections.Generic;
@inherits TrimViewPage<HP.HPTRIM.ServiceModel.RecordsResponse>
 
 
@if (Model != null && Model.Results != null && Model.Results.Count > 0)
{
	var wordCounts = new Dictionary<string, long>();
	foreach (TrimObject record in Model.Results)
	{
		Record docRecord = record as Record;
		foreach ( string word in docRecord.Title.Value.Split(' ').ToList() ) 
		{
			if ( word.Length > 1 ) {
			if ( wordCounts.ContainsKey(word) ) {
				wordCounts[word]++;
			} else {
				wordCounts.Add(word, 1);
			}
			}
		}
	}
	
	<script language="JavaScript">
	<!--
	function getParameterByName(name, url) {
		if (!url) url = window.top.location.href;
		name = name.replace(/[\[\]]/g, "\\$&");
		var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
		if (!results) return null;
		if (!results[2]) return '';
		return decodeURIComponent(results[2].replace(/\+/g, " "));
	}
	function ExploreWord(word){
		var searchQuery = getParameterByName("q", window.top.location.href);
		var newUrl = window.top.location.href.replace(searchQuery, "(" + searchQuery + ") AND title:" + word);
		window.top.location.href = newUrl;
	}
	//-->
	</script>
	<table align=center>
	<tr>
		<th>Word</th>
		<th>Count</th>
	</tr>
	
	@{
		var ordered = wordCounts.OrderByDescending(x=>x.Value);
		foreach ( var item in ordered ) {
			<tr>
				<td><a href="javascript:ExploreWord('@item.Key')">@item.Key</a></td>
				<td>@item.Value</td>
			</tr>
		}
	}
	
	</table>
}

Update the Webdrawer Layout

In the "Views\Shared" folder there is a file named "_Layout.cshtml".  This file defines the page layout/structure to be used by all files within Webdrawer.  The problem we have is that the WordList we're going to display is in an iframe and will show the banner & menus, which we don't want.  So the task here is to hide the banner & menus, but only for this new page.  

I accomplished this by placing an if statement around the section of the file that outputs the page banner and menu.  The condition being checked is where I've passed "nb=true" (no banner=true) in the query string of the page.  Later when we embed the word list into the search results page, we'll make sure we're passing this in the query string.

    <body class="@(hideMenu() ? "no-image" : null)">
      	@if ( HttpContext.Current.Request.QueryString["nb"] == null )
		{
			<div id="maincontainer">
			
					<div id="topsection">
						<div class="blue-line">&nbsp;</div>
						<div class="innertube">
							<img id="banner-img-large" src="~/images/top-banner-logo.png" />
							<img id="banner-img-small" src="~/images/top-banner-logo-title-SM.png" />
						</div>
						@if (showLogout() || WebDrawerConfiguration.Instance.UISettings.ShowUserLink)
						{
							<div id="logout-btn" class="dropdown pull-right">
								<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">@this.TrimHelper.CurrentUser.FormattedName <span class="caret"></span></a>
								<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
									@if (showLogout())
									{
										<li>
											<a href="~/auth/adlogout">Logout</a>
										</li>
									}
									<li>
										<a href="~/Location/Me">Profile</a>
									</li>
								</ul>
							</div>
						}
 
					</div>
				
				<div id="contentwrapper" class="@(hideMenu() ? "no-menu" : null)">
					<div id="contentcolumn" class="@(hideMenu() ? "no-menu" : null)">@RenderBody()</div>
				</div>
			</div>
		} else {
			RenderBody();
		}

In the code above, I located the body tag and then wrapped the contents with an IF statement.  I placed the RenderBody method in the else portion of the statement, and just left everything else in the if portion.


Update the search results page

Modify the resultsList.cshtml file in the "Views\Shared" directory, and locate the table element.  Here we're going to basically do the same thing as in the layout file: wrap the existing content.  Though here I wrapped it with a table, partitioning the content into one column and placing an iframe into the second column.  The URL of that iframe will be the word list file created in the previous steps.  

The code just for the right-column is as follows:

	<td width="10%" valign=top>
	<h3>Search Explorer</h3>
	<div>All the words below exist in the title or notes of your search results.  Click on one word to explore results which contain that word.
	<br><br>
	<script language="JavaScript">
	<!--
	function autoResize(id){
		var newheight;
		var newwidth;
 
		if(document.getElementById){
			newheight=document.getElementById(id).contentWindow.document .body.scrollHeight;
			newwidth=document.getElementById(id).contentWindow.document .body.scrollWidth;
		}
 
		document.getElementById(id).height= (newheight) + "px";
		document.getElementById(id).width= (newwidth) + "px";
	}
	//-->
	</script>
	<iframe id='wordFrame'  src="~/Words?nb=true&q=@HttpContext.Current.Request["q"]" Style="border:0"  onLoad="autoResize('wordFrame');"  />
</td>

Source Files

The entire contents of the changes described above can be downloaded here.  The referenced zip contains only the four files modified, but keep in mind they are for my quick test environment.  You'd need to modify the configuration file to reference your workgroup server, paths, and dataset ID.  Otherwise you can drop them directly into a Webdrawer instance and see the functionality for yourself.

Adding a Word Explorer to Webdrawer

I've always wanted to see the words related to a search I've performed.  I know many others like that concept as well, especially when they aren't quite sure what they need, are conducting a legal hold search, or otherwise are just curious about their results.  Without any real "requirements", I set out to create something new for webdrawer.... feedback is welcome!

First, notice my search results page now has a search explorer pane displayed to the right:

2017-09-12_16-07-05.png

Clicking one of those words filters out all records except those containing the clicked word.

2017-09-12_16-07-05.png

This feature is both easy to use and easy to add to your Webdrawer.  I didn't bother really building out this functionality the way I'd truly like it to exist, but it highlights the flexibility of Webdrawer itself.  Ideally the search explorer pane would allow the user to narrow to a specific word (like it does now), exclude records using that word, and explore words in custom properties.  All of that is easily possible with the latest design of Webdrawer.