Examine’s Fluent Search API – Elevator Pitch

by Aaron Powell 31. March 2010 12:08

I realised that with my blog post about Examine it was fairly in-depth and a lot of people were probably bored before they got to the good bits about how easy searching can be.
So I decided that a smaller, more concise post was in order.

What?

The Fluent Search API is a chainable (like jQuery) API for building complex searches for a data source, in this case Umbraco. It doesn’t require you to know any “search language”, it just works via standard .NET style method calls, with intellisense to help guide you along the way.

How?

This is achieved by combining IQuery methods (search methods) with IBooleanOperation methods (And, Or, Not) to produce something cool. For example:

var query = sc
	.NodeName("umbraco")
	.And()
	.Field("bodyText", "is awesome".Escape())
	.Or()
	.Field("bodyText", "rock".Fuzzy()); 

Examineness can be implemented to do special things to search text, like making it a wild card query, or escaping several terms to have them used as a search sentence.

 

Hopefully this more direct post will engage your attention better and make you want more Examine sexiness.

Categories: .Net | Examine | Umbraco

sIFR vs. cufón: Text replacement and you

by James Diacono 31. March 2010 10:40

There are two reasons I use dynamic text replacement:

  1. Plain text in a browser window is never as smooth as it is in the design (except in Safari),
  2. The designs I'm given almost always use fancy (non-web based) fonts for headings, intro text etc.

Currently I subscribe to two solutions, both client-side: sIFR and cufón. If you want a quick answer to "what should I use?" then here it is: if you want replacement for long sentences and headings, use sIFR. If you want replacement for a few words on a button or in a menu, use cufón. If you want to know more, read on...

sIFR

How sIFR works

sIFR uses javascript to dynamically embed a Flash object in the place of specified HTML text elements. The Flash object is essentially an empty SWF (compiled Flash file) which includes the characters of the font you want to use. When javascript embeds the SWF in the HTML, it passes the SWF arguments such as text-content, font-size, color, rollover behaviour and many more. Some of these properties javascript takes from the CSS applied to the text, and some are overridden by sifr-config.js, which is a human-readable config file containing additional formatting tweaks.

How to use sIFR

  1. Download the source (only sifr.js, sifr-config.js and sifr.css are actually needed).
  2. Generate a font SWF from a True Type Font file. You can do this manually with Adobe Flash (like this) but it is easier to use this online generation tool.
  3. Link to sifr.css in the head of your HTML page.
  4. Link to both scripts in the head of your HTML page, first sifr.js, then sifr-config.js
  5. Edit sifr-config.js to read in the font SWF you created and use CSS selector syntax to select the HTML text elements you want to replace.
  6. Tweak away in sifr-config.js until the text looks right when sIFR is both enabled and disabled, in case the user is missing Flash (iPhones don't have Flash as of early 2010!).

cufón

How cufón works

cufón is entirely javascript and works in all major browsers (including IE6). You still need to generate a font file, but this is output to a javascript file similar in size to the equivalent sIFR SWF font file. cufón looks at selected blocks of text and replaces each word with a dynamically generated image (using the HTML <canvas> tag), or in IE's case, a VML object (Vector Markup Language). As a consquence of this, increasing the text size of the page either doesn't affect cufón-replaced text or expands the image, blurring it. Except in IE, which scales the text perfectly.

How to use cufón

  1. Download the source (all you need is cufon-yui.js)
  2. Generate a font file from a True Type Font. You are unfortunately dependent on this online generator.
  3. Link to cufon-yui.js in the head of your HTML page. Beneath it, link to any font files you've generated.
  4. You may also want to create another file, cufon-config.js, to hold selector information much the same way as sifr-config.js does.
  5. Populate cufon-config.js with what HTML text elements you want to replace.

Legality

Font foundaries are seemingly run by people who are very freaked out that their fonts are going to leak for free. Hence, the vast majority of fonts can't legally be embedded directly into the CSS (what, you didn't know about that? It's been around a while in some form or another - the @font-face directive allows you to supply the font file for obscure font-families - but it's only legal with open source fonts).

Because sIFR uses Flash, and Adobe has a cordial agreement with the font foundaries in Switzerland (or wherever) which allows anyone to embed pretty much any font in a .swf, sIFR is totally legal. cufón... cufón not so much. Although both supply a compiled/obfuscated font resource in .swf/.js format respectively, and are basically the same from the font foundaries' point of view, they haven't got around to adding "Allows embedding using javascript methods" to their fonts' terms of use agreements. And I wouldn't count on it...

So in short, use cufón. Go on, it's young and fresh and rad! Push the font foundaries to legalise it! But remember: you read that in a blog post...I'm not going to be your lawyer if they come after you.

Comparison

sIFR cufón
Core file-size (not including fonts) 30KB 18KB
Independent of Flash ×
Resizes nicely ×
Cursor-selectable text ×
Doesn't flicker on load ×
Independent of online font-generator ×
Online font-generator supports Open fonts (.otf) ×
Supported in all browsers
Degrades gracefully
Legal ×
Categories: Flash | JavaScript

Regionalizing validation messages, and regex in Umbraco Contour

by AnthonyDang 26. March 2010 12:23
Umbraco Contour is a great package for ultra fast building of forms. What we used it for was not entirely what it was meant for.
 
We were asked to build a form where labels, validation messages AND the regular expressions to validate phone numbers were all regionalized. Contour uses Umbraco's dictionary to store regionalized labels, so we decided to store our validation messages and regex there. Here is how we did it all...
 
Firstly, we name our field's in the form #Form_FirstName, #Form_LastName etc. In the dictionary, add your languages. Then create items with the same names as the form fields (without the #). This allows Contour to replace your labels. We create two matching items to handle regionalized values for validation messages and regex: #Form_FirstName_vmsg, and #Form_FirstName_regex respectively. 
 
Contour installs RenderForm.ascx under \usercontrols\umbracoContour\ in your project. Noticing this, you can easily change it's CodeBehind property to your own  "RenderForm.ascx.cs" which you inherit from Contour's. Overriding OnPreRender() is where the magic happens. The code is pretty self explanatory. We override OnPreRender(), loop through the fields, use their caption property and a suffix ("_vmsg" or "_regex") to get the values from the dictionary.
 
Here is the code... 
  
 
public class RenderForm : Umbraco.Forms.UI.Usercontrols.RenderForm
{
protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            // get the form fields
            FormStorage fs = new FormStorage();
            var form = fs.GetForm(new Guid(this.FormGuid));
            var fields = form.AllFields;

            foreach (var f in fields)
            {
                // get this field's validator
                var fieldId = f.Id.ToString();
                var vals = Page.Validators
                            .Cast<BaseValidator>()
                            .Where(x => x.ControlToValidate == fieldId).ToList();
                if (vals.Count > 0)
                {
                    foreach (var baseVal in vals)
                    {
  // get the validator type and assign properties
                        BaseValidator val = baseVal as RegularExpressionValidator;
                        if (val != null) // it is RegularExpressionValidator
                        {
                            // get regionalized regular expression
                            string valExpression = GetRegionalizedValidationText(f.Caption, "_regex");
                            ((RegularExpressionValidator)val).ValidationExpression = !string.IsNullOrEmpty(valExpression) ? valExpression : ((RegularExpressionValidator)val).ValidationExpression;
                        }
                        else // either a RequiredFieldValidator or another type which you must handle here!
                        {
                            // cast to another Validator type you are expecting, then set it's properties
                        }
 
   // Get the error message
val = baseVal as BaseValidator;
                        if (val != null)
                        {
                            // get regionalized error message
                            string errorMessage = GetRegionalizedValidationText(f.Caption, "_vmsg"); 
                            val.ErrorMessage = !string.IsNullOrEmpty(errorMessage) ? errorMessage : val.ErrorMessage;
                        } 
                        val.ValidationGroup = form.Name;
                    }
                }
            }          
        } 
 
 
  // Uses's the given string and suffix to get a value from the Umbraco dictionary.
        public string GetRegionalizedValidationText(string key, string type)
        {
            if (key.Contains("#"))
            {
                string itemName = key.Split('#')[1] + type;

                if (umbraco.library.GetDictionaryItem(itemName) != null) // note: item can exist and be ""
                    return umbraco.library.GetDictionaryItem(itemName);
            }
            return ""; // key does not contain #, or not found in dictionary
        } 
 } 
 
Tags:
Categories: .Net | Umbraco

jQuery fade bug in IE – background transparent PNG image

by Shannon Deminick 26. March 2010 08:20

(I’ve found a ‘solution’ to this… see bottom of post)

Problem

I’ve been trying to figure this out for the whole day today and have finally succumbed to the realization that I’m pretty sure I’ve found a bug in jQuery, even the latest version.

The example link is below. The mark-up is very simple and all that is being done is:

  • Create a box with a single pixel semi transparent PNG image
  • Call either fadeIn or fadeOut on any HTML element on the page… suddenly (and strangely) the box magically has a semi transparent gradient on it!

So if anyone out there know how to fix this, I’m all ears. I’m about to go searching on the net for an alternative fade in/fade out library that doesn’t produce these results but would obviously like to just use the built in jQuery methods.

Click here to see the bug and source! (You’ll have to view in IE 7/8 to see the bug)

Before fade out on the black box:

image

After fade out on the black box:

image

 

VERY STRANGE!!!!

Solution

I knew this had to be an issue with IE’s stupid DXImage transform stuff but didn’t really want to go down the route of fiddling with it but in the end, had to do it. And also had to add a stupid little hack to target IE directly.

Step 1:

Create a IE conditional div wrapper around everything under body:

<!--[if IE]><div id="ieWrap"><![endif]—>

(the rest of the page html goes here)

<!--[if IE]></div><![endif]—>

Step 2:

Target the elements in CSS for IE that have the background PNG transparent image:

#ieWrap .productView .productThumbnail a
{
	background-image: none;
	filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='grey_overlay.png',sizingMethod='scale');
}

Click here for solution

And, a day later i found out this isn’t working as expected in IE 7… great… so figured out i had to add: width:100% to the style with the DXImageTransform.

Tags: , ,

Examine’s fluent search API

by Aaron Powell 25. March 2010 14:14

As I mentioned in my last blog post we’ve done a lot of work to refactor Examine (and Umbraco Examine) to use a fluent search API rather than a string based search API.

The primary reason for this was to do with how we were handling the string searching and opening up the Lucene.Net search API. In the initial preview version we would take the text which you entered as a search term and then produce a Lucene.Net search against all the fields in your index. This is ok, but it’s not great. The problem came when we wanted to implement a dynamic search query. There were several different search parameters, which were to check against different fields in the index.
It was sort of possible to achieve this, but you needed to understand the internals of Examine and you also needed to understand the Lucene query language, and also that you couldn’t use the AND/ OR/ NOT operators, you had to use +, – or blank.

This is fine if you’re into search API’s, but really, how many people are actually like that? Ok, I must admit that I’m rather smitten with Lucene but I’m not exactly a good example of a normal person..

So I set about addressing this problem, we needed to get a much simpler way in which your average Joe could come and without knowing the underlying technology write complex and useful search queries.
For this we’ve build a set of interfaces which you require:

  • ISearchCriteria
  • IQuery
  • IBooleanOperation

ISearchCriteria

The ISearchCriteria interface is the real workhorse of the API, it’s the first interface you start with, and it’s the last interface you deal with. In fact, ISearchCriteria implements IQuery, meaning that all the query operations start here.

In addition to query operations there are several additional properties for such as the maximum number of results and the type of data being searched.

Because ISearchCriteria is tightly coupled with the BaseSearchProvider implementation it is actually created via a factory pattern, like so:

ISearchCriteria searchCriteria = ExamineManager.Instance.SearchProviderCollection["MySearcher"].CreateSearchCriteria(100, IndexType.Content);

What we’re doing here is requesting that our BaseSearchProvider creates an instance of an ISearchCriteria. It takes two parameters:

  • int maxResults
  • Examine.IndexType indexType

This data can/ should be then used by the search method to return what’s required.

IQuery

The IQuery interface is really the heart of the fluent API, it’s what you use to construct the search for your site. Since Examine is designed to be technology agnostic the methods which are exposed via IQuery are fairly generic. A lot of the concepts are borrowed from Lucene.Net, but they are fairly generic and should be viable for any searcher.

The IQuery API exposes the following methods:

  • IBooleanOperation Id(int id);
  • IBooleanOperation NodeName(string nodeName);
  • IBooleanOperation NodeName(IExamineValue nodeName);
  • IBooleanOperation NodeTypeAlias(string nodeTypeAlias);
  • IBooleanOperation NodeTypeAlias(IExamineValue nodeTypeAlias);
  • IBooleanOperation ParentId(int id);
  • IBooleanOperation Field(string fieldName, string fieldValue);
  • IBooleanOperation Field(string fieldName, IExamineValue fieldValue);
  • IBooleanOperation MultipleFields(IEnumerable<string> fieldNames, string fieldValue);
  • IBooleanOperation MultipleFields(IEnumerable<string> fieldNames, IExamineValue fieldValue);
  • IBooleanOperation Range(string fieldName, DateTime start, DateTime end);
  • IBooleanOperation Range(string fieldName, DateTime start, DateTime end, bool includeLower, bool includeUpper);
  • IBooleanOperation Range(string fieldName, int start, int end);
  • IBooleanOperation Range(string fieldName, int start, int end, bool includeLower, bool includeUpper);
  • IBooleanOperation Range(string fieldName, string start, string end);
  • IBooleanOperation Range(string fieldName, string start, string end, bool includeLower, bool includeUpper);

As you can see all the methods within the IQuery interface return an IBooleanOperator, this is how the fluent API works!

Hopefully it’s fairly obvious what each of the methods are, but the one you’re most likely to use is Field. Field allows you to specify any field in your index, and then provide a word to lookup within that field.

IExamineValue

You’ve probably noticed the IExamineValue parameter which is passable to a lot of the different methods, methods which take a string, but what is IExamineValue?
Well obviously it’s some-what provider dependant, so I’ll talk about it as part of Umbraco Examine, as that’s what I think most initial uptakers will want.

Because Lucene supports several different term modifiers for text we decided it would be great to have those exposed in the API for people to leverage. For this we’ve got a series of string extension methods which reside in the namespace

UmbracoExamine.SearchCriteria

So once you add a using statement for that you’ll have the following extension methods:

  • public static IExamineValue SingleCharacterWildcard(this string s)
  • public static IExamineValue MultipleCharacterWildcard(this string s)
  • public static IExamineValue Fuzzy(this string s)
  • public static IExamineValue Fuzzy(this string s, double fuzzieness)
  • public static IExamineValue Boost(this string s, double boost)
  • public static IExamineValue Proximity(this string s, double proximity)
  • public static IExamineValue Excape(this string s)
  • public static string Then(this IExamineValue vv, string s)

All of these (with the exception of Then) return an IExamineValue (which UmbracoExamine internally handles), and it tells Lucene.Net how to handle the term modifier you required.

I wont repeat what is said within the Lucene documentation, I suggest you read that to get an idea of what to use and when.
The only exceptions are Escape and Then.

Escape

If you’re wanting to search on multiple works together then Lucene requires them to be ‘escaped’, otherwise it’ll (generally) treat the space character as a break in the query. So if you wanted to search for Umbraco Rocks and didn’t escape it you’d match on both Umbraco and Rocks, where as when it’s escaped you’ll then match on the two words in sequence.

Then

The Then method just allows you to combine multiple strings or multiple IExamineValues, so you can boost your fuzzy query with a proximity of 0.1 :P.

IBooleanOpeation

IBooleanOperation allows your to join multiple IQuery methods together using:

  • IQuery And()
  • IQuery Or()
  • IQuery Not()

These are then translated into the underlying searcher so it can determine how to deal with your chaining. At the time of writing we don’t support nested conditionals (grouped OR’s operating like an And).

There’s another method on IBooleanOperation which doesn’t fall into the above, but it’s very critical to the overall idea:

  • ISearchCriteria Compile()

The Compile method will then return an ISearchCriteria which you then pass into your searcher. It’s expected that this is the last method which is called and it’s meant to prepare all search queries for execution.
The reason we’re going with this rather than passing the IQuery into the Searcher is that it means we don’t have to have the max results/ etc into every IQuery instance, it’s not something that is relevant in that scope, so it’d just introduce code smell, and no one wants that.

Bringing it all together

So now you know the basics, how do you go about producing a query?

Well the first thing you need to do is get an instance of your ISearchCriteria:

var sc = ExamineManager.Instance.CreateSearchCriteria();

Now lets do a search for a few things across a few different fields:

var query = sc.NodeName("umbraco").And().Field("bodyText", "is awesome".Escape()).Or().Field("bodyText", "rock".Fuzzy());

Now we’ve got a query across a few different fields, lastly we need to pass it to our searcher:

var results = ExamineManager.Instance.Search(query.Compile());

It’s just that simple!

 

Hopefully the fluent API is clean enough that people can build nice and complex queries and are able to search their websites with not problem. If you’ve got any feedback please leave it here, as we’re working to get an RC out soon.

Categories: Umbraco | Examine | .Net

Examine, but not as you knew it

by Aaron Powell 21. March 2010 14:07

Almost 12 months ago Shannon blogged about Umbraco Examine a Lucene.NET indexer which works nicely with Umbraco 4.x. Since then we’ve done quite a bit of work on Examine, and as people will may be aware we’ve integrated Examine into the Umbraco core and it will be shipped out of the box with Umbraco 4.1.

Something Shannon and I had discussed a few times was that we wanted to decouple Examine from Umbraco so it could be used for indexing on sites other than Umbraco.
You’ll also notice that I keep referring to it as Examine, not Umbraco Examine which most people are more familiar with.
This is because over the last week we have achieved what we’d wanted to do, we’ve decoupled Examine from Umbraco!

So what’s Examine?

Examine is a provider based, config driven search and indexer framework. Examine provides all the methods required for indexing and searching any data source you want to use.

Examine is now agnostic of the indexer/ searcher API, as well as the data source. That’s right Examine has no references within itself to Umbraco, nor does it have any references to Lucene.NET.
We have still maintained a usage of XML internally for passing the data-to-index around, as it’s the easiest construct which we could think to work with and pass around.

You could implement the Examine framework in any solution, to index any data you want, it could be from a SQL server, or it could be from web-scraped content.

Where does that leave Umbraco Examine?

Umbraco Examine still exists, in fact it’s the primary (and currently only) implementer of Examine. Over the last week though we’ve done a lot of refactoring of Umbraco Examine to work with some changes we’ve done to the underlying Examine API.

Changes? What changes?

Last week anyone who follows me on Twitter will have seen a lot of tweets around Umbraco Examine which was about a new search API and the breaking changes we were implementing.

While looking to refactor the underlying API of a large Umbraco site we have running I found that Examine was actually not properly designed if you wanted to search for data in specific fields, or build complex search queries.

This was a real bugger, I had many different parameters I needed to optionally search on, and only in certain fields, but since Umbraco Examine works with just a raw string this wasn’t possible.

So I set about creating a new fluent search API. This has actually turned out quite well, in fact so well that we new have this as the recommended search method, not raw text (which is still available).

The fluent API is part of the Examine API so it’s also available for any implementation, not just Umbraco! Since we’ve used Lucene.NET as the initial support model the API is designed similarly to what you’d expect from Lucene.NET, but we hope that it’s generic enough to look and feel right for any indexer/ searcher.

Here’s how the fluent API looks:

searchCriteria
.Id(1080)
.Or()
.Field("headerText", "umb".Fuzzy())
.And()
.NodeTypeAlias("cws".MultipleCharacterWildcard())
.Not()
.NodeName("home");

All you have to do is pass that into your searcher. That easy, and that beautiful. I’ll do a blog post where we’ll look more deeply into the fluent API separately.

Additionally we’ve done some other changes, because of what the framework new is we’ve renamed our assemblies and namespaces:

  • Examine.dll
    • This was formally UmbracoExamine.Core.dll
    • Root namespace Examine
    • Contains all the classes and methods to create your own indexer and searcher
  • UmbracoExamine.dll
    • This was formally UmbracoExamine.Providers.dll
    • Root namespace UmbracoExamine.dll
    • Contains all the classes and methods of an Umbraco & Lucene.NET

Apologies to any existing implementations of Umbraco Examine, this will result in breaking changes but since we’ve not hit RC yet too bad :P.

There are also some changes to the config, <IndexUserFields /> has become <IndexStandardFields />, and obviously the config registrations are different with the assembly and namspace changes.

The last change is that we’ve moved to the Ms-PL license for Examine, whos source is available on codeplex.

 

Currently we’re working to tidy up the API and the documentation so that we can get the RC release out shortly, so watch this space.

Categories: Umbraco | .Net | Examine

ASP.Net Client Dependency Framework RC1 Released!

by Shannon Deminick 18. March 2010 17:13

With the community feedback, bug reports, patches, etc… I’ve managed to find time to upgrade this library to a release candidate status. We do use this framework in many production websites but it was great to hear from other in regards to specific bugs that were found relating to particular environments. These bugs have all been fixed up and this library is looking very stable.

You can download the binaries here.

Better yet, I’ve put together a near complete documentation library on CodePlex here !!

I still think the best way to learn about this project is to download the source code from CodePlex here and have a look at the demo web application included.

Moving forward, the next phase for this library is to add MVC support and another file registration provider called PlaceholderProvider which will give you even more granular control over where dependencies can be rendered in your markup. MVC support should be fairly straight forward and we’ll include a demo project for this as well.

Well definitely be releasing a final version soon after the next Umbraco 4.1 release candidate is released (which will hopefully be fairly soon!)

Happy day! Any and all feedback, bug reports and patches are definitely appreciated!

New Umbraco Package – Media Link Checker

by Aaron Powell 3. March 2010 15:52

Ever been trying to work out if a media item is used within your site? And if it is, where are all the places that it’s being used?

Here at TheFARM we had this problem and we set about solving it, and once solved we thought it’d be a great idea to share it with the community.
To this extent we’ve put together a handy little Umbraco Data Type which you can attach to any media type and then find out its usages.

It’ll look up based on:

  • Media Pickers (or DataTypes which store the media node ID)
  • Usage within the WYSIWYG editor (based on the file-system path)

Version 1.0 of the package (released today) supports Umbraco 4.0.x.

When Umbraco 4.1 is released we’ll be producing an updated version of the Data Type which will have some nifty new features which it can leverages from the new 4.1 features.

So what can you do with it?

  • When the Data Type locates an instance of the media item attached to a media picker you have the option to directly disconnect it!
    • This will modify the document, but leave it in a unpublished state, so you can go review your change before putting it live
  • When the Data Type locates an instance of the media item in a WYSIWYG field it will allow you to view the full path to the document in the content tree, so you can navigate there and address it

But really, a picture is worth a thousand words, so since there’s a lot of pictures in a video I guess this is worth a hell of a lot - http://www.screencast.com/t/ZDcxNjQ2ND

So now that you’re excited why not jump over to the project section of Our.Umbraco and grab a copy!

Tags:
Categories: Umbraco