Monday, December 18, 2006
PhotoSynth Technology Preview
Friday, December 15, 2006
Visual Studio 2005 SP1
ASP.NET 2.0 AJAX Extensions RC1
another year passed
so, this post is really about 2 weeks old, but i thought i'd write it anyway.
I found myself thinking about the last couple of years that passed by, and it struck me like a blow to the head: this year has been fantastic!
The last year included:- working for metamatrix // interfolio
- working with sitecore cms (which you all by now know i love)
- went to tech ed in barcelona
- living in stockholm
- drinking beer
- playing music
- stopped smoking
- started going to the gym (if you knew me a year ago you'd be laughing right about now)
- bought an apartment
- bought a car
- started this blog
- found what i was hoping i'd find in a company that develop top-of-the-line solutions
Now, for those of you that don't know me personally, let's just compare this year to some previous:
1 year ago i was..
- living in stockholm
- working for morningstar
- drinking beer
- smoking cigarettes
- playing music
2 years ago i was..
- living in london
- working for morningstar
- drinking beer
- smoking cigarettes
- playing music
3 years ago i was..
- living in london
- working for morningstar
- drinking beer
- smoking cigarettes
- playing music
4 years ago i was..
- living in stockholm
- working for morningstar
- drinking beer
- smoking cigarettes
- playing music
see a repetative pattern evolving here? well, for the first time that pattern is gone, completely (ok, so not -really- completely, i still like my beers, stockholm and my music).
morningstar was great working for, don't get me wrong, and london was a fantastic city to live in. the friends i have there i'll keep for life, without doubt. the thing that separates those years from today is that today i'm loving it. 100% loving it.
and yeah, it's true: i'm going to the gym these days and yeah, it's true: i've stopped smoking (so far anyway)
time sure flies..
i'm -so- looking forward to another great year!
P.
Extending the RSS Module
public static void GetRssUrls() { Item root = Sitecore.Context.Item; System.Text.StringBuilder sb = new System.Text.StringBuilder(); if (root != null) { if (root.Fields["Rss_Feeds"]!=null) { Sitecore.Data.Fields.MultilistField mf = root.Fields["Rss_Feeds"]; if (mf != null) { if (mf.Count > 0) { foreach (Item itm in mf.GetItems()) { sb.AppendLine("<link rel=\"alternate\" type=\"application/rss+xml\" title=\"" + itm.Fields["Title"].Value.ToString() + "\" href=\"" + itm.Paths.GetFriendlyUrl() + "\" />"); } } } Sitecore.Context.Page.Page.Header.Controls.Add(new LiteralControl(sb.ToString())); } } }4) add the following code to your Page_Load event
that's it. now compatible browsers will 'light up' all shiny and stuff when you select a feed that will be available on a page - ain't that great for christmas? finally, wrapping up, Alex de Groot just posted his 1-year-blogging-anniversary post. Congratulations! today is friday - today is afterwork - today is gonna be one more day that i forget to go buy gifts.. but hey, at least it's friday.. take care, P.protected void Page_Load(object sender, EventArgs e) { RssAlternativeRenderer.GetRssUrls(); }
Wednesday, December 13, 2006
10 steps to adding search providers to a sitecore website using OpenSearch specifications
yep, 10 steps to adding search providers to a sitecore website using OpenSearch specifications. ok, so there's a lot of sub-steps and some code, but at least the highlighted parts are only 10 :) here we go!
1) create a new layout called OpenSearch
2) create a new template called OpenSearchSource 2.1) add the following fields to this template 2.1.1) OpenSearchDescription : text 2.1.2) ShortName : text 2.1.3) LongName : text 2.1.4) Description : text 2.1.5) Tags : text 2.1.6) Contact : text 2.1.7) URL_RSS : text 2.1.8) URL_Atom : text 2.1.9) URL_HTTP : text 2.1.10) Attribution : text 2.1.11) Language: text 2.1.12) AdultContent : checkbox 2.1.13) inputEncoding : text 2.1.14) outputEncoding : text 2.1.15) count : text 2.1.16) Icon_Large : text 2.1.17) Icon_Small : text 2.2) set the standard values of the fields accordingly (without the qoutes): 2.2.1) OpenSearchDescription : "http://a9.com/-/spec/opensearch/1.1/" 2.2.2) ShortName : "MyExample" (set your site name or something) 2.2.3) LongName : "Search using MyExample Search" (just a more detailed name) 2.2.4) Description : "Use our own search engine to search our site" 2.2.5) Tags : "example web" 2.2.6) Contact : "peter@interfolio.se" (your email would be better) 2.2.7) URL_RSS : "http://www.interfolio.se/search.aspx?q={searchTerms}&view=rss" (set this to the result querystring of your rss search page (if any) and add the {searchTerms} to the query param, or leave empty) 2.2.8) URL_Atom : "http://www.interfolio.se/search.aspx?q={searchTerms}&view=atom" (set this to the result querystring of your atom search page (if any) and add the {searchTerms} to the query param, or leave empty) 2.2.9) URL_HTTP : "http://www.interfolio.se/search.aspx?q={searchTerms"} (set this to the result querystring of your search page and add the {searchTerms} to the query param) 2.2.10) Attribution : "Copyright 2006, Peter Johansson, All Rights Reserved." 2.2.11) Language: "*" (can be set to a desired language, like sv-SE) 2.2.12) AdultContent : unchecked :) 2.2.13) inputEncoding : "UTF-8" 2.2.14) outputEncoding : "UTF-8" 2.2.15) count : 10 2.2.16) Icon_Large : "http://www.interfolio.se/images/find.png" (or leave blank to show no icon) 2.2.17) Icon_Small : "http://www.interfolio.se/images/find.png" (or leave blank to show no icon) 2.3) create a master for the newly created template
3) add a folder where you'll store your OpenSearch specification items (perhaps /sitecore/content/global/OpenSearch) 3.1) assing the master created in 2.4 to the newly created folder 3.2) assing the layout we created at step 1 to the standard values of our OpenSearchSource template
4) add a dummy specification item that we can change later, i'm naming mine OpenSearchExample, but you can name it what you want.
5) here you can approach it from many angles, but since this is my tutorial we're gonna look at it my way :), 5.1) create a template that your site-specific templates will inherit from (make sure it inherits Standard template), maybe even name it SitewideSettings like i'm doing. 5.2) add a Tree list field to that template, name it OpenSearch_Sources and specify it's source to be your newly created folder at step 3, and finally check the shared checkbox. 5.3) make your site-specific templates inherit from the SitewideSettings template created at step 4.1.
6) edit an item (or create a new one) and select the dummy item we created at step 4 in the OpenSearch_Sources tree list
7) commit a full publish
That's it for sitecore desktop stuff.. for now.. next up, let's change the OpenSearch layout file.
8) Create a new class called OpenSearchPage 8.1) Set the Inherits attribute of the layout to the newly created class, like Inherits="OpenSearch.OpenSearchPage" 8.2) make the new class inherit from the standard Page class 8.3) override the OnLoad event 8.4) create code to output our OpenSearch specification. Instead of doing this the really fancy way i'll just show a really simple way to output it. What should really be done is to make use of an xmltextwriter and an actual xml document to make sure the output is nice all follows standards, but to save time i've simply sent the format straight to the page and made sure the ContentType is text/xml. to make this better, go ahead and change all this, it should be made better so if you use any of this think about that :) anyway, here's really all of the code needed for (the not-so-correct-way-of) returning the output:
public class OpenSearchPage : Page { protected override void OnLoad(EventArgs e) { base.OnLoad(e); if (Sitecore.Context.Item != null) { this.Context.Response.Clear(); this.Context.Response.ContentType = "text/xml"; System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.AppendLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); sb.AppendLine("<OpenSearchDescription xmlns=\"" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["OpenSearchDescription"].Value, "") + "\">"); sb.AppendLine("<ShortName>" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["Shortname"].Value, "") + "</ShortName>"); sb.AppendLine("<Description>" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["Description"].Value, "") + "</Description>"); sb.AppendLine("<Tags>" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["Tags"].Value, "") + "</Tags>"); sb.AppendLine("<Contact>" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["Contact"].Value, "") + "</Contact>"); if (Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["URL_RSS"].Value, "") != "") sb.AppendLine("<Url type=\"application/rss+xml\" template=\"" + Server.HtmlEncode(Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["URL_RSS"].Value)) + "\"/>"); if (Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["URL_Atom"].Value, "") != "") sb.AppendLine("<Url type=\"application/atom+xml\" template=\"" + Server.HtmlEncode(Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["URL_Atom"].Value)) + "\"/>"); if (Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["URL_HTTP"].Value, "") != "") sb.AppendLine("<Url type=\"text/html\" method=\"get\" template=\"" + Server.HtmlEncode(Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["URL_HTTP"].Value)) + "\"/>"); if (Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["LongName"].Value, "") != "") sb.AppendLine("<LongName>" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["LongName"].Value) + "</LongName>"); if (Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["Icon_Large"].Value, "") != "") sb.AppendLine("<Image height=\"64\" width=\"64\" type=\"image/png\">" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["Icon_Large"].Value) + "</Image>"); if (Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["Icon_Small"].Value, "") != "") sb.AppendLine("<Image height=\"16\" width=\"16\" type=\"image/png\">" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["Icon_Small"].Value) + "</Image>"); sb.AppendLine("<Attribution>"); sb.AppendLine(Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["Attribution"].Value, "Copyright, All rights reserved.")); sb.AppendLine("</Attribution>"); sb.AppendLine("<AdultContent>" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["AdultContent"].Value, "false") + "</AdultContent>"); sb.AppendLine("<Language>" + Server.HtmlEncode(Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["language"].Value, "*")) + "</Language>"); sb.AppendLine("<OutputEncoding>" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["outputEncoding"].Value, "UTF-8") + "</OutputEncoding>"); sb.AppendLine("<InputEncoding>" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["inputEncoding"].Value, "UTF-8") + "</InputEncoding>"); sb.AppendLine("</OpenSearchDescription>"); this.Context.Response.Write(sb.ToString()); this.Context.Response.End(); } } }
9) add functionality to add content to the header. all we really need now is a way to tell the browser that there's a search provider available on the site, and here's a little code snippet for that as well
public class OpenSearchRenderer { public static void GetOpenSearchUrls() { Item root = Sitecore.Context.Item; System.Text.StringBuilder sb = new System.Text.StringBuilder(); if (root != null) { if (root.Fields["OpenSearch_Sources"] != null) { Sitecore.Data.Fields.MultilistField mf = root.Fields["OpenSearch_Sources"]; if (mf != null) { if (mf.Count > 0) { foreach (Item itm in mf.GetItems()) { sb.AppendLine("<link title=\"" + itm.Fields["ShortName"].Value.ToString() + "\" rel=\"search\" type=\"application/opensearchdescription+xml\" href=\"http://localhost" + itm.Paths.GetFriendlyUrl() + "\">"); } } } Sitecore.Context.Page.Page.Header.Controls.Add(new LiteralControl(sb.ToString())); } } } }
10) output the header information. to finalize the entire thing and actually get the output to the page, all you have to do is add a call to the GetOpenSearchUrls method on the pages, so for example just add a call to it in the Page_Load event;
protected void Page_Load(object sender, EventArgs e) { OpenSearch.OpenSearchRenderer.GetOpenSearchUrls(); }
now, to wrap it all up you should have a working example of how to add OpenSearch information that will enable your site to 'tell' the browser there's one or more search providers available on your site, it should light up the down arrow to the right of the magnifying glass in the top-right search area part of your IE7 toolbar and if you expand it it should show your newly added search provider. you could also extend the definition of the xml output to include mozilla specific resources (like xmlns:moz="http://www.mozilla.org/2006/browser/search/") and even further extend the functionality in a lot of customized ways since OpenSearch has many ways to extend the specifications and results.
further reading: OpenSearch: http://www.opensearch.org/ OpenSearch Specifications 1.1: http://www.opensearch.org/Specifications/OpenSearch/1.1 Search Provider Extensibility in Internet Explorer 7: http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/external/overview/ie7_opensearch_ext.asp Adding Search providers to IE 7 using OpenSearch 1.1: http://blogs.msdn.com/ie/archive/2005/09/14/466186.aspx
well, i guess that's that. Sorry for the bad formatting, one of these days i'll actually change the design, but right now this will have to do. take care, P.