home readme diff tree note docs

0commit d9eef16adaf292f3748db5fb5aa98463de10d712
1Author: Mason Wright <mason@lakefox.net>
2Date:   Sun Jun 15 16:07:44 2025 -0600
3
4    Creates elements, figuring out how to implement attributes
5
6diff --git a/element.cc b/element.cc
7index 0593b32..ae1f1b4 100755
8--- a/element.cc
9+++ b/element.cc
10@@ -1,15 +1,12 @@
11 #include <string>
12-#include <print>
13 #include <vector>
14 #include <fstream>
15 #include <unordered_map>
16 #include <iostream>
17 #include <memory>
18 #include <cctype>
19-
20-#define GETTER_SETTER(type, name) \
21-    type get##name() const { return name; } \
22-    void set##name(type value) { name = value; }
23+#include <algorithm>
24+#include <stdexcept>
25 
26 struct Styles {
27 	std::vector<std::unordered_map<std::string, std::string>> stylesheets;
28@@ -35,15 +32,83 @@ struct State {
29 	int tabIndex;
30 };
31 
32+class ClassList {
33+	private:
34+		std::vector<std::string> values;
35+	public:
36+		std::string value() const {
37+			if (values.empty()) {
38+				return "";
39+			}
40+			std::string collection = values[0];
41+			for (size_t i = 1; i < values.size(); ++i) {
42+				collection += " " + values[i];
43+			}
44+			return collection;
45+		}
46+
47+		void add(std::string value) {
48+			values.push_back(value);
49+		}
50+
51+		void remove(std::string value) {
52+			auto it_prev = std::find(values.begin(), values.end(), value);
53+			if (it_prev != values.end()) {
54+				*it_prev = values.back(); // Overwrite prevous position with last element
55+				values.pop_back();          // Remove the last element
56+			}
57+		}
58+};
59+
60 class Node {
61 	private:
62 		std::string TagName;
63-		std::string Id;
64-		std::string InnerText;
65+		// !NOTE: ContentEditable only supports plaintext
66 		std::unordered_map<std::string, std::string> Attributes;
67+
68+		template<typename T>
69+			T stringToType(const std::string& s) const {
70+				// This should theoretically not be called if we have std::string overload
71+				// but acts as a fallback for unsupported types or as a reminder.
72+				static_assert(!std::is_same<T, T>::value, "stringToType not implemented for this type");
73+				return T(); // Should not reach here
74+			}
75+
76+		int stringToType(const std::string& s) const {
77+			try {
78+				return std::stoi(s);
79+			} catch (const std::invalid_argument& e) {
80+				std::cerr << "Warning: Invalid integer attribute value '" << s << "'. Defaulting to 0." << std::endl;
81+				return 0;
82+			} catch (const std::out_of_range& e) {
83+				std::cerr << "Warning: Integer attribute value '" << s << "' out of range. Defaulting to 0." << std::endl;
84+				return 0;
85+			}
86+		}
87+
88+		bool stringToType(const std::string& s) const {
89+			// For boolean attributes, presence means true, value might be "true" or ""
90+			// You decide the logic. Common HTML: attribute presence means true.
91+			// If your parser puts "false" in the map for contenteditable="false", then check "false"
92+			// If it puts "" for contenteditable, check for non-empty string.
93+			// My setAttribute for bool puts "" for true, and removes for false.
94+			// So, if the attribute is present, it's true.
95+			return true; // If attribute exists, it's considered true
96+				     // If you want to strictly parse "true"/"false" strings:
97+				     // return (s == "" || s == "true"); // Assuming empty string means true for boolean attribute
98+				     // return (s != "false" && !s.empty()); // If "false" explicitly means false
99+		}
100+
101+		// Add more overloads for other types like double, float, long, etc.
102+		double stringToType(const std::string& s) const {
103+			try {
104+				return std::stod(s);
105+			} catch (...) { /* error handling */ return 0.0; }
106+		}
107 	public:
108 		Node* parent;
109 		std::vector<std::unique_ptr<Node>> children;
110+		ClassList classList;
111 
112 		Node() : parent(nullptr) {}
113 
114@@ -55,21 +120,52 @@ class Node {
115 			return children.back().get();
116 		}
117 
118-		// Define the getters and setters for each private property
119-		GETTER_SETTER(std::string, TagName)
120-		GETTER_SETTER(std::string, Id)
121-		GETTER_SETTER(std::string, InnerText)
122 
123-		void setAttribute(std::string name, std::string value) {
124+		// --- Templated setAttribute ---
125+		// This will convert the given value (of any type T) to std::string
126+		template<typename T>
127+			void setAttribute(const std::string& name, const T& value) {
128+				Attributes[name] = std::to_string(value); // Default for numbers, bools need custom
129+			}
130+
131+		// Overload for std::string to avoid unnecessary conversion
132+		void setAttribute(const std::string& name, const std::string& value) {
133 			Attributes[name] = value;
134 		}
135 
136-		std::string getAttribute(std::string name) const { 
137+		// Overload for bool (custom serialization)
138+		void setAttribute(const std::string& name, bool value) {
139+			Attributes[name] = value ? "" : "false"; 
140+			if (value) {
141+				Attributes[name] = ""; // Attribute present with empty value typically means 'true'
142+			} else {
143+				// If value doesn't exist then remove it
144+				Attributes.erase(name);
145+			}
146+		}
147+
148+
149+		// --- Templated getAttribute ---
150+		// This will convert the string from the map to the desired type T
151+		template<typename T>
152+			T getAttribute(const std::string& name) const {
153+				auto it = Attributes.find(name);
154+				if (it != Attributes.end()) {
155+					// Need to convert it->second (std::string) to T
156+					// This requires a helper or std::from_chars/stoi/etc.
157+					return stringToType<T>(it->second);
158+				}
159+				// Fail return default constructor for T
160+				return T();
161+			}
162+
163+		// Overload for std::string directly
164+		std::string getAttribute(const std::string& name) const {
165 			auto it = Attributes.find(name);
166 			if (it != Attributes.end()) {
167 				return it->second;
168 			}
169-			return ""; // Return empty string if attribute not found
170+			return ""; // Default for string attributes if not found
171 		}
172 };
173 
174@@ -134,7 +230,7 @@ std::unordered_map<std::string, std::string> parseAttributes(std::vector<std::st
175 	return attrs;
176 }
177 
178-
179+// !TODO: Make a html string parser as well
180 std::unique_ptr<Node> parserdocument(std::string file) {
181 	std::ifstream inputFile(file);
182 
183@@ -154,23 +250,35 @@ std::unique_ptr<Node> parserdocument(std::string file) {
184 	bool escaped = false;
185 	bool inQuote = false;
186 	char quoteType = '"';
187-
188+	bool inClosing = false;
189 
190 	std::vector<std::string> tokens;
191 	std::string word = "";
192 
193 	while (std::getline(inputFile, line)) {
194-		println("{}", line);
195-
196 		int ll = line.length();
197 		for (unsigned short i = 0; i < ll; i++) {
198 			char current = line[i];
199-			
200+
201+			if (current == '/' && inTag) {
202+				currentNode = currentNode->parent;
203+				inClosing = true;
204+			}
205+
206+			// Hijack the closing skipping to skipp over comments
207+			if (current == '!' && inTag) {
208+				inClosing = true;
209+			}
210 			
211 			if (current == '>') {
212 				tokens.push_back(word);
213 				word = "";
214 				inTag = false;
215+				inClosing = false;
216+			}
217+
218+			if (inClosing) {
219+				continue;
220 			}
221 
222 			if (inTag) {
223@@ -209,7 +317,47 @@ std::unique_ptr<Node> parserdocument(std::string file) {
224 				currentNode = currentNode->createElement(tokens[0]);
225 				auto attrs = parseAttributes(tokens);
226 				for (auto const& pair : attrs) {
227-					std::cout << "Key: " << pair.first << ", Value: " << pair.second << std::endl;
228+					auto v = pair.second;
229+					// !TODO: Add all global attributes
230+					// + Src: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes
231+					if(pair.first == "id") {
232+						currentNode->setId(v);
233+					} else if (pair.first == "contentEditable") {
234+						if (v != "false") {
235+						}
236+						currentNode->setContentEditable(true);
237+					} else if (pair.first == "href") {
238+						currentNode->setHref(v);
239+					} else if (pair.first == "src") {
240+						currentNode->setSrc(v);
241+					} else if (pair.first == "title") {
242+						currentNode->setTitle(v);
243+					} else if (pair.first == "value") {
244+						currentNode->setValue(v);
245+					} else if (pair.first == "tabindex") {
246+						try {
247+							int tabindex = std::stoi(v);
248+							currentNode->setTabIndex(tabindex);
249+						} catch (const std::invalid_argument& e) {
250+							std::cerr << "Error converting \"" << v << "\": Invalid argument: \"tabindex\"=" << e.what() << std::endl;
251+						} catch (const std::out_of_range& e) {
252+							std::cerr << "Error converting \"" << v << "\": Out of range: \"tabindex\"=" << e.what() << std::endl;
253+						}
254+					} else if (pair.first == "disabled") {
255+						if (v != "false") {
256+							currentNode->setDisabled(true);
257+						}
258+					} else if (pair.first == "checked") {
259+						if (v != "false") {
260+							currentNode->setChecked(true);
261+						}
262+					} else if (pair.first == "required") {
263+						if (v != "false") {
264+							currentNode->setRequired(true);
265+						}
266+					} else {
267+						currentNode->setAttribute(pair.first, v);
268+					}
269 				}
270 
271 				tokens.clear();
272@@ -218,11 +366,12 @@ std::unique_ptr<Node> parserdocument(std::string file) {
273 		}
274 	}
275 
276-	for (auto t : tokens) {
277-		std::cout << t << std::endl;
278-	}
279-
280 	inputFile.close();
281+
282+
283+	std::cout << root->children.size() << std::endl;
284+	std::cout << root->children[0].get()->children[1].get()->getTagName() << std::endl;
285+
286 	return root;
287 }
288 
289diff --git a/index.html b/index.html
290index 0afb07f..1e8f67f 100644
291--- a/index.html
292+++ b/index.html
293@@ -3,4 +3,7 @@
294 	contentEditable
295 >
296 	hi
297+	<p>
298+		this is a test
299+	</p>
300 </html>
301diff --git a/main b/main
302index b48aa86..38a69b3 100755
303Binary files a/main and b/main differ