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