-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathVBA-Word-Macros.vba
305 lines (235 loc) · 11.6 KB
/
VBA-Word-Macros.vba
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
Sub UpdateAll()
Application.ScreenUpdating = False 'This improves performance
'Firstly hide the field codes so Word doesn't need to update their display
ActiveWindow.View.ShowFieldCodes = False 'Alt + F9
'Update all fields in the document, including references, cross references & caption labels
ActiveDocument.Fields.Update
'This has to be before StyleBibliography because it resets the style and can also add rows
StyleBibliography 'This has to be before UpdateTablesOfFiguresAndContents, because the bibliography can spill into more pages, so we start from the end
UpdateTablesOfFiguresAndContents
Application.ScreenUpdating = True 'Re-enable screen updating
End Sub
Sub StyleBibliography()
Application.ScreenUpdating = False 'This improves performance
'Style the Bibliography References Table: turn http into hyperlinks, adjust columns widths and align text to the left
Dim T As Table: Set T = FindBibliography: T.AllowAutoFit = False
Dim httpPos, spacePos, refs As Integer: Dim cols, C2 As Object
Set cols = T.columns: Set C2 = cols(2)
refs = ActiveDocument.Bibliography.Sources.Count
'Width of 1st col based on how many digits of references you have:
If refs <= 9 Then '[9]
cols(1).Width = 17 ': C2.Width = 420
ElseIf refs <= 99 Then '[99]
cols(1).Width = 22 ': C2.Width = 415
Else '[999]
cols(1).Width = 30 ': C2.Width = 407
End If
C2.AutoFit 'Width
Dim CellsRange As Cells: Set CellsRange = C2.Cells
Dim r As Range: Dim cellText, linkText As String
For Each c In CellsRange
Set r = c.Range
r.ParagraphFormat.Alignment = wdAlignParagraphLeft 'Align Left
'Hyperlinks
cellText = r.Text: cellText = Left(cellText, Len(cellText) - 2)
httpPos = InStr(cellText, "http") 'some links don't have the 's' in 'https', but 'http' works for both
If httpPos > 0 Then
spacePos = InStr(httpPos, cellText, " ") 'Find the first space after "http"
If spacePos = 0 Then spacePos = Len(cellText) + 1 'Use text length if no space is found
'Extract the link text (URL)
linkText = Mid(cellText, httpPos, spacePos - httpPos - 1) 'Assuming there's a dot '.' just before thespace ' '
r.Start = r.Start + httpPos - 1 'Assuming there's a dot '.' just before thespace ' '
r.End = r.Start + Len(linkText)
ActiveDocument.Hyperlinks.Add Anchor:=r, Address:=linkText
End If
Next c
Application.ScreenUpdating = True 'Re-enable screen updating
End Sub
Function FindBibliography() As Table
Application.ScreenUpdating = False 'This improves performance
'There is no in-built syntax to find the Bibliography References Table. This function finds it and attempts to do so in the most quick and efficient way.
Dim p As Integer ' n 'p = page, n = new page
Dim RangeFields As Fields
Dim DocTables As Tables: Set DocTables = ActiveDocument.Tables
Dim rng As Range: Set rng = ActiveDocument.Range
For Each T In DocTables 'T = Table
n = T.Range.Information(wdActiveEndPageNumber): If p = n Then GoTo SkipLoop 'If a single page has multiple tables, skip because we already checked this page
'I search all the field codes in the page because I can't figure the relation (parent, sibling, etc) because the Bibliography table and field code.
'But at least I narrow down the search only to pages that have ActiveDocument.Tables.
rng.Start = rng.GoTo(What:=wdGoToPage, Which:=wdGoToAbsolute, Count:=n).Start
rng.End = rng.GoTo(What:=wdGoToPage, Which:=wdGoToAbsolute, Count:=n + 1).Start
Set RangeFields = rng.Fields 'Fields on the page of the table
For Each fld In RangeFields
If fld.Type = wdFieldBibliography Then
Set FindBibliography = fld.Result.Tables(1)
MsgBox "Bibliography is (ends) on page " & FindBibliography.Range.Information(wdActiveEndPageNumber)
Application.ScreenUpdating = True 'Re-enable screen updating
Exit Function 'Increase efficiency and stop searching, assuming there is only 1 Bibliography References Table
End If
Next fld
p = n
SkipLoop:
Next T 'Many bibliographies are followed by an appendix with many tables, so it's not obvious that the Bibliography table is in the latter half of ActiveDocument.Tables.
'Also, For-In is faster than For-To-Step in VBA, so for both reasons it makes sense to search through the tables with For-In as opposed to from the end.
MsgBox "No Bibliography Found"
Application.ScreenUpdating = True 'Re-enable screen updating
End Function
Sub UpdateTablesOfFiguresAndContents()
Application.ScreenUpdating = False 'This improves performance
Dim ToFs As TablesOfFigures: Dim ToCs As TablesOfContents: Dim Paras As Paragraphs
Set ToFs = ActiveDocument.TablesOfFigures: Set ToCs = ActiveDocument.TablesOfContents
Dim p, n, Change, i, j As Integer 'p = #pages, n = new #pages, Change = change in #page, i = #Loop iterations
n = ActiveDocument.ComputeStatistics(wdStatisticPages)
i = 0: Change = 0
Do 'The Do-Until Loop is in case of potentially spilling ToCs and ToFs.
i = i + 1: p = n: j = 0
For Each ToF In ToFs
ToF.Update
Next ToF
For Each ToC In ToCs
ToC.Update 'Update first, because it resets the indentation
j = j + 1: Set Paras = ToC.Range.Paragraphs
If j = 1 Then '1st ToC is a special case
For Each para In Paras
para.LeftIndent = (Val(Right(para.Style, 1)) - 1) * 21
Next para
Else 'Indent all to the left except in the 1st ToC
For Each para In Paras
para.LeftIndent = (Val(Right(para.Style, 1)) - 1) * 21 - 20
Next para
End If
Next ToC
n = ActiveDocument.ComputeStatistics(wdStatisticPages)
Change = Change + n - p 'postive means increase, negative means decrease
Loop Until p = n
If Change > 0 Then
MsgBox "# iterations: " & i & vbCrLf & "# pages increased: " & Change
ElseIf Change < 0 Then
MsgBox "# iterations: " & i & vbCrLf & "# pages decreased: " & -1 * Change 'Abs(Change)
End If 'No need to MsgBox if Change = 0 because this is typically the case
Application.ScreenUpdating = True 'Re-enable screen updating
End Sub
'---------------------------------------------HotKeys Shortcuts---------------------------------------------
Sub PasteAsText() '(Ctrl+Shift+V)
On Error Resume Next 'Prevent an error and simply do nothing in case of an empty clipboard or image
Selection.PasteAndFormat (wdFormatPlainText) 'Selection.PasteSpecial DataType:=wdPasteText, but faster
End Sub
'---------------------------------------------Counters---------------------------------------------
Sub CountImages()
Dim i, f As Integer 'i = inlineImages, f = floatingImages
i = ActiveDocument.InlineShapes.Count: f = ActiveDocument.Shapes.Count
MsgBox "Inline Images: " & i & vbCrLf & _
"Floating Images: " & f & vbCrLf & "Total Images: " & i + f
End Sub
Sub CountBookmarks() 'These allow forming custom TOCs for each chapter
MsgBox "Number of Bookmarks: " & ActiveDocument.Bookmarks.Count
End Sub
Sub CountToCs() '#Tables of Contents
MsgBox "Number of Tables of Contents: " & ActiveDocument.TablesOfContents.Count
End Sub
'Note that I have 1 bookmark for every ToC besides the main ToC, so for me: #ToCs = #Bookmarks + 1.
'For you it might be different if you use bookmarks for other purposes as well.
Sub CountToFs() '#Tables of Figures
MsgBox "Number of Tables of Figures: " & ActiveDocument.TablesOfFigures.Count
End Sub
Sub CountCaptionLabels()
Application.ScreenUpdating = False 'This improves performance
Dim i, Total, LabelsCount As Integer
Total = 0: LabelsCount = CaptionLabels.Count
Dim obj: Set obj = CreateObject("Scripting.Dictionary")
Dim Name, Msg As String: Msg = ""
For i = 1 To LabelsCount
obj.Add CaptionLabels(i).Name, 0
Next
Dim fld, flds As Fields: Set flds = ActiveDocument.Fields
For Each fld In flds
If fld.Type = wdFieldSequence Then
Total = Total + 1
Name = Trim(Split(fld.Code.Text, " ")(2))
obj(Name) = obj(Name) + 1
End If
Next
i = 0
For Each Name In obj.keys
i = i + 1
Msg = Msg & i & ") " & Name & ": " & obj(Name) & vbCrLf
Next
MsgBox "Number of Labels: " & LabelsCount & vbCrLf & vbCrLf & _
Msg & vbCrLf & "Total Number of Captions: " & Total
Application.ScreenUpdating = True 'Re-enable screen updating
End Sub
Sub CountTables() '#Tables, excluding ToCs & ToFs, but includes Bibliography
MsgBox "Number of Tables: " & ActiveDocument.Tables.Count
End Sub
Sub CountFields() 'Including field codes, but not only
MsgBox "Number of Fields: " & ActiveDocument.Fields.Count
End Sub
Sub CountCitationsAndReferences()
Application.ScreenUpdating = False 'This improves performance
Dim c, r As Integer: c = 0: r = ActiveDocument.Bibliography.Sources.Count
'#References = Length of current list of sources or updated Bibliography
Dim flds As Fields: Set flds = ActiveDocument.Fields
For Each fld In flds
If fld.Type = wdFieldCitation Then
c = c + 1 '#Citations = Occurances of citations throughout the document
End If
Next
MsgBox "Number of Citations: " & c & vbCrLf & "Number of References: " & _
r & vbCrLf & "Citations/References Ratio: " & Round(c / r, 2)
Application.ScreenUpdating = True 'Re-enable screen updating
End Sub
Sub CountCrossReferences()
Application.ScreenUpdating = False 'This improves performance
Dim c As Integer: c = 0
Dim flds As Fields: Set flds = ActiveDocument.Fields
For Each fld In flds
If fld.Type = wdFieldRef Then
c = c + 1
End If
Next
MsgBox "Number of Cross-References: " & c
Application.ScreenUpdating = True 'Re-enable screen updating
End Sub
Sub CountHyperlinksURLs()
Application.ScreenUpdating = False 'This improves performance
Dim c As Integer: c = 0
Dim flds As Fields: Set flds = ActiveDocument.Fields
For Each fld In flds
If fld.Type = wdFieldHyperlink Then
c = c + 1
End If
Next
MsgBox "Number of Hyperlinks URLs: " & c
Application.ScreenUpdating = True 'Re-enable screen updating
End Sub
'---------------------------------------------Non-Counters, Other MsgBox---------------------------------------------
Sub TodaysDate()
MsgBox "Today's date is: " & Format(Date, "dddd, mmmm d, yyyy")
End Sub
Sub DocumentFolderPath() 'Where it's saved to
Dim p As String: p = ActiveDocument.Path
If p <> "" Then
MsgBox "Document Path: " & p
Else
MsgBox "This document hasn't been saved yet"
End If
End Sub
'---------------------------------------------Non-MsgBox---------------------------------------------
Sub SaveDocument() 'To Do: make this into atuo-save on close & after every edit change
ActiveDocument.Save
End Sub
'---------------------------------------------ToggleShow---------------------------------------------
Sub ToggleShowHeadingsNavigationPane()
If ActiveWindow.DocumentMap Then
ActiveWindow.DocumentMap = False
Else
ActiveWindow.DocumentMap = True
End If
End Sub
Sub ToggleShowFieldCodes() 'Alt + F9
If ActiveWindow.View.ShowFieldCodes Then
ActiveWindow.View.ShowFieldCodes = False
Else
ActiveWindow.View.ShowFieldCodes = True
End If
End Sub