Implementing "Most Recently Used" (MRU) in web sites
Internet Explorer 9 (IE 9) introduced the ability to "Pin" a web site to the taskbar. With just a few images, meta tags, JavaScript, and JQuery, web content developers can implement the equivalent of a "Most Recently Used" (MRU) list of pages to their web sites. In so doing, users who frequently return to the same page can have a dynamic jump list to save efforts in navigation.
This blog post will teach you how to easily pin your site to the task bar, and to enable dynamic jump lists to enable MRU functionality. As there are related concepts of pinning via meta tags, I'm including a couple bonus features, which will be explained along the way as optional. The main features of this article are in yellow highlight below, and the bonus features are not highlighted.
- Pin to task bar.
- Pin static jump list to task bar.
- Pin dynamic jump list (MRU) of task bar.
- Pin to Windows start screen.
INCLUDED IN THIS ARTICLE:
- User Benefits: How and why?
- MRU Methods
- Developer: Give me the code!
- Developer: Rework to support user friendly lists
- Special Considerations
- References
- Conclusion
USER BENEFITS: HOW AND WHY
Users want to have an easy way to return to their favorite site (much like CTRL-D works to save a favorite page), yet they visit the same page multiple times (much like storing history). If you imagine a shopping experience, a user might have found 5 items but not added them to their shopping cart. The next day, instead of searching the history for the site, they might simply find the item bookmarked to the actual page!
- Pinning to the task bar will give the user the ability to quickly reference the site from the task bar. The code provided in this article will enable users with the ability to see a static list of pages (such as help) and a dynamic list of pages (such as MRU pages).
- Pinning to the Windows start screen will give the user the ability to find the site simply by searching for it as an application (shortcut, Windows-Q) or as a tile on the windows start screen.
MRU METHODS
There are varying methods of pinning to the task bar and implementing MRU functionality, below is high level approach for three methods. The first method will get you quickly up to speed with working code and understand the concepts. The second method will be the most useful one, as this provides a friendly name to pin the pages to. The third method below possibly has limited value, despite ability to save queries, because the jump list functionality might best be used for specific results, not a table of results.
The biggest challenge to all of the methods below is to come up with a user friendly means to anchor the text of the MRU link to something that is meaningful to them.
NAVIGATE BY KEY OF QUERY STRING PARAMETER
The first method in this blog is based on navigating through pinned jump lists whereby the friendly name for the jump list is derived from a query string parameter. This should be a unique key value to differentiate from other pages. For example, in case a book were pinned, the query string parameter might use the ISBN number for a key.
NAVIGATE BY ATTRIBUTE OF A PAGE
The next method in this blog will have the jump list friendly name display a key value that is embedded in the page. Using the example of a book again, we might realize that few people memorize ISBN numbers, so we instead want to display the name of the book. This name is part of the text within the document, and will be extracted from the page by Element ID.
NAVIGATE BY POST
The final method discussed is not being presented with code for this blog. It realizes that some people may want to refer back to common searches that they perform. In this case, you will want to enable searching by post and by query string, as the jump list is based on query string. This will get the parameters during the post, and the web site author will have to use some imagination to find a friendly name to display in the jump list. I might include code for this in a later blog, but before writing the code, take a moment to evaluate alternatives. It might best be achieved by providing a static jump list to the search page, and have the search page itself offer links to recent searches. As there is a finite number of items in a jump list, the developer will want to maximize use of the entries for the best user experience. It would be easy to clutter the jump list with search history that could be useless if the user does not know what the searches represent, as seen by the title.
DEVELOPER: GIVE ME THE CODE!
The set of code below is an example of how to pin to the taskbar, as well as pin to the Windows 8 start screen tile. Although the purpose of this blog is to pin to the taskbar, with just a few extra lines of code, you can have a nice Start Screen Tile.
To understand the code, you should follow along this article according to the first version as the MRU is associated to the query string, and then the refactored code as the MRU is associated to the textual value of an element in the page. By following along, it is hoped to quickly teach the basics of pinning. Attached to this article is all the demo code in a VSTS solution, as many will learn faster by just taking the code directly from a working project.
META TAGS AND XML
The meta tags below apply to the home page, or the page that is used to pin the site. I am including additional tags for pinning to the Start Screen Tile for IE 9/10 versus IE 11. The XML file could alternatively be implemented as meta tags, but the choice of an external file is due to the fact that it is cached static content.
Site home page, to be pinned. This is within the header section.
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="msapplication-config" content="/BrowserConfig.xml" />
<meta name="application-name" content="My Application Pin Demo" />
<meta name="msapplication-tooltip" content="MyApplication Web Pages" />
<meta name="msapplication-starturl" content="/Home.aspx" />
<meta content="name=Search for Exams;
action-uri=/ExamSearch.aspx;
icon-uri=/Static/Images/MyApplication-SiteIcon.ico;
window-type=self"
name="msapplication-task" />
<meta name="msapplication-TileImage" content="/Static/Images/MyApplication-Square.png" />
browserconfig.xml
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square70x70logo src="https://blogs.msdn.com/Static/Images/MyApplication-Tiny$.png"/>
<square150x150logo src="https://blogs.msdn.com/Static/Images/MyApplication-Square$.png"/>
<wide310x150logo src="https://blogs.msdn.com/Static/Images/MyApplication-Wide$.png"/>
<square310x310logo src="https://blogs.msdn.com/Static/Images/MyApplication-Large$.png"/>
<TileColor>#ffc533</TileColor>
</tile>
</msapplication>
</browserconfig>
JAVASCRIPT
The include JavaScript is intended to be a simple method that is in an external file called "MyApplicationJSLibrary.js". There are some parameters that are coded internal to the function which you could expose if it were necessary to be configurable. For example, the WindowType attribute given below as "Self" could be "tab" or "window", or a parameter so that it could vary by page (see references section for link to documentation of this method). In this example, I am simplifying it so that only the minimum parameters need to be sent.
If you were to include this functionality for all pages, the jump list might be less predictable to the user, as there is a limited number of links by default. Notice that application specific logic is in the JavaScript, to represent the ExamId as well as other application specific text. This is generally a bad practice, if one were making a reusable library function to share with the developer community. However, we are assuming that in your web site, you are implementing "Most Recently Used" functionality for a limited number of pages, possibly even just one page in the entire web site.
// FILENAME: MyApplicationJsLibrary.js
function MyApplicationJsLibrary() {
/// <summary>MyApplicationJsLibrary is methods for pinning to the taskbar, such as for jump lists.</summary>
this.pinExam = function (jumpListTitle) {
/// <summary>pinExam will add the current Exam.aspx page to the jump list of the task bar, referenced by Exam number.</summary>
/// <param name="jumpListTitle" type="String">Optional. Entry title that is displayed in the Jump List. If not provided, jumpListTitle will be derived from the query string parameter.</param>
try {
if (window.external.msIsSiteMode()) {
var webUrl = window.location.href;
var friendlyTitle;
var webPage = window.external;
if (jumpListTitle == undefined) {
friendlyTitle = "ExamID " + getQuerystringNameValue(webUrl, 'ExamId');
}
else {
friendlyTitle = jumpListTitle;
}
webPage.msSiteModeCreateJumpList("My Recent Exams");
webPage.msSiteModeAddJumpListItem(
friendlyTitle, webUrl, "/Static/Images/MyApplication-SiteIcon.ico", "self");
}
}
catch (ex) {
}
}
//PRIVATE METHODS (helper functions)
function getQuerystringNameValue(webUrl, parameterName) {
/// <summary>Get parameter from a url, which assumes querystring objects are name=value pairs, this will not work if querystring parameter is of format having just parameter name.</summary>
/// <param name="webUrl" type="String">Full Web URL, including querystring.</param>
/// <param name="parameterName" type="String">Querystring parameter name to extract value from.</param>
/// <returns type="String" />
var queryStringArray = webUrl.split("?");
var queryStringParamArray = queryStringArray[1].split("&");
var nameValue = null;
for (var iParamIndex = 0; iParamIndex < queryStringParamArray.length; iParamIndex++) {
queryStringNameValueArray = queryStringParamArray[iParamIndex].split("=");
if (parameterName == queryStringNameValueArray[0]) {
nameValue = queryStringNameValueArray[1];
}
}
return nameValue;
}
}
JQUERY
There are several methods to pin the page to the taskbar using JavaScript. My preference is to use the JavaScript library JQuery. The code attached to this post uses JQuery as referenced from the CDN, which is best for caching instead of publishing your local version of JQuery. The simplest approach would be immediately executing JavaScript code, which is a bad practice that should always be avoided, especially whenever code accesses DOM elements. A better approach is to ensure that the page has loaded, then execute the function. An example of this would be as follows, to embed code example into the header of the web page that you wish to implement MRU for:
<script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.0.3.min.js"></script>
<script src="https://blogs.msdn.com/Static/JS/MyApplicationJsLibrary.js"></script>
<script>
$(document).ready(function () {
var pin = new MyApplicationJsLibrary();
pin.pinExam();
})
</script>
IMAGES
We want images for icons to appear by your browser address bar, history, pinned task bar, and jump lists. We also want images for the Start Screen Tile. The table of image sizes below apply to features as described in this post, as a recommended first draft during development. As you are developing the site, you will be testing images repeatedly, experimenting first with the images at 80% size, then 100%. The .png files could be other image types, but I favor this format for purposes of this post. If the cache seems to interfere with the development, a link to another person's blog about how to clear the cache is provided in the references section at the end of this post. For implementing MRU functionality, all you really need is the .ico file, and to take it further to implement start screen tile, the .png files are necessary.
To see what we are trying to accomplish with the icon images, the screen grabs below which were taken by right clicking the pinned site from the taskbar and by viewing the page in a browser window. The icons should be tested at all locations in the jump list, and all locations in the browser. I have observed times when the image looks great in the taskbar, but blurry in the address bar, or vice versa. It is also possible to use different icon files for different places, as referenced by the meta tags, in case you really need to optimize the images.
As you are developing the site, you may need several iterations of testing the icon images, where the differences may be subtle. If it appears that your changes are either not being accepted, or are too subtle to detect a difference, I use two approaches. The first approach is to have an icon handy that is radically different from the published icon, and temporarily load that in your browser before publishing the new image. This will verify that there was a difference. Sometimes though, you might not be getting refreshed icons loaded, so clear the browser cache (Tools, Delete Browsing History...).
The browser will represent the icon images at the top of the page as seen below.
The secondary (optional) part of this article has to do with images for the Start Screen Tile, which is implemented by the .png files and not the .ico files detailed above. Depending on your system, you might see two possible sizes, Small and Medium, or 4 possible sizes, Small, Medium, Wide, Large. IE11 supports the 4 sizes, as rendered by the browserconfig.xml, and for IE9/10, only 2 sizes are supported, as rendered by the misapplication-TileImage meta tag.
Much like for icon images, the .png images used for the Start Screen Tiles will need to be tested and very likely refactored. In the course of development, the images will need to have their cache cleared, which is not the same cache as in the normal browser. To clear the cache, open the browser from the desktop, and hit the Windows-C keys to display the charms bar for the browser, and choose the Settings as it applies to Internet Explorer. Choose Options and then select the History to select browsing data that you want to delete. In the History taskbar, delete cached images, cookies and browsing history and hit the delete button.
Troubleshooting can be sometimes difficult, but some known issues are mentioned here.
- If your site expects the 4 sizes, yet you do not see all of them, it could be caused by incorrect size of the images. For example, if the large (square310x310logo) image is only 120x120 pixels, it will not be available, and you will see only 3 images.
- If your site expects the 4 sizes, but only see 2 of them, verify that the link to the browserconfig.xml file is correct. The site will still function, but failure to find the browserconfig.xml file will result in implementing the deprecated IE10 meta tag, which supports only two sizes.
Image size table.
META TAG |
PURPOSE / NOTES |
IMAGE1 80% |
IMAGE2 100% |
square70x70logo |
Small Tile, .png file, no background color. |
56 x 56 pixels |
70 x 70 pixels |
square150x150logo |
Medium Tile, .png file, no background color. |
120 x 120 pixels |
150 x 150 pixels |
wide310x150logo |
Wide Tile, .png file, no background color. |
248 x 120 pixels |
310 x 150 pixels |
square310x310logo |
Large Tile, .png file, no background color. |
248 x 248 pixels |
310 x 310 pixels |
Favicon.ico |
Icon. You may generate this using https://www.xiconeditor.com/ using appropriate background color. |
32 x 32 pixel icon |
64 x 64 pixel icon |
Developer: Rework to support user friendly lists
Now that we understand the basic concepts, we might want to enhance the user experience to support MRU list with more friendly names, that are derived from the attributes of a page instead of the query string. Effectively, this can be perceived as the difference between users access by key name instead of key value. To do this, the following code changes would have to be done for the JavaScript function in the .js file, as well as the JQuery code on the page being indexed for MRU.
JavaScript Changes:
The original JavaScript presented above already supports user friendly lists, as the method pinExam effectively acts as an overloaded function by having logic to determine if the parameter jumpListTitle is provided or not. To ensure your code is as lightweight as possible, it is suggested that you remove the condition and implement the parameter or not, depending on your needs. As a reminder, your site is not using this code as a reusable library, rather a specific implementation of MRU list, so please take the code and tweak it according to your specific needs, removing any dead code.
JQuery Changes:
Assuming there is a form element whose ID is txtExamTitle, simply modifying the previously provided call to pinExam as below will implement the necessary change to pin by friendly name. Here, it is important to realize that this code would not work unless the entire DOM was loaded, so that the value for txtExamTitle is derived from the query string. Also, realize that this is behind the scenes logic that happens at time of page load, if it were necessary to pin to a title derived from user entry, the logic would have to be changed.
pin.pinExam($("#txtExamTitle").val());
Sometimes, in ASP.NET, the clientID is not always predictable, so you could remove the client side derivation of the value to server side, as per <%=txtExamTitle.Text%>. Do yourself a favor, and make it predictable without having to resort to server side code embedded in your JavaScript and/or JQuery code. An ASP.NET textbox control could have the attribute ClientIDMode="Static" set to help if this were an issue.
Final View:
After some simple refactoring of the code, and using the friendly name of the title of the exams being displayed, we see the equivalent MRU jump list represented as below. Notice that the text of the titles exceeds the boundaries of the container. This minor issue is mitigated by users being able to hover over the jump list to see the full text of the title.
SPECIAL CONSIDERATIONS
In case of pinning to pages that require active sessions, or redirection after required login, you will have to alter your web page design, or else have pinning of limited value.
REFERENCES
A few useful links that I use for pinning web sites and for authoring this blog post.
Pinned sites for the desktop. MSDN documentation, a must read.
msSiteModeAddJumpListItem method. MSDN documentation on MRU part of the code.
X-Icon Editor. I use this site to convert the source .png files to an .ico file, such as for favicon.ico.
How to Clear Cache in Windows 8 Step by Step. Changing image references while developing sometimes shows old code. Clear the cache if you see unexpected results.
How to: Create JavaScript XML Documentation Comments. Always document your code! Some simple tips to enable IntelliSense.
CONCLUSION
This explains how to implement "Most Recently Used" functionality in your web sites. This blog post is designed to get you quickly up to speed on the basic concepts, with working code. This covers Windows 8 static tiles, and pinning to the task bar using IE 9,10, and 11.
A lot of functionality was covered, including pin to taskbar, static jump lists, dynamic jump lists, most recently used web pages, start screen tiles, and searching for web site locally as if it were a windows store application.