1if not modules then modules = { } end modules ['lxml-css'] = {
2 version = 1.001,
3 comment = "companion to lxml-css.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9local tonumber, rawset, type, select = tonumber, rawset, type, select
10local lower, format, find, gmatch = string.lower, string.format, string.find, string.gmatch
11local topattern, is_empty = string.topattern, string.is_empty
12local P, S, C, R, Cb, Cg, Carg, Ct, Cc, Cf, Cs = lpeg.P, lpeg.S, lpeg.C, lpeg.R, lpeg.Cb, lpeg.Cg, lpeg.Carg, lpeg.Ct, lpeg.Cc, lpeg.Cf, lpeg.Cs
13local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
14local sort = table.sort
15local setmetatableindex = table.setmetatableindex
16
17xml.css = xml.css or { }
18local css = xml.css
19
20local report_css = logs and logs.reporter("xml","css") or function(...) print(string.format(...)) end
21
22local getid = lxml.getid
23
24if not number.dimenfactors then
25 require("util-dim.lua")
26end
27
28local dimenfactors = number.dimenfactors
29local bpf = 1/dimenfactors.bp
30local cmf = 1/dimenfactors.cm
31local mmf = 1/dimenfactors.mm
32local inf = 1/dimenfactors["in"]
33
34local whitespace = lpegpatterns.whitespace
35local skipspace = whitespace^0
36
37local percentage, exheight, emwidth, pixels
38
39if tex then
40
41 local exheights = fonts.hashes.exheights
42 local emwidths = fonts.hashes.emwidths
43 local texget = tex.get
44
45 percentage = function(s,pcf) return tonumber(s) * (pcf or texget("hsize")) end
46 exheight = function(s,exf) return tonumber(s) * (exf or exheights[true]) end
47 emwidth = function(s,emf) return tonumber(s) * (emf or emwidths[true]) end
48 pixels = function(s,pxf) return tonumber(s) * (pxf or emwidths[true]/300) end
49
50else
51
52 local function generic(s,unit) return tonumber(s) * unit end
53
54 percentage = generic
55 exheight = generic
56 emwidth = generic
57 pixels = generic
58
59end
60
61local validdimen = Cg(lpegpatterns.number,'a') * (
62 Cb('a') * P("pt") / function(s) return tonumber(s) * bpf end
63 + Cb('a') * P("cm") / function(s) return tonumber(s) * cmf end
64 + Cb('a') * P("mm") / function(s) return tonumber(s) * mmf end
65 + Cb('a') * P("in") / function(s) return tonumber(s) * inf end
66 + Cb('a') * P("px") * Carg(1) / pixels
67 + Cb('a') * P("%") * Carg(2) / percentage
68 + Cb('a') * P("ex") * Carg(3) / exheight
69 + Cb('a') * P("em") * Carg(4) / emwidth
70 + Cb('a') * Carg(1) / pixels
71 )
72
73local pattern = (validdimen * skipspace)^1
74
75
76
77local function dimension(str,pixel,percent,exheight,emwidth)
78 return (lpegmatch(pattern,str,1,pixel,percent,exheight,emwidth))
79end
80
81local function padding(str,pixel,percent,exheight,emwidth)
82 local top, bottom, left, right = lpegmatch(pattern,str,1,pixel,percent,exheight,emwidth)
83 if not bottom then
84 bottom, left, right = top, top, top
85 elseif not left then
86 bottom, left, right = top, bottom, bottom
87 elseif not right then
88 bottom, left, right = left, bottom, bottom
89 end
90 return top, bottom, left, right
91end
92
93css.dimension = dimension
94css.padding = padding
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
123local context = context
124
125if context then
126
127 local currentfont = font.current
128 local texget = tex.get
129 local hashes = fonts.hashes
130 local quads = hashes.quads
131 local xheights = hashes.xheights
132
133 local function todimension(str)
134 local font = currentfont()
135 local exheight = xheights[font]
136 local emwidth = quads[font]
137 local hsize = texget("hsize")/100
138 local pixel = emwidth/100
139 return dimension(str,pixel,hsize,exheight,emwidth)
140 end
141
142 css.todimension = todimension
143
144 function context.cssdimension(str)
145
146 context(todimension(str) .. "sp")
147 end
148
149end
150
151
152do
153
154 local p_digit = lpegpatterns.digit
155 local p_unquoted = Cs(lpegpatterns.unquoted)
156 local p_size = (S("+-")^0 * (p_digit^0 * P(".") * p_digit^1 + p_digit^1 * P(".") + p_digit^1)) / tonumber
157 * C(P("p") * S("txc") + P("e") * S("xm") + S("mc") * P("m") + P("in") + P("%"))
158
159 local pattern = Cf( Ct("") * (
160 Cg(
161 Cc("style") * (
162 C("italic")
163 + C("oblique")
164 + C("slanted") / "oblique"
165 )
166 + Cc("variant") * (
167 (C("smallcaps") + C("caps")) / "small-caps"
168 )
169 + Cc("weight") * (
170 C("bold")
171 )
172 + Cc("family") * (
173 (C("mono") + C("type")) / "monospace"
174 + (C("sansserif") + C("sans")) / "sans-serif"
175 + C("serif")
176 )
177 + Cc("size") * Ct(p_size)
178 )
179 + P(1)
180 )^0 , rawset)
181
182 function css.fontspecification(str)
183 return str and lpegmatch(pattern,lower(str))
184 end
185
186
187
188 function css.style(str)
189 if str and str ~= "" then
190 str = lower(str)
191 if str == "italic" then
192 return "italic"
193 elseif str == "slanted" or str == "oblique" then
194 return "slanted"
195 end
196 end
197 return "normal"
198 end
199
200 function css.variant(str)
201 if str and str ~= "" then
202 str = lower(str)
203 if str == "small-caps" or str == "caps" or str == "smallcaps" then
204 return "caps"
205 end
206 end
207 return "normal"
208 end
209
210 function css.weight(str)
211 if str and str ~= "" then
212 str = lower(str)
213 if str == "bold" then
214 return "bold"
215 end
216 end
217 return "normal"
218 end
219
220 function css.family(str)
221 if str and str ~= "" then
222 str = lower(str)
223 if str == "mono" or str == "type" or str == "monospace" then
224 return "mono"
225 elseif str == "sansserif" or str == "sans" then
226 return "sans"
227 elseif str == "serif" then
228 return "serif"
229 else
230
231 return lpegmatch(p_unquoted,str) or str
232 end
233 end
234 end
235
236 function css.size(str,factors, pct)
237 local size, unit
238 if type(str) == "table" then
239 size, unit = str[1], str[2]
240 elseif str and str ~= "" then
241 size, unit = lpegmatch(p_size,lower(str))
242 end
243 if size and unit then
244 if unit == "%" and pct then
245 return size * pct
246 elseif factors then
247 return (factors[unit] or 1) * size
248 else
249 return size, unit
250 end
251 end
252 end
253
254 function css.colorspecification(str)
255 if str and str ~= "" then
256 local c = attributes.colors.values[tonumber(str)]
257 if c then
258 return format("rgb(%s%%,%s%%,%s%%)",c[3]*100,c[4]*100,c[5]*100)
259 end
260 end
261 end
262
263end
264
265
266
267
268
269
270
271local function s_element_a(list,collected,c,negate,str,dummy,dummy,n)
272 local all = str == "*"
273 for l=1,#list do
274 local ll = list[l]
275 local dt = ll.dt
276 if dt then
277 local ok = all or ll.tg == str
278 if negate then
279 ok = not ok
280 end
281 if ok then
282 c = c + 1
283 collected[c] = ll
284 end
285 if (not n or n > 1) and dt then
286 c = s_element_a(dt,collected,c,negate,str,dummy,dummy,n and n+1 or 1)
287 end
288 end
289 end
290 return c
291end
292
293
294
295local function s_element_b(list,collected,c,negate,str)
296 local all = str == "*"
297 for l=1,#list do
298 local ll = list[l]
299 local pp = ll.__p__
300 if pp then
301 local dd = pp.dt
302 if dd then
303 local ni = ll.ni
304 local d = dd[ni+1]
305 local dt = d and d.dt
306 if not dt then
307 d = dd[ni+2]
308 dt = d and d.dt
309 end
310 if dt then
311 local ok = all or d.tg == str
312 if negate then
313 ok = not ok
314 end
315 if ok then
316 c = c + 1
317 collected[c] = d
318 end
319 end
320 end
321 end
322 end
323 return c
324end
325
326
327
328local function s_element_c(list,collected,c,negate,str)
329 local all = str == "*"
330 for l=1,#list do
331 local ll = list[l]
332 local pp = ll.__p__
333 if pp then
334 local dt = pp.dt
335 if dt then
336 local ni = ll.ni
337 for i=ni+1,#dt do
338 local d = dt[i]
339 local dt = d.dt
340 if dt then
341 local ok = all or d.tg == str
342 if negate then
343 ok = not ok
344 end
345 if ok then
346 c = c + 1
347 collected[c] = d
348 end
349 end
350 end
351 end
352 end
353 end
354 return c
355end
356
357
358
359
360local function s_element_d(list,collected,c,negate,str)
361 if str == "*" then
362 if not negate then
363 for l=1,#list do
364 local ll = list[l]
365 local dt = ll.dt
366 if dt then
367 if not ll.special then
368 c = c + 1
369 collected[c] = ll
370 end
371 c = s_element_d(dt,collected,c,negate,str)
372 end
373 end
374 end
375 else
376 for l=1,#list do
377 local ll = list[l]
378 local dt = ll.dt
379 if dt then
380 if not ll.special then
381 local ok = ll.tg == str
382 if negate then
383 ok = not ok
384 end
385 if ok then
386 c = c + 1
387 collected[c] = ll
388 end
389 end
390 c = s_element_d(dt,collected,c,negate,str)
391 end
392 end
393 end
394 return c
395end
396
397
398
399
400
401
402
403
404
405
406
407local function s_attribute(list,collected,c,negate,str,what,value)
408 for l=1,#list do
409 local ll = list[l]
410 local dt = ll.dt
411 if dt then
412 local at = ll.at
413 if at then
414 local v = at[str]
415 local ok = negate
416 if v then
417 if not what then
418 ok = not negate
419 elseif what == 1 then
420 if v == value then
421 ok = not negate
422 end
423 elseif what == 2 then
424
425 if find(v,value) then
426 ok = not negate
427 end
428 elseif what == 3 then
429
430 if find(v," ",1,true) then
431 for s in gmatch(v,"[^ ]+") do
432 if s == value then
433 ok = not negate
434 break
435 end
436 end
437 elseif v == value then
438 ok = not negate
439 end
440 end
441 end
442 if ok then
443 c = c + 1
444 collected[c] = ll
445 end
446 end
447 c = s_attribute(dt,collected,c,negate,str,what,value)
448 end
449 end
450 return c
451end
452
453
454
455
456
457
458local function filter_down(collected,c,negate,dt,a,b)
459 local t = { }
460 local n = 0
461 for i=1,#dt do
462 local d = dt[i]
463 if type(d) == "table" then
464 n = n + 1
465 t[n] = i
466 end
467 end
468 if n == 0 then
469 return 0
470 end
471 local m = a
472 while true do
473 if m > n then
474 break
475 end
476 if m > 0 then
477 t[m] = -t[m]
478 end
479 m = m + b
480 end
481 if negate then
482 for i=n,1-1 do
483 local ti = t[i]
484 if ti > 0 then
485 local di = dt[ti]
486 c = c + 1
487 collected[c] = di
488 end
489 end
490 else
491 for i=n,1,-1 do
492 local ti = t[i]
493 if ti < 0 then
494 ti = - ti
495 local di = dt[ti]
496 c = c + 1
497 collected[c] = di
498 end
499 end
500 end
501 return c
502end
503
504local function filter_up(collected,c,negate,dt,a,b)
505 local t = { }
506 local n = 0
507 for i=1,#dt do
508 local d = dt[i]
509 if type(d) == "table" then
510 n = n + 1
511 t[n] = i
512 end
513 end
514 if n == 0 then
515 return 0
516 end
517 if not b then
518 b = 0
519 end
520 local m = n - a
521 while true do
522 if m < 1 then
523 break
524 end
525 if m < n then
526 t[m] = -t[m]
527 end
528 m = m - b
529 end
530 if negate then
531 for i=1,n do
532 local ti = t[i]
533 if ti > 0 then
534 local di = dt[ti]
535 c = c + 1
536 collected[c] = di
537 end
538 end
539 else
540 for i=1,n do
541 local ti = t[i]
542 if ti < 0 then
543 ti = - ti
544 local di = dt[ti]
545 c = c + 1
546 collected[c] = di
547 end
548 end
549 end
550 return c
551end
552
553local function just(collected,c,negate,dt,a,start,stop,step)
554 local m = 0
555 for i=start,stop,step do
556 local d = dt[i]
557 if type(d) == "table" then
558 m = m + 1
559 if negate then
560 if a ~= m then
561 c = c + 1
562 collected[c] = d
563 end
564 else
565 if a == m then
566 c = c + 1
567 collected[c] = d
568 break
569 end
570 end
571 end
572 end
573 return c
574end
575
576local function s_nth_child(list,collected,c,negate,a,n,b)
577 if n == "n" then
578 for l=1,#list do
579 local ll = list[l]
580 local dt = ll.dt
581 if dt then
582 c = filter_up(collected,c,negate,dt,a,b)
583 end
584 end
585 else
586 for l=1,#list do
587 local ll = list[l]
588 local dt = ll.dt
589 if dt then
590 c = just(collected,c,negate,dt,a,1,#dt,1)
591 end
592 end
593 end
594 return c
595end
596
597local function s_nth_last_child(list,collected,c,negate,a,n,b)
598 if n == "n" then
599 for l=1,#list do
600 local ll = list[l]
601 local dt = ll.dt
602 if dt then
603 c = filter_down(collected,c,negate,dt,a,b)
604 end
605 end
606 else
607 for l=1,#list do
608 local ll = list[l]
609 local dt = ll.dt
610 if dt then
611 c = just(collected,c,negate,dt,a,#dt,1,-1)
612 end
613 end
614 end
615 return c
616end
617
618
619
620
621
622
623local function s_nth_of_type(list,collected,c,negate,a,n,b)
624 if n == "n" then
625 return filter_up(collected,c,negate,list,a,b)
626 else
627 return just(collected,c,negate,list,a,1,#list,1)
628 end
629end
630
631local function s_nth_last_of_type(list,collected,c,negate,a,n,b)
632 if n == "n" then
633 return filter_down(collected,c,negate,list,a,b)
634 else
635 return just(collected,c,negate,list,a,#list,1,-1)
636 end
637end
638
639
640
641local function s_only_of_type(list,collected,c,negate)
642 if negate then
643 for i=1,#list do
644 c = c + 1
645 collected[c] = list[i]
646 end
647 else
648 if #list == 1 then
649 c = c + 1
650 collected[c] = list[1]
651 end
652 end
653 return c
654end
655
656
657
658local function s_only_child(list,collected,c,negate)
659 if negate then
660 for l=1,#list do
661 local ll = list[l]
662 local dt = ll.dt
663 if dt then
664 for i=1,#dt do
665 local di = dt[i]
666 if type(di) == "table" then
667 c = c + 1
668 collected[c] = di
669 end
670 end
671 end
672 end
673 else
674 for l=1,#list do
675 local ll = list[l]
676 local dt = ll.dt
677 if dt and #dt == 1 then
678 local di = dt[1]
679 if type(di) == "table" then
680 c = c + 1
681 collected[c] = di
682 end
683 end
684 end
685 end
686 return c
687end
688
689
690
691local function s_empty(list,collected,c,negate)
692 for l=1,#list do
693 local ll = list[l]
694 local dt = ll.dt
695 if dt then
696 local dn = #dt
697 local ok = dn == 0
698 if not ok and dn == 1 then
699 local d = dt[1]
700 if type(d) == "string" and is_empty(d) then
701 ok = true
702 end
703 end
704 if negate then
705 ok = not ok
706 end
707 if ok then
708 c = c + 1
709 collected[c] = ll
710 end
711 end
712 end
713 return c
714end
715
716
717
718local function s_root(list,collected,c,negate)
719 for l=1,#list do
720 local ll = list[l]
721 if type(ll) == "table" then
722 local r = xml.root(ll)
723 if r then
724 if r.special and r.tg == "@rt@" then
725 r = r.dt[r.ri]
726 end
727 c = c + 1
728 collected[c] = r
729 break
730 end
731 end
732 end
733 return c
734end
735
736local P, R, S, C, Cs, Ct, Cc, Carg, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Ct, lpeg.Cc, lpeg.Carg, lpeg.match
737
738local p_number = lpegpatterns.integer / tonumber
739
740local p_key = C((R("az","AZ","09") + S("_-"))^1)
741local p_left = S("#.[],:()")
742local p_right = S("#.[],:() ")
743local p_tag = C((1-p_left) * (1-p_right)^0)
744local p_value = C((1-P("]"))^0)
745local p_unquoted = (P('"')/"") * C((1-P('"'))^0) * (P('"')/"")
746 + (1-P("]"))^1
747local p_element = Ct( (
748 P(">") * skipspace * Cc(s_element_a) +
749 P("+") * skipspace * Cc(s_element_b) +
750 P("~") * skipspace * Cc(s_element_c) +
751 Cc(s_element_d)
752 ) * p_tag )
753local p_attribute = P("[") * Ct(Cc(s_attribute) * p_key * (
754 P("=" ) * Cc(1) * Cs( p_unquoted)
755 + P("^=") * Cc(2) * Cs(Cc("^") * (p_unquoted / topattern))
756 + P("$=") * Cc(2) * Cs( p_unquoted / topattern * Cc("$"))
757 + P("*=") * Cc(2) * Cs( p_unquoted / topattern)
758 + P("~=") * Cc(3) * Cs( p_unquoted)
759 )^0 * P("]"))
760
761local p_separator = skipspace * P(",") * skipspace
762
763local p_formula = skipspace * P("(")
764 * skipspace
765 * (
766 p_number * skipspace * (C("n") * skipspace * (p_number + Cc(0)))^-1
767 + P("even") * Cc(0) * Cc("n") * Cc(2)
768 + P("odd") * Cc(-1) * Cc("n") * Cc(2)
769 )
770 * skipspace
771 * P(")")
772
773local p_step = P(".") * Ct(Cc(s_attribute) * Cc("class") * Cc(3) * p_tag)
774 + P("#") * Ct(Cc(s_attribute) * Cc("id") * Cc(1) * p_tag)
775 + p_attribute
776 + p_element
777 + P(":nth-child") * Ct(Cc(s_nth_child) * p_formula)
778 + P(":nth-last-child") * Ct(Cc(s_nth_last_child) * p_formula)
779 + P(":first-child") * Ct(Cc(s_nth_child) * Cc(1))
780 + P(":last-child") * Ct(Cc(s_nth_last_child) * Cc(1))
781 + P(":only-child") * Ct(Cc(s_only_child) )
782 + P(":nth-of-type") * Ct(Cc(s_nth_of_type) * p_formula)
783 + P(":nth-last-of-type") * Ct(Cc(s_nth_last_of_type) * p_formula)
784 + P(":first-of-type") * Ct(Cc(s_nth_of_type) * Cc(1))
785 + P(":last-of-type") * Ct(Cc(s_nth_last_of_type) * Cc(1))
786 + P(":only-of-type") * Ct(Cc(s_only_of_type) )
787 + P(":empty") * Ct(Cc(s_empty) )
788 + P(":root") * Ct(Cc(s_root) )
789
790local p_not = P(":not") * Cc(true) * skipspace * P("(") * skipspace * p_step * skipspace * P(")")
791local p_yes = Cc(false) * skipspace * p_step
792
793local p_stepper = Ct((skipspace * (p_not+p_yes))^1)
794local p_steps = Ct((p_stepper * p_separator^0)^1) * skipspace * (P(-1) + function() report_css("recovering from error") end)
795
796local cache = setmetatableindex(function(t,k)
797 local v = lpegmatch(p_steps,k) or false
798 t[k] = v
799 return v
800end)
801
802local function selector(root,s)
803
804 local steps = cache[s]
805 if steps then
806 local done = { }
807 local collected = { }
808 local nofcollected = 0
809 local nofsteps = #steps
810 for i=1,nofsteps do
811 local step = steps[i]
812 local n = #step
813 if n > 0 then
814 local r = root
815 local m = 0
816 local c = { }
817 for i=1,n,2 do
818 local s = step[i+1]
819 m = s[1](r,c,0,step[i],s[2],s[3],s[4])
820 if m == 0 then
821 break
822 else
823 r = c
824 c = { }
825 end
826 end
827 if m > 0 then
828 if nofsteps > 1 then
829 for i=1,m do
830 local ri = r[i]
831 if done[ri] then
832
833
834
835 else
836 nofcollected = nofcollected + 1
837 collected[nofcollected] = ri
838 done[ri] = true
839 end
840 end
841 else
842 return r
843 end
844 end
845 end
846 end
847 if nofcollected > 1 then
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866 local n = 0
867 local function traverse(dt)
868 for i=1,#dt do
869 local e = dt[i]
870 if done[e] then
871 n = n + 1
872 done[e] = n
873 if n == nofcollected then
874 return
875 end
876 end
877 local d = e.dt
878 if d then
879 traverse(d)
880 if n == nofcollected then
881 return
882 end
883 end
884 end
885 end
886 local r = root[1]
887 if done[r] then
888 n = n + 1
889 done[r] = n
890 end
891 traverse(r.dt)
892
893 sort(collected,function(a,b) return done[a] < done[b] end)
894 end
895 return collected
896 else
897 return { }
898 end
899end
900
901xml.applyselector= selector
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970function css.applyselector(x,str)
971
972 return applyselector({ x },str)
973end
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018local ctx_sprint = context.sprint
1019local ctx_xmlvalue = context.xmlvalue
1020
1021local colon = P(":")
1022local semicolon = P(";")
1023local eos = P(-1)
1024local somevalue = (1 - (skipspace * (semicolon + eos)))^1
1025local someaction = skipspace * colon * skipspace * (somevalue/ctx_sprint)
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036local patterns = setmetatableindex(function(t,k)
1037 local v = P(k * someaction + 1)^0
1038 t[k] = v
1039 return v
1040end)
1041
1042function css.stylevalue(root,name)
1043 local list = getid(root).at.style
1044 if list then
1045 lpegmatch(patterns[name],list)
1046 end
1047end
1048
1049local somevalue = (1 - whitespace - semicolon - eos)^1
1050local someaction = skipspace * colon * (skipspace * Carg(1) * C(somevalue)/function(m,s)
1051 ctx_xmlvalue(m,s,"")
1052end)^1
1053
1054local patterns= setmetatableindex(function(t,k)
1055 local v = P(k * someaction + 1)^0
1056 t[k] = v
1057 return v
1058end)
1059
1060function css.mappedstylevalue(root,map,name)
1061 local list = getid(root).at.style
1062 if list then
1063 lpegmatch(patterns[name],list,1,map)
1064 end
1065end
1066
1067
1068
1069interfaces.implement {
1070 name = "xmlcssstylevalue",
1071 public = true,
1072 actions = css.stylevalue,
1073 arguments = "2 strings",
1074}
1075
1076interfaces.implement {
1077 name = "xmlcssmappedstylevalue",
1078 public = true,
1079 actions = css.mappedstylevalue,
1080 arguments = "3 strings",
1081}
1082
1083
1084
1085local containsws = string.containsws
1086local classsplitter = lpeg.tsplitat(whitespace^1)
1087
1088function xml.functions.classes(e,class)
1089 if class then
1090 local at = e.at
1091 local data = at[class] or at.class
1092 if data then
1093 return lpegmatch(classsplitter,data) or { }
1094 end
1095 end
1096 return { }
1097end
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117function xml.functions.hasclass(e,class,name,more,...)
1118 if class and name then
1119 local at = e.at
1120 local data = at[class] or at.class
1121 if not data or data == "" then
1122 return false
1123 end
1124 if data == name or data == more then
1125 return true
1126 end
1127 if containsws(data,name) then
1128 return true
1129 end
1130 if not more then
1131 return false
1132 end
1133 if containsws(data,more) then
1134 return true
1135 end
1136 for i=1,select("#",...) do
1137 if containsws(data,select(i,...)) then
1138 return true
1139 end
1140 end
1141 end
1142 return false
1143end
1144
1145function xml.expressions.hasclass(data,name,more,...)
1146 if data then
1147 if not data or data == "" then
1148 return false
1149 end
1150 if data == name or data == more then
1151 return true
1152 end
1153 if containsws(data,name) then
1154 return true
1155 end
1156 if not more then
1157 return false
1158 end
1159 if containsws(data,more) then
1160 return true
1161 end
1162 for i=1,select("#",...) do
1163 if containsws(data,select(i,...)) then
1164 return true
1165 end
1166 end
1167 end
1168 return false
1169end
1170 |