Wiki Doc

Wiki called WikiDoc: http://sourceforge.net/projects/wikidoc/
The following Microsoft Word 97 macros make a single word document into a mini wiki database. Sort of "wiki for one". WHAT?! If you hook the subroutime WikiDoc up to Alt-W (or whatever), whenever you press Alt-W, all wiki names (called "page names" in the code) at the beginning of pages become bookmarks (hyperlink targets) of style "heading 2". All page names not at the beginning of pages become underlined hyperlinks.

If you hook the subroutine WikiUnPage up to Alt-U (or whatever), you can press Alt-U to remove all the page breaks. This is useful if you want to print the document.

The rule used for page names is: start with uppercase and contain at least two uppercase and one lowercase.

[To copy these macros without the ?'s, click on Edit Text, then select text from the edit text box]. -- StanSilver

 What a WikiDoc looks like:
----------
TopicOne
Blah blah blah TopicTwo
----------
TopicTwo
Blah blah TopicThree
----------
TopicThree
Blah blah TopicOne and TopicTwo blah blah TopicFour
----------

Sub WikiDoc() '=================================' ' Delete bookmarks and hyperlinks ' '=================================' For i = ActiveDocument.Bookmarks.Count To 1 Step -1 ActiveDocument.Bookmarks(i).Delete Next i For i = ActiveDocument.Hyperlinks.Count To 1 Step -1 ActiveDocument.Hyperlinks(i).Delete Next i '====================================' ' Set target page names as bookmarks ' '====================================' Dim myRange As Range For Each myRange In ActiveDocument.Words If WikiIsPageName(myRange) Then If WikiIsTarget(myRange) Then '=======' ' Taget ' '=======' myName = Trim(myRange.Text) With ActiveDocument.Bookmarks .Add Range:=myRange, Name:=myName .DefaultSorting = wdSortByName .ShowHidden = False End With myRange.Style = wdStyleHeading2 End If End If Next '=================================================' ' Set link page names with targets as hyperlinks ' ' Underline link page names without targets' '=================================================' For Each myRange In ActiveDocument.Words If WikiIsPageName(myRange) Then If Not WikiIsTarget(myRange) Then '======' ' Link ' '======' myRange.Bold = False myRange.Underline = False myName = Trim(myRange.Text) If ActiveDocument.Bookmarks.Exists(myName) = True Then ActiveDocument.Hyperlinks.Add Anchor:=myRange, Address:="", SubAddress:=myName Else myRange.Underline = True myRange.Font.ColorIndex = wdRed End If End If End If Next ActiveDocument.Save MsgBox ("Done") End Sub

Function WikiIsPageName(myRange As Range) As Boolean '==============================================================' ' Page name must start with an uppercase, and contain at least ' ' two uppercase and one lowercase characters' '==============================================================' WikiIsPageName = False If (myRange.Characters(1) > "Z") Then Exit Function myUpperCaseCount = 0 myLowerCaseCount = 0 For Each myCharRange In myRange.Characters If ((myCharRange <= "Z") And (myCharRange >= "A")) Then myUpperCaseCount = myUpperCaseCount + 1 End If If ((myCharRange <= "z") And (myCharRange >= "a")) Then myLowerCaseCount = myLowerCaseCount + 1 End If Next If ((myUpperCaseCount > 1) And (myLowerCaseCount > 0)) Then WikiIsPageName = True End If End Function

Function WikiIsTarget(myRange As Range) As Boolean '============================================' ' Assume myRange is a page name. Target must ' ' appear directly after a new page character ' '============================================' WikiIsTarget = False myStart = myRange.Start - 1 myEnd = myRange.Start Set myPreviousRange = ActiveDocument.Range(Start:=myStart, End:=myEnd) myPreviousChar = myPreviousRange.Characters(1).Text If Asc(myPreviousChar) = 12 Then WikiIsTarget = True End Function

Sub WikiUnPage() '===============================' ' Remove all manual page breaks ' '===============================' Selection.HomeKey Unit:=wdStory Selection.Find.ClearFormatting Selection.Find.Replacement.ClearFormatting With Selection.Find .Text = "^m" .Replacement.Text = "" .Forward = True .Wrap = wdFindContinue .Format = False .MatchCase = False .MatchWholeWord = False .MatchWildcards = False .MatchSoundsLike = False .MatchAllWordForms = False End With Selection.Find.Execute Replace:=wdReplaceAll End Sub


Suggestion for Speedup:

 I removed the lowercase part:
If ((myCharRange <= "z") And (myCharRange >= "a")) Then
 myLowerCaseCount = myLowerCaseCount + 1
End If

and replaced the WikiPageName criterion:

If ((myUpperCaseCount > 1) And (myLowerCaseCount > 0)) Then WikiIsPageName = True End If

By:

If (myUpperCaseCount > 1) Then WikiIsPageName = True End If

The MicrosoftWord interpreter thanks it with greater speed and we have more flexible WikiPageNames. See http://www.data-music.com for useful samples. -- FridemarPache


I found the above code to take greater than 15 seconds to execute even for a small document. The following code is much faster by allowing links to be created on demand, instead of processing the entire document each time. If the macro WikiCreateLink is executed (I have a key bound to this) after typing a Wiki Word, then a link is created to the bookmark with the same name as the Wiki Word. If that bookmark doesn't exist, then the WikiWord is made into a Macro Button field. When this macro button field is double clicked, a page break, along with a page title and a new bookmark is inserted at the end of the current page. I like to set the value of the Field Shading dropdown in the Tools->Options->View Tab to Always so the links to the nonexisting pages stand out. The following code also requires the WikiIsPageName macro from the above code. -- BrianTheado

 Sub WikiCreateLink()
 '
 ' Create a Wiki link out of the nearest word to the left
 '
 Selection.MoveLeft Unit:=wdWord, Count:=1, Extend:=wdExtend
 If WikiIsPageName(Selection.Words.First) Then
myName = Trim(Selection.Words.First)
If ActiveDocument.Bookmarks.Exists(myName) = True Then
' Page already exists - add a hyperlink
ActiveDocument.Hyperlinks.Add Anchor:=Selection.Words.First, Address:="", SubAddress:=myName
Else
'
' Page doesn't exist turn the word into a macrobutton
' field that will create a new page when double clicked
'
Selection.Words.First.underline = True
Selection.Words.First.Font.ColorIndex = wdRed
Selection.Fields.Add Range:=Selection.Range, Type:=wdFieldMacroButton, Text:= _
"WikiAddNewPage " + myName, PreserveFormatting:=False
End If
 End If
 End Sub
 Sub WikiAddNewPage()
 ' Remove the macrobutton field
 Selection.Fields.Unlink

' Hyperlink the word to the about to be created page Selection.MoveLeft Unit:=wdWord, Count:=1, Extend:=wdExtend myName = Selection.Words.First.Text ActiveDocument.Hyperlinks.Add Anchor:=Selection.Words.First, Address:="", SubAddress:=myName

If ActiveDocument.Bookmarks.Exists(myName) = False Then ' Move to just beyond the next page break and create the new page FindPageBreak Selection.MoveRight WikiCreatePage (myName) End If End Sub Sub WikiCreatePage(myName As String) Selection.TypeText Text:=myName Selection.Style = wdStyleHeading1 ActiveDocument.Bookmarks.Add Range:=Selection.Words.First, Name:=myName Selection.TypeParagraph Selection.InsertBreak Type:=wdPageBreak Selection.MoveUp End Sub Sub FindPageBreak() Selection.Find.ClearFormatting With Selection.Find .Text = "^m" .Replacement.Text = "" .Forward = True .Wrap = wdFindStop .Format = False .MatchCase = False .MatchWholeWord = False .MatchWildcards = False .MatchSoundsLike = False .MatchAllWordForms = False End With Selection.Find.Execute End Sub


on my Word97 SR2 installation, I had to add one line of code:

Sub WikiCreatePage(myName As String)

myName = RTrim(myName)
...
-- TimmDanker

This quick linking feature is very helpful. I adapted the WikiDoc routine to also insert macro button fields for unknown Wiki Words, but describing this as changes to the code above would become unreadable, so if anyone is interested, please send me an email. -- RalfHandl

''Alas, I wasn't able to get any of these macros to work on my Word97 setup. Ralf, where is your email address? -- MichaelBrown


 Function WikiIsPageName(myRange As Range) As Boolean
WikiIsPageName = (myRange.Case = wdToggleCase)
 End Function

... seems to do what we want (and quickly). Now one can inline the function. -- FalkBruegmann

Well, at least on my machine (WinNT, Office97) this is much slower than the original function. -- RalfHandl


Does this work with OfficeXP, too? I tried and it didn't work. Any improvement suggestions? -- PeterHenning?


So, here's my preliminary version based on BrianTheado's. Name restrictions are only given by Word. Why use WikiNames if the Wiki doesn't automatically detect them? I tried to install a routine that converts illegal WikiWords into legal ones (in my sense). Unfortunately, I never used VBA with Word before... -- GüntherLehnert

 ' WordWiki
 ' Tested with <a href="http://www.serverlogic3.com/lm/rtl3.asp?si=1&k=office%20xp" onmouseover="window.status='Office XP'; return true;" onmouseout="window.status=''; return true;">Office XP</a>

Sub WikiLink()

' Hyperlink the word to the about to be created page Selection.MoveLeft Unit:=wdWord, Count:=1, Extend:=wdExtend myName = Selection.Words.First.Text

' Begin Word with a letter Do While NumberRange(Asc(Left(myName, 1))) < 2 myName = Right(myName, Len(myName) - 1) Loop

' End with the last allowed character Do While NumberRange(Asc(Right(myName, 1))) < 1 myName = Left(myName, Len(myName) - 1) Loop

' Delete characters not allowed in Links i = 1 Do While i < Len(myName) If NumberRange(Asc(Mid(myName, i, 1))) = 0 Then myName = Left(myName, i - 1) & Right(myName, Len(myName) - i) Else i = i + 1 End If Loop

ActiveDocument.Hyperlinks.Add Anchor:=Selection.Words.First, Address:="", SubAddress:=myName

If ActiveDocument.Bookmarks.Exists(myName) = False Then ' Move to just beyond the next page break and create the new page FindPageBreak Selection.MoveRight WikiCreatePage (myName) End If End Sub

' Checks for allowed characters ' How could you do this easier? Function NumberRange(Number As Byte) As Integer NumberRange = 0 If Number > 47 And Number < 58 Then NumberRange = 1 If Number > 64 And Number < 91 Then NumberRange = 2 If Number > 96 And Number < 123 Then NumberRange = 2 If Number > 191 And Number < 215 Then NumberRange = 2 If Number > 215 And Number < 247 Then NumberRange = 2 If Number > 248 And Number < 256 Then NumberRange = 2 If Number = 95 Then NumberRange = 1 End Function

Sub WikiCreatePage(myName As String) Selection.TypeText Text:=myName Selection.Style = wdStyleHeading1 ActiveDocument.Bookmarks.Add Range:=Selection.Words.First, Name:=myName Selection.TypeParagraph Selection.InsertBreak Type:=wdPageBreak Selection.MoveUp End Sub

Sub FindPageBreak(Optional joke As Boolean) '<- so it is not displayed as a separate macro Selection.Find.ClearFormatting With Selection.Find .Text = "^m" .Replacement.Text = "" .Forward = True .Wrap = wdFindStop .Format = False .MatchCase = False .MatchWholeWord = False .MatchWildcards = False .MatchSoundsLike = False .MatchAllWordForms = False End With Selection.Find.Execute End Sub


Please see my site at http://www.SuperThinking.com. I have a Word Addin there. Could use some de-klugeing, but addresses many of the aspirations of some of these macros.

--RichVanSchaik?

This link/domain is gone/expired. -- John Godin



EditText of this page (last edited October 18, 2011) or FindPage with title or text search