Module:Italic title
Jump to navigation
Jump to search
Documentation for this module may be created at Module:Italic title/doc
1 -- This module implements {{italic title}}.
2
3 require('Module:No globals')
4 local libraryUtil = require('libraryUtil')
5 local checkType = libraryUtil.checkType
6 local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg
7 local yesno = require('Module:Yesno')
8
9 --------------------------------------------------------------------------------
10 -- ItalicTitle class
11 --------------------------------------------------------------------------------
12
13 local ItalicTitle = {}
14
15 do
16 ----------------------------------------------------------------------------
17 -- Class attributes and functions
18 -- Things that belong to the class are here. Things that belong to each
19 -- object are in the constructor.
20 ----------------------------------------------------------------------------
21
22 -- Keys of title parts that can be italicized.
23 local italicizableKeys = {
24 namespace = true,
25 title = true,
26 dab = true,
27 }
28
29 ----------------------------------------------------------------------------
30 -- ItalicTitle constructor
31 -- This contains all the dynamic attributes and methods.
32 ----------------------------------------------------------------------------
33
34 function ItalicTitle.new()
35 local obj = {}
36
37 -- Function for checking self variable in methods.
38 local checkSelf = libraryUtil.makeCheckSelfFunction(
39 'ItalicTitle',
40 'obj',
41 obj,
42 'ItalicTitle object'
43 )
44
45 -- Checks a key is present in a lookup table.
46 -- Param: name - the function name.
47 -- Param: argId - integer position of the key in the argument list.
48 -- Param: key - the key.
49 -- Param: lookupTable - the table to look the key up in.
50 local function checkKey(name, argId, key, lookupTable)
51 if not lookupTable[key] then
52 error(string.format(
53 "bad argument #%d to '%s' ('%s' is not a valid key)",
54 argId,
55 name,
56 key
57 ), 3)
58 end
59 end
60
61 -- Set up object structure.
62 local parsed = false
63 local categories = {}
64 local italicizedKeys = {}
65 local italicizedSubstrings = {}
66
67 -- Parses a title object into its namespace text, title, and
68 -- disambiguation text.
69 -- Param: options - a table of options with the following keys:
70 -- title - the title object to parse
71 -- ignoreDab - ignore any disambiguation parentheses
72 -- Returns the current object.
73 function obj:parseTitle(options)
74 checkSelf(self, 'parseTitle')
75 checkType('parseTitle', 1, options, 'table')
76 checkTypeForNamedArg('parseTitle', 'title', options.title, 'table')
77 local title = options.title
78
79 -- Title and dab text
80 local prefix, parentheses
81 if not options.ignoreDab then
82 prefix, parentheses = mw.ustring.match(
83 title.text,
84 '^(.+) %(([^%(%)]+)%)$'
85 )
86 end
87 if prefix and parentheses then
88 self.title = prefix
89 self.dab = parentheses
90 else
91 self.title = title.text
92 end
93
94 -- Namespace
95 local namespace = mw.site.namespaces[title.namespace].name
96 if namespace and #namespace >= 1 then
97 self.namespace = namespace
98 end
99
100 -- Register the object as having parsed a title.
101 parsed = true
102
103 return self
104 end
105
106 -- Italicizes part of the title.
107 -- Param: key - the key of the title part to be italicized. Possible
108 -- keys are contained in the italicizableKeys table.
109 -- Returns the current object.
110 function obj:italicize(key)
111 checkSelf(self, 'italicize')
112 checkType('italicize', 1, key, 'string')
113 checkKey('italicize', 1, key, italicizableKeys)
114 italicizedKeys[key] = true
115 return self
116 end
117
118 -- Un-italicizes part of the title.
119 -- Param: key - the key of the title part to be un-italicized. Possible
120 -- keys are contained in the italicizableKeys table.
121 -- Returns the current object.
122 function obj:unitalicize(key)
123 checkSelf(self, 'unitalicize')
124 checkType('unitalicize', 1, key, 'string')
125 checkKey('unitalicize', 1, key, italicizableKeys)
126 italicizedKeys[key] = nil
127 return self
128 end
129
130 -- Italicizes a substring in the title. This only affects the main part
131 -- of the title, not the namespace or the disambiguation text.
132 -- Param: s - the substring to be italicized.
133 -- Returns the current object.
134 function obj:italicizeSubstring(s)
135 checkSelf(self, 'italicizeSubstring')
136 checkType('italicizeSubstring', 1, s, 'string')
137 italicizedSubstrings[s] = true
138 return self
139 end
140
141 -- Un-italicizes a substring in the title. This only affects the main
142 -- part of the title, not the namespace or the disambiguation text.
143 -- Param: s - the substring to be un-italicized.
144 -- Returns the current object.
145 function obj:unitalicizeSubstring(s)
146 checkSelf(self, 'unitalicizeSubstring')
147 checkType('unitalicizeSubstring', 1, s, 'string')
148 italicizedSubstrings[s] = nil
149 return self
150 end
151
152 -- Renders the object into a page name. If no title has yet been parsed,
153 -- the current title is used.
154 -- Returns string
155 function obj:renderTitle()
156 checkSelf(self, 'renderTitle')
157
158 -- Italicizes a string
159 -- Param: s - the string to italicize
160 -- Returns string.
161 local function italicize(s)
162 assert(type(s) == 'string', 's was not a string')
163 assert(s ~= '', 's was the empty string')
164 return string.format('<i>%s</i>', s)
165 end
166
167 -- Escape characters in a string that are magic in Lua patterns.
168 -- Param: pattern - the pattern to escape
169 -- Returns string.
170 local function escapeMagicCharacters(s)
171 assert(type(s) == 'string', 's was not a string')
172 return s:gsub('%p', '%%%0')
173 end
174
175 -- If a title hasn't been parsed yet, parse the current title.
176 if not parsed then
177 self:parseTitle{title = mw.title.getCurrentTitle()}
178 end
179
180 -- Italicize the different parts of the title and store them in a
181 -- titleParts table to be joined together later.
182 local titleParts = {}
183
184 -- Italicize the italicizable keys.
185 for key in pairs(italicizableKeys) do
186 if self[key] then
187 if italicizedKeys[key] then
188 titleParts[key] = italicize(self[key])
189 else
190 titleParts[key] = self[key]
191 end
192 end
193 end
194
195 -- Italicize substrings. If there are any substrings to be
196 -- italicized then start from the raw title, as this overrides any
197 -- italicization of the main part of the title.
198 if next(italicizedSubstrings) then
199 titleParts.title = self.title
200 for s in pairs(italicizedSubstrings) do
201 local pattern = escapeMagicCharacters(s)
202 local italicizedTitle, nReplacements = titleParts.title:gsub(
203 pattern,
204 italicize
205 )
206 titleParts.title = italicizedTitle
207
208 -- If we didn't make any replacements then it means that we
209 -- have been passed a bad substring or that the page has
210 -- been moved to a bad title, so add a tracking category.
211 if nReplacements < 1 then
212 categories['Pages using italic title with no matching string'] = true
213 end
214 end
215 end
216
217 -- Assemble the title together from the parts.
218 local ret = ''
219 if titleParts.namespace then
220 ret = ret .. titleParts.namespace .. ':'
221 end
222 ret = ret .. titleParts.title
223 if titleParts.dab then
224 ret = ret .. ' (' .. titleParts.dab .. ')'
225 end
226
227 return ret
228 end
229
230 -- Returns an expanded DISPLAYTITLE parser function called with the
231 -- result of obj:renderTitle, plus any other optional arguments.
232 -- Returns string
233 function obj:renderDisplayTitle(...)
234 checkSelf(self, 'renderDisplayTitle')
235 return mw.getCurrentFrame():callParserFunction(
236 'DISPLAYTITLE',
237 self:renderTitle(),
238 ...
239 )
240 end
241
242 -- Returns an expanded DISPLAYTITLE parser function called with the
243 -- result of obj:renderTitle, plus any other optional arguments, plus
244 -- any tracking categories.
245 -- Returns string
246 function obj:render(...)
247 checkSelf(self, 'render')
248 local ret = self:renderDisplayTitle(...)
249 for cat in pairs(categories) do
250 ret = ret .. string.format(
251 '[[Category:%s]]',
252 cat
253 )
254 end
255 return ret
256 end
257
258 return obj
259 end
260 end
261
262 --------------------------------------------------------------------------------
263 -- Exports
264 --------------------------------------------------------------------------------
265
266 local p = {}
267
268 local function getArgs(frame, wrapper)
269 assert(type(wrapper) == 'string', 'wrapper was not a string')
270 return require('Module:Arguments').getArgs(frame, {
271 wrappers = wrapper
272 })
273 end
274
275 -- Main function for {{italic title}}
276 function p._main(args)
277 checkType('_main', 1, args, 'table')
278 local italicTitle = ItalicTitle.new()
279 italicTitle:parseTitle{
280 title = mw.title.getCurrentTitle(),
281 ignoreDab = yesno(args.all, false)
282 }
283 if args.string then
284 italicTitle:italicizeSubstring(args.string)
285 else
286 italicTitle:italicize('title')
287 end
288 return italicTitle:render(args[1])
289 end
290
291 function p.main(frame)
292 return p._main(getArgs(frame, 'Template:Italic title'))
293 end
294
295 function p._dabonly(args)
296 return ItalicTitle.new()
297 :italicize('dab')
298 :render(args[1])
299 end
300
301 function p.dabonly(frame)
302 return p._dabonly(getArgs(frame, 'Template:Italic dab'))
303 end
304
305
306 return p