-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathCss.lua
453 lines (367 loc) · 12.6 KB
/
Css.lua
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
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
--[[
This module holds CSS-generating functions. Its main utility are reducing
calls to Colore module and adding vendor prefixes
--]]
local css = {}
-- stylua: ignore start
local mw = require('mw')
local txt = require('Wikilib-strings')
local w = require('Wikilib')
local c = require("Colore-data")
local colorscheme = require("Colorscheme-data")
-- stylua: ignore end
-- Holds mappings from standard values to vendor-specific ones
local vendorMappings = {}
-- Gradient function first arguments for vendor prefixes
vendorMappings.gradient = {
moz = {
horiz = function()
return "left"
end,
slanted = function(direction)
return (
direction:gsub("^%d+", function(angle)
return 450 - angle
end)
) -- 360 - angle + 90
end,
},
webkit = {
horiz = function()
return "left"
end,
slanted = function(direction)
return (
direction:gsub("^%d+", function(angle)
return 450 - angle
end)
) -- 360 - angle + 90
end,
},
}
-- All linear gradient function names
vendorMappings.linearGradients = {
"-moz-linear-gradient",
"-webkit-linear-gradient",
"linear-gradient",
}
-- All radial gradient function names
vendorMappings.radialGradients = {
"-moz-radial-gradient",
"-ms-radial-gradient",
"-o-radial-gradient",
"-webkit-radial-gradient",
"radial-gradient",
}
-- Holds parsing-related functions
local parser = {}
--[[
Processes wikicode arguments from gradient functions, returning hexes for the
passed colors. Takes a single table holding the proper arguments, that should
be in one of the following formats:
- color name, followed by shade. If the shade is not given, it defaults to
'normale'.
- color hexadecimal, with or without leading hashtag.
- color stop, either percentage or absolute length.
- 'transparent', with ot without color stop.
- any CSS gradient function first parameter value. Must be first as well.
A convenience syntax can be used with named parameters 'type1' (or 'type')
and 'type2': if type2 exists and it is different from type1, then
type1-normale and type2-normale are returned; otherwise, type1-light and
type1-normale are.
Another syntax with named parameter 'colorscheme' allows to use colorscheme as
gradient colors: returns the light and dark (in this order) version of the
colorscheme.
--]]
parser.gradientArgs = function(args)
-- If a table is passed, then we are facing named parameters
local p = type(args[1]) == "table" and args[1] or w.trimAll(args, false)
-- Named parameters, as described above
if p.type1 or p.type then
p = w.emptyStringToNil(p)
local type1, mod1 = (p.type1 or p.type):match("^(%S+)%s*(.*)$")
-- Matching against type1 ensures mod1 is not propagated as well
local type2, mod2 = (p.type2 or type1):match("^(%S+)%s*(.*)$")
type1 = type1:lower()
type2 = type2:lower()
-- Cannot use and/or operator because nil is false
if mod1 == "" then
mod1 = nil
end
if mod2 == "" then
mod2 = nil
end
table.insert(p, type1)
table.insert(p, type1 == type2 and "light" or "normale")
table.insert(p, mod1)
table.insert(p, type2)
table.insert(p, "normale")
table.insert(p, mod2)
p.type1, p.type2, p.type = nil, nil, nil
return parser.gradientArgs(p)
end
-- Colorscheme syntax
if p.colorscheme then
local cs = p.colorscheme
return { "#" .. colorscheme[cs].light, "#" .. colorscheme[cs].dark }
end
-- Standard behavior
local gradArgs, currColor = {}, nil
for _, param in ipairs(p) do
param = param == "" and "normale" or param
-- Color name with no shade
if type(currColor) == "table" and not currColor[param] then
table.insert(gradArgs, "#" .. currColor.normale)
currColor = nil
end
--[[
Color name: next parameter should be the shade, so nothing is
appended to args yet.
`not currColor` is necesary due to 'normale' being both a color
and a shade
--]]
if not currColor and c[param] then
currColor = c[param]
-- Shade. Ready to append color now
elseif type(currColor) == "table" and currColor[param] then
table.insert(gradArgs, "#" .. currColor[param])
currColor = nil
--[[
Hexadecimal colors: hashtag is always prefixed due to the regex
matching only unprefixed hexes. Prefixed ones will match the else
branch and will be inserted correctly anyway.
--]]
elseif not param:find("%X") then
table.insert(gradArgs, "#" .. param)
-- Color stop: appending to last args
elseif txt.parseInt(param) then
gradArgs[#gradArgs] =
table.concat({ gradArgs[#gradArgs], " ", param })
-- Trusting the user to enter valid CSS
else
table.insert(gradArgs, param)
end
end
if type(currColor) == "table" then
table.insert(gradArgs, "#" .. currColor.normale)
end
return gradArgs
end
-- Parses an HTML class attribute value into a list of strings
parser.parseClasses = function(classes)
if classes == "" then
return {}
elseif type(classes) ~= "string" then
return classes
end
return mw.text.split(classes, " ")
end
-- Returns an HTML class attribute value from a list of class names
parser.printClasses = function(classes)
return table.concat(classes, " ")
end
--[[
Parses an HTML style attribute value into a table. Keys are CSS property
names and values their CSS values. Example:
'margin: 2px 3px'; padding: 3px; color: #22AAEE;' -->
{margin = '2px 3px', padding = '3px', 'color: #22AAEE'}
--]]
parser.parseStyles = function(stys)
if stys == "" then
return {}
elseif type(stys) ~= "string" then
return stys
end
-- Empty strings break the split in the fold
stys = table.filter(mw.text.split(stys, ";"), function(stmt)
return stmt:find("%S")
end)
return table.fold(stys, {}, function(acc, stmt)
local splits = w.trimAll(mw.text.split(stmt, ":"))
acc[splits[1]] = splits[2]
return acc
end)
end
--[[
Returns an HTML style attribute value from a table. Keys must be CSS
property names and values their CSS values. Example:
{margin = '2px 3px', padding = '3px', 'color: #22AAEE'} -->
'margin: 2px 3px'; padding: 3px; color: #22AAEE;'
--]]
parser.printStyles = function(stys)
return table.concat(
table.mapToNum(stys, function(value, property)
return table.concat({ property, ": ", value })
end),
"; "
) .. ";"
end
-- Holds all css generating functions
local styles = {}
-- Holds all gradient-generating functions
styles.gradient = {}
-- Generates styles for linear gradients
styles.gradient.linear = function(type, dir, colors)
-- Accumulator table
local acc = { "background-size: 100%" }
for _, funct in pairs(vendorMappings.linearGradients) do
-- Cloning due to later table.insert
local gradientArgs = mw.clone(colors)
if type ~= "vert" then
local prefix = funct:match("^%-(%a+)%-")
local direction = prefix
and vendorMappings.gradient[prefix][type](dir)
or dir
table.insert(gradientArgs, 1, direction)
end
local gradientArgs = table.concat(gradientArgs, ", ")
table.insert(
acc,
table.concat({
"background-image: ",
funct,
"(",
gradientArgs,
")",
})
)
end
return table.concat(acc, "; ") .. ";"
end
-- Generates styles for linear gradients
styles.gradient.radial = function(config, colors)
colors = table.concat(colors, ", ")
-- Accumulator table
local acc = { "background-size: 100%" }
for _, funct in pairs(vendorMappings.radialGradients) do
table.insert(
acc,
table.concat({
"background-image: ",
funct,
"(",
config,
", ",
colors,
")",
})
)
end
return table.concat(acc, "; ") .. ";"
end
--[[
This function returns classes and styles structured as parseClasses and
parseStyles would. These can be generated by both custom inputs and
predefinite configurations. Arguments:
- predefs: The table predefined configurations are taken from. Predefined
configuration names are the keys, while values are tables with 'classes'
and 'styles' keys. These hold classes and styles respectively, and have as
values the same structures as arseClasses and parseStyles return.
- pdfs: Table or space-spearated string of predefined configurations names.
Optional, defaults to {}.
- classes: Table/string of CSS classes, in the format parseClasses and
printClasses produce respectively. Optional, defaults to {}.
- stys: Table/string of CSS styles, in the format parseStyles and
printStyles produce respectively. Optional, defaults to {}.
--]]
styles.classesStyles = function(predefs, pdfs, classes, stys)
classes = parser.parseClasses(classes or {})
stys = parser.parseStyles(stys or {})
if pdfs and pdfs ~= "" then
pdfs = type(pdfs) == "string" and mw.text.split(pdfs, " ") or pdfs
for _, predef in pairs(pdfs) do
local pdf = predefs[predef]
if pdf then
classes = table.merge(classes, pdf.classes)
--[[
stys is the second argument of table.merge so that
user-supplied styles override predefinite ones
--]]
stys = table.merge(pdf.styles, stys)
end
end
end
return classes, stys
end
-- Generates horizontal linear gradients styles
css.horizGradLua = function(args)
return styles.gradient.linear(
"horiz",
"to right",
parser.gradientArgs(args)
)
end
css.horiz_grad_lua = css.horizGradLua
-- Generates vertical linear gradients styles
css.vertGradLua = function(args)
return styles.gradient.linear("vert", nil, parser.gradientArgs(args))
end
css.vert_grad_lua = css.vertGradLua
-- Generates slanted linear gradients styles
css.slantedGradLua = function(args)
-- Angle is taken before input processing since it maches an hexadecimal
local angle = txt.trim(table.remove(args, 1))
angle = tonumber(angle) and angle .. "deg" or angle
args = parser.gradientArgs(args)
return styles.gradient.linear("slanted", angle, args)
end
css.slanted_grad_lua = css.slantedGradLua
-- Generates radial gradients styles
css.radialGradLua = function(args)
args = parser.gradientArgs(args)
local first = table.remove(args, 1)
return styles.gradient.radial(first, args)
end
css.radial_grad_lua = css.radialGradLua
--[[
Wikicode interface to generate
horizontal linear gradients styles
--]]
css["horiz-grad"] = function(frame)
return css.horizGradLua(table.copy(frame.args))
end
css.horizGrad, css.horiz_grad = css["horiz-grad"], css["horiz-grad"]
--[[
Wikicode interface to generate
vertical linear gradients styles
--]]
css["vert-grad"] = function(frame)
return css.vertGradLua(table.copy(frame.args))
end
css.vertGrad, css.vert_grad = css["vert-grad"], css["vert-grad"]
--[[
Wikicode interface to generate
slanted linear gradients styles
--]]
css["slanted-grad"] = function(frame)
return css.slantedGradLua(table.copy(frame.args))
end
css.slantedGrad, css.slanted_grad = css["slanted-grad"], css["slanted-grad"]
--[[
Wikicode interface to generate
radial gradients styles
--]]
css["radial-grad"] = function(frame)
return css.radialGradLua(table.copy(frame.args))
end
css.radialGrad, css.radial_grad = css["radial-grad"], css["radial-grad"]
-- Exporting classesStyles to lua only
css.classesStyles = styles.classesStyles
css.classes_styles = css.classesStyles
-- Exporting parseClasses to lua only
css.parseClasses = parser.parseClasses
css.parse_classes = css.parseClasses
-- Exporting parseStyles to lua only
css.parseStyles = parser.parseStyles
css.parse_styles = css.parseStyles
-- Exporting printClasses to lua only
css.printClasses = parser.printClasses
css.print_classes = css.printClasses
-- Exporting printStyles to lua only
css.printStyles = parser.printStyles
css.print_styles = css.printStyles
-- First uppercase aliases
for name, funct in pairs(css) do
css[txt.fu(name)] = funct
end
return css