1 // SemiTwist Library
2 // Written in the D programming language.
3 //
4 // Helper tools for the arsd DOM module at: 
5 // https://github.com/adamdruppe/arsd/blob/master/dom.d
6 
7 module semitwist.arsddom;
8 
9 import std.string;
10 import arsd.dom;
11 
12 void deactivateLink(Element link)
13 {
14 	link.removeAttribute("href");
15 	link.className = "inactive-link";
16 	link.tagName = "span";
17 }
18 
19 void removeAll(Element elem, string selector)
20 {
21 	foreach(ref elemToRemove; elem.getElementsBySelector(selector))
22 		elemToRemove.outerHTML = "";
23 }
24 
25 void setAttributes(Element elem, string[string] attributes)
26 {
27 	if(attributes != null)
28 	{
29 		foreach(key, value; attributes)
30 		{
31 			if(key.toLower() == "class")
32 				elem.addClass(value);
33 			else if(key.toLower() == "style")
34 				elem.style ~= value;
35 			else
36 				elem.setAttribute(key, value);
37 		}
38 	}
39 }
40 
41 /++
42 Sample usage:
43 
44 	struct Foo {
45 		int i; string s;
46 	}
47 
48 	auto doc = new Document("
49 		<body>
50 			<h1>Foo:</h1>
51 			<div class="foo">
52 				<h2 class=".foo-int">(placeholder)</h2>
53 				<p class=".foo-str">(placeholder)</p>
54 				<hr />
55 			</div>
56 		</body>
57 		", true, true);
58 
59 	fill!(Foo[])(
60 		doc.requireSelector(".foo"),
61 		[Foo(10,"abc"), Foo(20,"def")],
62 		(stamp, index, foo) {
63 			stamp.requireSelector(".foo-int").innerHTML = text("#", index, " ", foo.i);
64 			stamp.requireSelector(".foo-str").innerHTML = foo.s;
65 			return stamp;
66 		}
67 	)
68 	
69 	/+
70 	Result:
71 		<body>
72 			<h1>Foo:</h1>
73 			<div class="foo">
74 				<h2 class=".foo-int">#0: 10</h2>
75 				<p class=".foo-str">abc</p>
76 				<hr />
77 			</div>
78 			<div class="foo">
79 				<h2 class=".foo-int">#1: 20</h2>
80 				<p class=".foo-str">def</p>
81 				<hr />
82 			</div>
83 		</body>
84 	+/
85 	writeln(doc);
86 +/
87 //TODO: fill() needs a way to do a plain old 0..x with no data
88 void fill(T)(
89 	Element elem, T collection,
90 	Element delegate(Element, size_t, ElementType!T) dg
91 ) if(isInputRange!T)
92 {
93 	auto elemTemplate = elem.cloned;
94 	string finalHtml;
95 	for(size_t i=0; !collection.empty; i++)
96 	{
97 		auto stamp = elemTemplate.cloned;
98 		auto newElem = dg(stamp, i, collection.front);
99 		finalHtml ~= newElem.toString();
100 		collection.popFront();
101 	}
102 	elem.outerHTML = finalHtml;
103 }
104 
105 class MissingHtmlAttributeException : Exception
106 {
107 	Element elem;
108 	string attrName;
109 	string htmlFileName;
110 	
111 	this(string file=__FILE__, size_t line=__LINE__)(Element elem, string attrName, string htmlFileName=null)
112 	{
113 		super("", file, line);
114 		setTo(elem, attrName, htmlFileName);
115 	}
116 	
117 	void setTo(Element elem, string attrName, string htmlFileName)
118 	{
119 		this.elem         = elem;
120 		this.attrName     = attrName;
121 		this.htmlFileName = htmlFileName;
122 
123 		auto msg = "Missing attribute '"~attrName~"' on <"~elem.tagName~"> element";
124 		if(htmlFileName != "")
125 			msg ~= " (in file '"~htmlFileName~"')";
126 		
127 		this.msg = msg;
128 	}
129 }
130 
131 string requireAttribute(Element elem, string name)
132 {
133 	auto value = elem.getAttribute(name);
134 	if(value == "")
135 		throw new MissingHtmlAttributeException(elem, name);
136 
137 	return value;
138 }