Module:Italic title

From Viki
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