Following our
previous post, we will now see a bit of the code that will allow us to retrieve the information we need to display the history of the item (Page Item) as well as retrieving all datasource items from the presentation renderings.
The first thing is that on the speak application running on the content tab, we need to retrieve the current item: ID, Version and Language so we can pass it on to a Service to retrieve the current item and its history. We want to pass on the version and language information so the content of the tab will be different when the user is changing the version and Language as per:
Well, your SPEAK app is mostly knockout JS based and all your actions to get your Data from will be located on the JS. This is where you will call the Webservice using Ajax Call and retrieve the json object with all your history information. So the easiest way will be to pass on the ID, Version, Language to the Controller call. Those parameters can easily get retrieved form the Query String Parameters using the following JS method:
GetQueryStringParameter: function (name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
You can then call your webservice using something similar to:
GetPageHistory: function (app) {
jQuery.ajax({
type: "GET",
dataType: "json",
url: "/OPageHistory/OPageHistory/GetCurrentItem?id=" + this.GetQueryStringParameter("id") + "&database=" + this.GetQueryStringParameter("database") + "&language=" + this.GetQueryStringParameter("language") + "&version=" + this.GetQueryStringParameter("version"),
cache: false,
success: function (data) {
app.set("pagehistory", data);
},
error: function () {
console.log("There was an error in GetPageHistory() function!");
}
});
}
Obviously you may want to retrieve this data when building the model. so the above code will go into the Model Initialisation.
Now this will call the Controller to retrieve the json data and then bind it to the pagehistory. So what we now need to do is to make sure our service is up and running, accessible and return the correct jSon. In this exemple, I wanted to try MVC Area and define the service there. we could do a normal Sitecore WebAPI service but as this code is more a PoC I wanted to go with the Area...
To declare the area, I will be using a pipeline action:
During the pipeline action what you want to do is to check for the routes and if the route for the area does not exist then we will need to add it to the routes list:
List list = Enumerable.ToList(Enumerable.Where((IEnumerable)RouteTable.Routes, (Func)(route =>
{
Route route1 = route as Route;
if (route1 != null && route1.Defaults != null && route1.Defaults.ContainsKey("area"))
return string.Equals(route1.Defaults["area"].ToString(), "OPageHistory", StringComparison.Ordinal);
return false;
})));
if (!Enumerable.Any((IEnumerable)list))
{
new OPageHistoryAreaRegistration().RegisterArea(new AreaRegistrationContext("OPageHistory", RouteTable.Routes));
}
else
{
foreach (Route route in list)
route.DataTokens["UseNamespaceFallback"] = (object)true;
}
During the Area registration we will just add the following route:
context.MapRoute(
"OPageHistory_default",
"OPageHistory/{controller}/{action}/{id}",
(object)new { area = "OPageHistory", action = "Index", id = UrlParameter.Optional },
(object)new {
controller = ".*OPageHistory"
}
);
Now in order to be able to test and access some code you will need to create a controller: OPageHistory with a GetCurrentItem method so the call to /OPageHistory/OPageHistory/GetCurrentItem will resolve...
So lets create something like:
public class OPageHistoryController : System.Web.Mvc.Controller
{
///
/// get the full item history information including the renderings datasources
///
///
///
///
///
///
public ActionResult GetCurrentItem(string id, string database, string language, string version)
{
return Json("Hello world", JsonRequestBehavior.AllowGet);
}
}
If all is working fine, you should now be able to call controller /OPageHistory/OPageHistory/GetCurrentItem
Now our controller is accessible, we just need to look at the different code to retrieve:
- Datasource information: We already saw something like that in a previous blog post that you can review here: http://sitecorepromenade.blogspot.com.au/2015/08/loop-through-renderings-in-presentation.html. This will go through the presentation details and retrieve the renderings. This will then retrieve the datasource associated with the rendering from the RenderingReference.Settings.Datasource... You can also check the code in bitbucket
- Item History. The item history is in 2 parts: you first need to retrieve the item versions. Once you have the workflow enable, everytime you update the item, sitecore will create a new version. so the item can have multiple versions. Then each version will go through different states: Draft > Awaiting for Approval > Approved...
An easy way to retrieve the versions of the item is to use the following code. This will return an item array:
var allOlderVersions = item.Versions.GetOlderVersions();
You can then loop through the list of items to get the workflow history. The workflow history (WorkflowEvents) can be retrieved using the workflow provider as per the following
var workflowProvider = (item.Database.WorkflowProvider as Sitecore.Workflows.Simple.WorkflowProvider);
if (workflowProvider == null)
return;
if (workflowProvider.HistoryStore == null)
return;
var workflowEvents = workflowProvider.HistoryStore.GetHistory(item);
foreach (var wEvent in workflowEvents)
{
var vHistory = new VersionHistory(wEvent, item.Database);
if (vHistory != null)
ItemVersionHistory.Add(vHistory);
}
Combining all, you can easily retrieve all the history for not only the page item but go through the presentation and retrieve the history of each item set as rendering datasources. On the module code in bitbucket, I am also looping through the children of the item from the datasource. The reason behind is that some of the datasource items use their children items. For instance to render an accordion component, I usually set an item as datasource (Accordion Panel) then each of its children will be a section of the accordion...
On the next part, I just wanted to do a quick parenthese to show a quick way of doing IoC using Sitecore...