I've been using
OneNote for a while now and its great.
In fact I'm typing this into OneNote right now.
The one thing that really annoys me, though, is the lack of an insert hyperlink command.
Now, this does not need to be as advanced as
Word, although as common parts of the
Office System it would have been nice, but even some simple functionality would have been a
huge improvement over none.
I have been using BlogJet as a way of doing this but it’s a little bit clumsy having to open BlogJet, create the hyperlink then copy and paste it into OneNote. I thought that I could make the process a bit easier. And the BlogJet beta had run out and it looked like I would have to pay to continue to use it.
So, I thought, "This will be pretty easy. I don't need much. Just something to pop up and let me type in a url and some text for it and let me paste that into OneNote."
It wasn't quite as straightforward as that but it wasn't too bad either. The first try at it got me to the user interface and some knowledge of the Clipboard object and it looked pretty straightforward.
Dim strURL As String As String
strURL = "" & _
LinkText.Text & ""
Clipboard.SetDataObject(strURL)
This worked fine to paste the actual text but wasn't what I was looking for. I wanted the text showing with the URL hidden but available. So the result of the HTML rather than the code. I knew this was possible as you can paste from Internet Explorer and it will paste quite happily into OneNote in the format that I wanted. OneNote would try to be clever here and put in the source as well but the basic principle was that it should work.
So with a little more investigation I discovered the different data formats that could be contained in the clipboard and updated my code again.
Dim strURL As String, strHTML As String
strURL = "" & _
LinkText.Text & ""
Dim data_object As New DataObject
data_object.SetData(DataFormats.Text, True, strURL)
data_object.SetData(DataFormats.Html, True, strURL)
data_object.SetData(DataFormats.Rtf, True, LinkText.Text)
Clipboard.SetDataObject(data_object, True)
Me.Close()
At first glance this seemed to be moving backwards as I could no longer paste it into OneNote at all. So back to researching the clipboard and I came across ClipSpy on The Code Project. This is a great tool from Michael Dunn that lets you see the various formats stored in the clipboard at any time. Well, looking at the HTML format, it was clear there was more going on here than it first appeared. So, after a bit of hacking and a pretty much ripped-off piece of Delphi code I found on Newsnet I came up with a workable solution. I even added some sensible behaviour if there is text already in the clipboard when you run it. If you have Version 1.1 of the .NET framework you can get the executable here.
Public
Class EnterLink
Inherits System.Windows.Forms.Form
#
Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
Friend WithEvents Label1 As System.Windows.Forms.Label
Friend WithEvents Label2 As System.Windows.Forms.Label
Friend WithEvents OKButton As System.Windows.Forms.Button
Friend WithEvents LinkText As System.Windows.Forms.TextBox
Friend WithEvents LinkURL As System.Windows.Forms.TextBox
Friend WithEvents ForgetItButton As System.Windows.Forms.Button
Private Sub InitializeComponent()
Me.Label1 = New System.Windows.Forms.Label
Me.OKButton = New System.Windows.Forms.Button
Me.LinkText = New System.Windows.Forms.TextBox
Me.Label2 = New System.Windows.Forms.Label
Me.LinkURL = New System.Windows.Forms.TextBox
Me.ForgetItButton = New System.Windows.Forms.Button
Me.SuspendLayout()
'
'Label1
'
Me.Label1.Location = New System.Drawing.Point(8, 16)
Me.Label1.Name = "Label1"
Me.Label1.Size = New System.Drawing.Size(48, 23)
Me.Label1.TabIndex = 0
Me.Label1.Text = "Text"
'
'OKButton
'
Me.OKButton.Location = New System.Drawing.Point(312, 8)
Me.OKButton.Name = "OKButton"
Me.OKButton.TabIndex = 2
Me.OKButton.Text = "OK"
'
'LinkText
'
Me.LinkText.Location = New System.Drawing.Point(72, 8)
Me.LinkText.Name = "LinkText"
Me.LinkText.Size = New System.Drawing.Size(208, 20)
Me.LinkText.TabIndex = 0
Me.LinkText.Text = "Link"
'
'Label2
'
Me.Label2.Location = New System.Drawing.Point(8, 56)
Me.Label2.Name = "Label2"
Me.Label2.Size = New System.Drawing.Size(48, 23)
Me.Label2.TabIndex = 3
Me.Label2.Text = "URL"
'
'LinkURL
'
Me.LinkURL.Location = New System.Drawing.Point(72, 48)
Me.LinkURL.Name = "LinkURL"
Me.LinkURL.Size = New System.Drawing.Size(208, 20)
Me.LinkURL.TabIndex = 1
Me.LinkURL.Text = "http://"
'
'ForgetItButton
'
Me.ForgetItButton.DialogResult = System.Windows.Forms.DialogResult.Cancel
Me.ForgetItButton.Location = New System.Drawing.Point(312, 48)
Me.ForgetItButton.Name = "ForgetItButton"
Me.ForgetItButton.TabIndex = 3
Me.ForgetItButton.Text = "Cancel"
'
'EnterLink
'
Me.AcceptButton = Me.OKButton
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.CancelButton = Me.ForgetItButton
Me.ClientSize = New System.Drawing.Size(416, 101)
Me.Controls.Add(Me.ForgetItButton)
Me.Controls.Add(Me.LinkURL)
Me.Controls.Add(Me.Label2)
Me.Controls.Add(Me.LinkText)
Me.Controls.Add(Me.OKButton)
Me.Controls.Add(Me.Label1)
Me.Name = "EnterLink"
Me.Text = "Enter Link"
Me.ResumeLayout(False)
End Sub
#
End Region
Private Sub OKButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OKButton.Click
Dim strURL As String, strHTML As String
strURL = "" & _
LinkText.Text & ""
strHTML = MakeFragment(strURL)
Dim data_object As New DataObject
data_object.SetData(DataFormats.Text,
True, strURL)
data_object.SetData(DataFormats.Html,
True, strHTML)
data_object.SetData(DataFormats.Rtf,
True, LinkText.Text)
Clipboard.SetDataObject(data_object,
True)
Me.Close()
End Sub
Private Function MakeFragment(ByVal HTML As String) As String
' Helper routine to build a properly-formatted HTML fragment.
Const Version As String = "Version:1.0" & vbCrLf
Const StartHTML As String = "StartHTML:"
Const EndHTML As String = "EndHTML:"
Const StartFragment As String = "StartFragment:"
Const EndFragment As String = "EndFragment:"
Const DocType = "
Const HTMLIntro As String = "
Const HTMLExtro As String = ""
Const NumberLengthAndCR As Integer = 10
' Let the compiler determine the description length.
Dim DescriptionLength As Integer = Version.Length + StartHTML.Length + _
EndHTML.Length + StartFragment.Length + _
EndFragment.Length + 4 * NumberLengthAndCR
Dim Description As String
Dim StartHTMLIndex, EndHTMLIndex, StartFragmentIndex, EndFragmentIndex As Integer
' The HTML clipboard format is defined by using byte positions in the
'entire block where HTML text and
'fragments start and end. These positions are written in a
'description. Unfortunately the positions depend on the
'length of the description but the description may change with
'varying positions.
'To solve this dilemma the offsets are converted into fixed length
'strings which makes it possible to know
'the description length in advance.
StartHTMLIndex = DescriptionLength
StartFragmentIndex = StartHTMLIndex + DocType.Length + HTMLIntro.Length
EndFragmentIndex = StartFragmentIndex + HTML.Length
EndHTMLIndex = EndFragmentIndex + HTMLExtro.Length
Dim sb As New System.Text.StringBuilder(Version)
sb.Append(StartHTML)
sb.Append(StartHTMLIndex.ToString.PadLeft(8, "0"))
sb.AppendFormat(vbCrLf)
sb.Append(EndHTML)
sb.Append(EndHTMLIndex.ToString.PadLeft(8, "0"))
sb.Append(vbCrLf)
sb.Append(StartFragment)
sb.Append(StartFragmentIndex.ToString.PadLeft(8, "0"))
sb.Append(vbCrLf)
sb.Append(EndFragment)
sb.Append(EndFragmentIndex.ToString.PadLeft(8, "0"))
sb.Append(vbCrLf)
sb.Append(DocType)
sb.Append(HTMLIntro)
sb.Append(HTML)
sb.Append(HTMLExtro)
Return sb.ToString
End Function
Private Sub CancelButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ForgetItButton.Click
Me.Close()
End Sub
Private Sub InsertExistingLink(ByVal HTML As String, ByVal TextLink As String)
Dim LinkStartIndex As Integer = HTML.ToUpper.IndexOf("
If LinkStartIndex > 0 Then
Dim LinkEndIndex As Integer = HTML.ToUpper.IndexOf("") + 4
Dim FullLink As String = HTML.Substring(LinkStartIndex, LinkEndIndex - LinkStartIndex)
Dim hrefStartIndex As Integer = FullLink.IndexOf(Chr(34)) + 1
Dim hrefEndIndex As Integer = FullLink.IndexOf(Chr(34), hrefStartIndex + 1) - 1
Dim LinkTextStartIndex As Integer = FullLink.IndexOf(">", hrefEndIndex + 1) + 1
Dim LinkTextEndIndex As Integer = FullLink.ToUpper.IndexOf("
LinkText.Text = FullLink.Substring(LinkTextStartIndex, LinkTextEndIndex - LinkTextStartIndex + 1)
Dim Link As String = FullLink.Substring(hrefStartIndex, hrefEndIndex - hrefStartIndex + 1)
LinkURL.Text = CheckRelativeLink(Link, HTML)
Else
InsertTextLink(TextLink)
End If
End Sub
Private Function CheckRelativeLink(ByVal URL As String, _
ByVal HTML As String) As String
If URL.ToUpper.StartsWith("HTTP") Then
Return URL
Else
Dim SourceStartIndex As Integer = HTML.ToUpper.IndexOf("SOURCEURL") + 10
Dim SourceEndIndex As Integer = HTML.IndexOf(Chr(13), SourceStartIndex) - 1
Dim Source As String = HTML.Substring(SourceStartIndex, SourceEndIndex - SourceStartIndex + 1)
If URL.StartsWith("/") AndAlso Source.EndsWith("/") Then
Source = Source.TrimEnd("/")
End If
Return Source & URL
End If
End Function
Private Sub InsertTextLink(ByVal Clip As String)
If Not Clip Is Nothing Then
If Clip.ToUpper.StartsWith("HTTP") Then
LinkURL.Text = Clip
ElseIf Clip.ToUpper.StartsWith("WWW") Then
LinkURL.Text &= Clip
Else
LinkText.Text = Clip
End If
End If
End Sub
Private Sub EnterLink_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim DataObj As DataObject
DataObj = Clipboard.GetDataObject()
If DataObj.GetDataPresent(DataFormats.Html) Then
InsertExistingLink(DataObj.GetData(DataFormats.Html), DataObj.GetData(DataFormats.Text))
ElseIf DataObj.GetDataPresent(DataFormats.Text) Then
InsertTextLink(DataObj.GetData(DataFormats.Text))
End If
End Sub
End
Class