1 moduledhtags.attrs.define;
2 3 /**
4 * Define an html attribute with name and a list of types it accepts for its value.
5 */6 templateDefineAttrWithTypes(aliasname, TVal...) {
7 importdhtags.attrs.attribute : AttrPair, BoolAttribute;
8 importdhtags.utils.html;
9 importstd..string : format, replace, capitalize;
10 importstd.traits : isSomeString;
11 12 staticif (isSomeString!(typeof(name))) {
13 // If a single name is provided it will be both the attribute symbol and name14 enumattrSymbol = name.hyphenToCamelCase;
15 enumattrName = name;
16 } else {
17 // Otherwise assume an array or tuple (symbol, name) was provided18 enumattrSymbol = name[0].hyphenToCamelCase;
19 staticif (name.length > 1) { enumattrName = name[1]; }
20 else { enumattrName = attrSymbol; }
21 }
22 23 enumcapitalizedAttrSymbol = capitalize(attrSymbol);
24 25 /**
26 * Define an attribute that can be assigned to.
27 * e.g. 'struct IdAttr' for attribute 'id'
28 */29 mixin(format(q{
30 enum %1$s = %2$sAttr();
31 32 private struct %2$sAttr {
33 enum name = attrName;
34 alias TValues = TVal;
35 mixin DefineOpAssign;
36 }
37 }, attrSymbol, capitalizedAttrSymbol));
38 39 mixintemplateDefineOpAssign() {
40 /**
41 * Iterate through TVal tuple and define opAssign functions for all types for this attribute's value
42 */43 privatestaticstringdefineOpAssign(inti = 0)() {
44 staticif (i < TVal.length) {
45 // Check if TVal[i] is actually a literal value and if so we'll define a member to store it46 staticif (__traits(compiles, typeof(TVal[i]))) {
47 returnformat(q{
48 enum _allowedValue%1$d = asString!(TVal[%1$d]);
49 static if (!hasType!(typeof(TVal[%1$d]), %1$d + 1)) {
50 auto opAssign(typeof(TVal[%1$d]) value) {
51 return new AttrPair!(typeof(this), typeof(TVal[%1$d]))(name, value);
52 }
53 }
54 }, i) ~ defineOpAssign!(i + 1);
55 56 // Otherwise TVal is a type so define an opAssign function to allow a value of this type to be assigned to the attribute57 } else {
58 returnformat(q{
59 static if (!hasType!(TVal[%1$d], %1$d + 1)) {
60 auto opAssign(TVal[%1$d] value) {
61 return new AttrPair!(typeof(this), TVal[%1$d])(name, value);
62 }
63 }
64 65 static if ((is(TVal[%1$d] : BoolAttribute))) {
66 auto boolPair() {
67 return new AttrPair!(typeof(this), string)(name, name);
68 }
69 alias boolPair this;
70 }
71 }, i) ~ defineOpAssign!(i + 1);
72 }
73 } else { return""; }
74 }
75 76 mixin(defineOpAssign);
77 }
78 79 /**
80 * Helper function to check if TVal starting at index i and onwards has the type T
81 */82 boolhasType(T, inti)() {
83 staticif (i < TVal.length) {
84 staticif (__traits(compiles, typeof(TVal[i]))) {
85 return (is(typeof(TVal[i]) : T)) || hasType!(T, i + 1);
86 } else {
87 return (is(TVal[i] : T)) || hasType!(T, i + 1);
88 }
89 } else {
90 returnfalse;
91 }
92 }
93 }
94 95 /**
96 * Helper template to ensure all attributes can take values of type string.
97 */98 templateDefineAttr(aliasname, TVal...) {
99 importdhtags.attrs.define : DefineAttrWithTypes;
100 mixinDefineAttrWithTypes!(name, string, TVal);
101 }
102 103 /**
104 * Define a boolean html attribute with name and additional list of values.
105 * If present, the attribute's value will be rendered as an exact match of the attribute's name.
106 */107 templateDefineBooleanAttr(aliasname, TVal...) {
108 importdhtags.attrs.attribute : BoolAttribute;
109 importdhtags.attrs.define : DefineAttr;
110 mixinDefineAttr!(name, BoolAttribute, TVal);
111 }