Sunday, September 21, 2008

How To Set the Default Spellchecker Dictionary in Microsoft Word 2003

If you find the default language changing in MS Word 2003, you need to change the normal.dot template.

To do this, open a new Microsoft Word document, cut and paste some text into it from somewhere, and then click on Tools/Language/Set Language and select English (whatever).

Next, whilst English (whatever) is highlighted, and the option Detect language automatically is selected, click on the Default button.

You should get a message indicating that the template.dot template will be changed and that all new documents from now on will use the whatever dictionary by default. NB: New documents.

I suspect that this needs to be done each time you change the underlying template.

Thanks to Liz Jamieson: How To Set the UK Dictionary as Default Spellchecker in Microsoft Word 2003

Thursday, September 18, 2008

SpringWidgets - An RSS reader and consolidator

See Google's Google's Dynamic Feed Control Wizard - Put feeds on Your Web Page - makes life easy. for another (pure JavaScript) feed reader/consolidator.

SNAG-0908

SpringWidgets has given me a tool that I can put on my traditional site at http://johnsawyer.info/.

It contains 3 feeds, My Traditional Site, My Techo Blog, and my creative writing blog.

You can select the feed via the arrows or via the menu.

You can get a copy of this widget by using the "Options" button. SNAG-0909

 

 

 

I got one for my Google home page

SNAG-0910

and my desktop.

SNAG-0911

 

 

I also got a reskined  copy of this widget for the side bar of this blog.

Try It!

Wednesday, September 17, 2008

Windows Live Writer is a pretty good tool for making and updating BLOGs on Blogger.com

After a few weeks struggling with JavaScript rich text editors, I found  Windows Live Writer. It allows me to write my post in windows using familiar tools.

I can view the post

  • normally,
    SNAG-0898
  • in a web layout using the style sheets on the target blog
    SNAG-0899 
  • on as a WWW preview or HTML
    image
  • HTML

I can

  • publish
    SNAG-0901 ,
  • choose my BLOG
    SNAG-0902 
  • Edit or delete an existing post
    SNAG-0903

Excellent

There are two features that I found to be particularly useful:

  • Paste special has a number of paste options
    SNAG-0904
    I use the Thinned HTML method.
    The Writer's built in editor is pretty good for my techo blog but I need the research and lookup features of MS Word for my Creative Writing blog. When I'm ready to publish, I just save the word document as HTML, copy the data from MS Word & paste special into Writer.
  • the Insert Syntax Highlighter is a much safer method of pasting in code snippets without the danger of breaking the HTML on the target page
    SNAG-0905 
    You still have to include styles and script in the Blog's main template. I describe that in my earlier How to highlight code in a blog post. That's just a one off exercise.

There are lots of Plug-ins that are worth exploring.

One negative

I could not install the program without rebooting the PC. It got to 99% and then it just hung.
image Other than that it's been great and I've been far more productive.

Build your own VB.Net Search Engine (Part 1)

I wanted to produce my own site search engine using VB.net and I chose
  • Html Agility Pack  for HTML page parsing
      - Extract word list for indexing
      - Extract a list of embedded links
  • lucene.Net as the search engine

This post shows the steps I took to

  • parse the the document
  • produce a word list
  • hint at how to add the word list to lucene
    (Part 2 is to come)
  • extract each link

Part 2 will describe the lucene.Net

  • Indexing
  • Lookup
The Main Process

When the HTML has been obtained, text is passed to ProcessHTML below.

  • The document is parsed with LoadHtml
  • The words are extracted with ConvertContentTo
  • a collection of links is built using SelectNodes("//a[@href]")
    Sub ProcessHTML(ByVal html As String, ByVal url As String)
Dim doc As New HtmlDocument
doc.LoadHtml(html)
Dim sw As New StringWriter
ConvertContentTo(doc.DocumentNode, sw)
Dim wordlist As String = sw.ToString
Dim lDoc As New Lucene.Net.Documents.Document
lDoc.Add(New Field("text", wordlist, Field.Store.YES, Field.Index.TOKENIZED))
lDoc.Add(New Field("url", url, Field.Store.YES, Field.Index.TOKENIZED))
iw.AddDocument(lDoc)

For Each link As HtmlNode In doc.DocumentNode.SelectNodes("//a[@href]")
Dim att As HtmlAttribute = link.Attributes("href")
Dim a As String = att.Value
If Not a.StartsWith("#") Then
Extracting a list of words

The following code builds a list of words. It has been adapted from C# code here.
It is also one of the samples in the download.

   Sub ConvertContentTo(ByVal node As HtmlNode, ByVal tw As TextWriter)
For Each subnode As HtmlNode In node.ChildNodes
ConvertTo(subnode, tw)
Next
End Sub
Sub ConvertTo(ByVal node As HtmlNode, ByVal tw As TextWriter)
Dim html As String
Select Case node.NodeType
Case HtmlNodeType.Document
ConvertContentTo(node, tw)
Case HtmlNodeType.Text
' script and style must not be output
Dim parentName As String = node.ParentNode.Name
If parentName = "script" Or parentName = "style" Then
Return
End If
' html = node.
html = node.InnerText
' is it in fact a special closing node output as text?
If (HtmlNode.IsOverlappedClosingElement(html)) Then
Return
End If
' check the text is meaningful and not a bunch of whitespaces
If (html.Trim().Length > 0) Then
tw.Write(HtmlEntity.DeEntitize(html) + " ")
End If
Case HtmlNodeType.Element
If node.Name = "p" Then
tw.WriteLine("")
End If
If node.HasChildNodes Then
ConvertContentTo(node, tw)
End If
End Select
End Sub

The HTML parsing was pretty quick - much quicker than an earlier approach using regular expressions.

Tuesday, September 16, 2008

Found It: The list of email subscribers in FeedBurn

I spent ages looking for the list of email subscribers in the FeedBurn Dashboard.
I did find FeedBurner Email Overview and FAQ, but it didn't actually say what to do.

Its real easy when you know how.

Feedburner --> Dashboard --> Publicise --> Email Subscriptions



Then right down the bottom - just above Save

Click View Subscriber Details


There they all are


Maybe I'll write about using Excel (2003) to collect the data regularly.

Monday, September 15, 2008

Adding "Email this post" to each Blogger post


Feedburner does have a "FeedFlare" facility that allows users to email an individual post but it means that they have to fill out a form and type a "Captcha".

Most people resist this.

Thanks to Ben Hall's 'Add link building links your blogger posts' I added a more conventional href="mailto:..." entry to the bottom of each post.

The following code goes just before <div class='post-footer-line:

<a expr:href='"mailto:?body=Thought you might like this: " + data:post.url + "&amp;subject=" + data:post.title'>Email It!</a>

NB: it is pretty important that you use the string &amp;Subject= when pasting in the HTML template

Thursday, September 11, 2008

Overcoming Problems with AdSense for Search

sourcehealer.net has a Google Custom Search on each of its pages. This is implemented via personalised code javascript code generated by Google as you create each new ad channel.

Search Box

The snippet is pasted to the page where you want it.
We also need to place the style import on the page:
There was a problem with the search box. It was caused because ASPX Master Page generated
tags in unexpected places and this meant that the
tags had to be rearranged carefully or the wrong form was submitted or it used the 'put' method (which is the ASPX default)

The Results Page

The snippet is pasted where you want Google to display the results (and targeted ads).
This all works well until you attempt to have a page that resizes itself to match the browser.
  • changing var googleSearchFrameWidth = 800; to less than 800 will not display results if you are using FORID:9 (Ads on the right only)
  • resizing after download proved particularly difficult
  1. the results are displayed in an iframe which can't easily be controlled using CSS
  2. IE7 treats offsetLeft differently than the others
  3. detecting the browser caused a long search but resulted in a very simple result, see
    another way to detect IE7 in Javascript
  4. finding the iframe was supplied by Changing properties for the search results iframe

The resulting code is driven by <body onload="myOnLoad();" onresize="myResize();" ...

See the resulting resizable page in action.

Tuesday, September 9, 2008

How to highlight code in a blog

When you want to include a Code Snippet in your blog, it looks better like this:

Dim dt As New DataTable
With dt.Columns
.Add("Title")
.Add("Start", Type.GetType("System.DateTime"))
.Add("End", Type.GetType("System.DateTime"))
.Add("Content")
.Add("Location")
End With

You can do this by:
Step 1
Obtain the syntax highlighter from here
Step 2
Copy the compressed js and the css files to some friendly WWW site
Step 3
Change your Blogger HTML template to include a css link just after the head tag

Step 3

You then copy the following JavaScript links after the outer wrapper

Step 4
You then add the following javascript:

All done!

Now when you include a snippet in your a blog, just surround it with pre tags as follows:


NB: Push past this error message, but check that your blog still displays.

Google Calendar Service hosts a Gig Guide

Google Data APIs allow your client applications to interact with Google services such as Picassa Web Albums, Blogger Data and Calendar Data.

The .NET version of the API can be downloaded from here.

When Yarra Community Music Network wanted a Gig Guide on their site, I provided it by


  • using the Google Calendar service to maintain a list of events via a browser and
  • accessing this from the WEB application using Google.GData.Calander namespace in the API (see code snippet below)

SecurityException:

Everything worked well on the local development site, but when it was loaded to the GoDaddy virtual WEB hosting, the page failed with a message like:

“System.Security.SecurityException: That assembly does not allow partially trusted callers”

This was finally overcome by using the Google API that was generated using “Allowing Partially Trusted Callers”.

It is in the “\Program Files\Google\Google Data API SDK\Redist\ASP.NET” folder







You must use the 1.2.2 (or later) version of the API. Earlier versions do not work.

(and explanation of sorts is in the README.TXT file)


WARNING

Those assemblies here are identical to the assemblies in the Release directory, with the exception of being marked as PartiallyTrusted. If you
do not know what this means, or what the potential implications are for your website, refer to MSDN and search for

AllowPartiallyTrustedCallers

to get the information you need to use this correctly.

Note, while we believe that the Google Data assemblies follow security protocol, they do allow to call other websites directly, and hence
it is up to you, the developer of the website, to make that final judgement call. The assemblies in this directory are provide as is, and
just as a matter of convienience, as it is easy enough to recompile the code yourself.



A preliminary code snippet





With query
.Uri = New Uri("http://www.google.com/calendar/feeds/default/private/full")
.StartTime = Now.AddDays(-28) ' Set the date range
.EndTime = Now.AddMonths(6)
End With
Dim feed As EventFeed

With service
.setUserCredentials("me", "secret") ' *** you know what to do
feed = .Query(query)
End With
Dim dt As New DataTable ' store the results in a table for sorting
With dt.Columns
.Add("Title")
.Add("Start", Type.GetType("System.DateTime"))
.Add("End", Type.GetType("System.DateTime"))
.Add("Content")
.Add("Location")
End With
While feed.Entries.Count > 0
For Each entry As EventEntry In feed.Entries
With entry
For Each w As Object In .Times
If .Status.Value.Equals(EventEntry.EventStatus.CONFIRMED_VALUE.ToString) Then
' Only process confirmed events (in case a date in a repeating event has been deleted - say because of holidays)
Dim dr As DataRow = dt.NewRow
dr!Title = .Title.Text
dr!Start = w.StartTime
dr!End = w.EndTime
dr!Content = .Content.Content
dr!Location = .Locations(0).ValueString
dt.Rows.Add(dr)
End If
Next
End With
Next
If feed.NextChunk = Nothing Then
Exit While ' the data is delivered in "chunks"
End If
query.Uri = New Uri(feed.NextChunk)
feed = service.Query(query)
End While
For Each dr As DataRow In dt.Select("", "Start") ' now get the events based on start time
With dr



See: Sorting photo data from Google's Picasa API for a later description of the API.