Diff
diff --git a/docs/gui/index.html b/docs/gui/index.html
index 61e1cfe..b6b45d2 100644
--- a/docs/gui/index.html
+++ b/docs/gui/index.html
@@ -42,190 +42,190 @@
- 5 "bytes"
- 6 "crypto/sha256"
- 7 _ "embed"
- 8 "encoding/json"
- 9 "fmt"
- 10 "gui/cstyle"
- 11 "gui/cstyle/plugins/flex"
- 12 "gui/cstyle/plugins/inline"
- 13 "gui/cstyle/plugins/textAlign"
- 14 "gui/cstyle/transformers/text"
- 15 "gui/window"
- 16 "time"
- 17
- 18 "gui/element"
- 19 "gui/events"
- 20 "gui/utils"
- 21 "net/url"
- 22 "os"
- 23 "path/filepath"
- 24 "regexp"
- 25 "strconv"
- 26 "strings"
- 27
- 28 rl "github.com/gen2brain/raylib-go/raylib"
- 29 "golang.org/x/net/html"
- 30)
- 31
- 32// _ "net/http/pprof"
- 33
- 34//go:embed master.css
- 35var mastercss string
- 36
- 37type Window struct {
- 38 CSS cstyle.CSS
- 39 Document element.Node
- 40 Adapter func()
- 41}
- 42
- 43func Open(path string) Window {
- 44 window := New()
- 45
- 46 styleSheets, styleTags, htmlNodes := parseHTMLFromFile(path)
- 47
- 48 for _, v := range styleSheets {
- 49 window.CSS.StyleSheet(v)
- 50 }
- 51
- 52 for _, v := range styleTags {
- 53 window.CSS.StyleTag(v)
- 54 }
- 55
- 56 CreateNode(htmlNodes, &window.Document)
- 57
- 58 return window
- 59}
- 60
- 61func New() Window {
- 62 css := cstyle.CSS{
- 63 Width: 800,
- 64 Height: 450,
- 65 }
- 66
- 67 css.StyleTag(mastercss)
- 68 // This is still apart of computestyle
- 69 // css.AddPlugin(position.Init())
- 70 css.AddPlugin(inline.Init())
- 71 // css.AddPlugin(block.Init())
- 72 css.AddPlugin(textAlign.Init())
- 73 // css.AddPlugin(inlineText.Init())
- 74 css.AddPlugin(flex.Init())
- 75
- 76 css.AddTransformer(text.Init())
- 77
- 78 el := element.Node{}
- 79 document := el.CreateElement("ROOT")
- 80 document.Style["width"] = "800px"
- 81 document.Style["height"] = "450px"
- 82 document.Properties.Id = "ROOT"
- 83 return Window{
- 84 CSS: css,
- 85 Document: document,
- 86 }
- 87}
- 88
- 89func (w *Window) Render(doc element.Node, state *map[string]element.State) []element.State {
- 90 s := *state
- 91
- 92 flatDoc := flatten(doc)
- 93
- 94 store := []element.State{}
- 95
- 96 keys := []string{}
- 97
- 98 for _, v := range flatDoc {
- 99 store = append(store, s[v.Properties.Id])
-100 keys = append(keys, v.Properties.Id)
-101 }
-102
-103 // Create a set of keys to keep
-104 keysSet := make(map[string]struct{}, len(keys))
-105 for _, key := range keys {
-106 keysSet[key] = struct{}{}
-107 }
-108
-109 // Iterate over the map and delete keys not in the set
-110 for k := range s {
-111 if _, found := keysSet[k]; !found {
-112 delete(s, k)
-113 }
-114 }
-115
-116 return store
-117}
-118
-119func flatten(n element.Node) []element.Node {
-120 var nodes []element.Node
-121 nodes = append(nodes, n)
-122
-123 children := n.Children
-124 if len(children) > 0 {
-125 for _, ch := range children {
-126 chNodes := flatten(ch)
-127 nodes = append(nodes, chNodes...)
-128 }
-129 }
-130 return nodes
-131}
-132
-133func View(data *Window, width, height int32) {
-134 debug := false
-135 data.Document.Style["width"] = strconv.Itoa(int(width)) + "px"
-136 data.Document.Style["height"] = strconv.Itoa(int(height)) + "px"
-137
-138 wm := window.NewWindowManager()
-139 wm.FPSCounterOn = true
-140
-141 wm.OpenWindow(width, height)
-142 defer wm.CloseWindow()
-143
-144 evts := map[string]element.EventList{}
-145
-146 eventStore := &evts
-147
-148 state := map[string]element.State{}
-149
-150 shouldStop := false
-151
-152 var hash []byte
-153 var rd []element.State
-154
-155 lastChange := time.Now()
-156
-157 // Main game loop
-158 for !wm.WindowShouldClose() && !shouldStop {
-159 // fmt.Println("######################")
-160 rl.BeginDrawing()
-161 if !shouldStop && debug {
-162 shouldStop = true
-163 }
-164 // Check if the window size has changed
-165 newWidth := int32(rl.GetScreenWidth())
-166 newHeight := int32(rl.GetScreenHeight())
-167
-168 resize := false
-169
-170 if newWidth != width || newHeight != height {
-171 resize = true
-172 rl.ClearBackground(rl.RayWhite)
-173 // Window has been resized, handle the event
-174 width = newWidth
-175 height = newHeight
-176
-177 data.CSS.Width = float32(width)
-178 data.CSS.Height = float32(height)
-179
-180 data.Document.Style["width"] = strconv.Itoa(int(width)) + "px"
-181 data.Document.Style["height"] = strconv.Itoa(int(height)) + "px"
-182 }
-183
-184 newHash, _ := hashStruct(&data.Document.Children[0])
-185 eventStore = events.GetEvents(&data.Document.Children[0], &state, eventStore)
-186 if !bytes.Equal(hash, newHash) || resize {
-187 if wm.FPS != 30 {
-188 wm.SetFPS(30)
-189 }
-190 lastChange = time.Now()
-191 hash = newHash
-192 newDoc := CopyNode(data.CSS, data.Document.Children[0], &data.Document)
-193
-194 newDoc = data.CSS.Transform(newDoc)
+ 5 "crypto/sha256"
+ 6 _ "embed"
+ 7 "encoding/json"
+ 8 "fmt"
+ 9 "gui/cstyle"
+ 10 "gui/cstyle/plugins/flex"
+ 11 "gui/cstyle/plugins/inline"
+ 12 "gui/cstyle/plugins/textAlign"
+ 13 "gui/cstyle/transformers/text"
+ 14 "gui/window"
+ 15 "time"
+ 16
+ 17 "gui/element"
+ 18 "gui/events"
+ 19 "gui/utils"
+ 20 "net/url"
+ 21 "os"
+ 22 "path/filepath"
+ 23 "regexp"
+ 24 "strconv"
+ 25 "strings"
+ 26
+ 27 rl "github.com/gen2brain/raylib-go/raylib"
+ 28 "golang.org/x/net/html"
+ 29)
+ 30
+ 31// _ "net/http/pprof"
+ 32
+ 33//go:embed master.css
+ 34var mastercss string
+ 35
+ 36type Window struct {
+ 37 CSS cstyle.CSS
+ 38 Document element.Node
+ 39 Adapter func()
+ 40}
+ 41
+ 42func Open(path string) Window {
+ 43 window := New()
+ 44
+ 45 styleSheets, styleTags, htmlNodes := parseHTMLFromFile(path)
+ 46
+ 47 for _, v := range styleSheets {
+ 48 window.CSS.StyleSheet(v)
+ 49 }
+ 50
+ 51 for _, v := range styleTags {
+ 52 window.CSS.StyleTag(v)
+ 53 }
+ 54
+ 55 CreateNode(htmlNodes, &window.Document)
+ 56
+ 57 return window
+ 58}
+ 59
+ 60func New() Window {
+ 61 css := cstyle.CSS{
+ 62 Width: 800,
+ 63 Height: 450,
+ 64 }
+ 65
+ 66 css.StyleTag(mastercss)
+ 67 // This is still apart of computestyle
+ 68 // css.AddPlugin(position.Init())
+ 69 css.AddPlugin(inline.Init())
+ 70 // css.AddPlugin(block.Init())
+ 71 css.AddPlugin(textAlign.Init())
+ 72 // css.AddPlugin(inlineText.Init())
+ 73 css.AddPlugin(flex.Init())
+ 74
+ 75 css.AddTransformer(text.Init())
+ 76
+ 77 el := element.Node{}
+ 78 document := el.CreateElement("ROOT")
+ 79 document.Style["width"] = "800px"
+ 80 document.Style["height"] = "450px"
+ 81 document.Properties.Id = "ROOT"
+ 82 return Window{
+ 83 CSS: css,
+ 84 Document: document,
+ 85 }
+ 86}
+ 87
+ 88func (w *Window) Render(doc element.Node, state *map[string]element.State) []element.State {
+ 89 s := *state
+ 90
+ 91 flatDoc := flatten(doc)
+ 92
+ 93 store := []element.State{}
+ 94
+ 95 keys := []string{}
+ 96
+ 97 for _, v := range flatDoc {
+ 98 store = append(store, s[v.Properties.Id])
+ 99 keys = append(keys, v.Properties.Id)
+100 }
+101
+102 // Create a set of keys to keep
+103 keysSet := make(map[string]struct{}, len(keys))
+104 for _, key := range keys {
+105 keysSet[key] = struct{}{}
+106 }
+107
+108 // Iterate over the map and delete keys not in the set
+109 for k := range s {
+110 if _, found := keysSet[k]; !found {
+111 delete(s, k)
+112 }
+113 }
+114
+115 return store
+116}
+117
+118func flatten(n element.Node) []element.Node {
+119 var nodes []element.Node
+120 nodes = append(nodes, n)
+121
+122 children := n.Children
+123 if len(children) > 0 {
+124 for _, ch := range children {
+125 chNodes := flatten(ch)
+126 nodes = append(nodes, chNodes...)
+127 }
+128 }
+129 return nodes
+130}
+131
+132func View(data *Window, width, height int32) {
+133 debug := false
+134 data.Document.Style["width"] = strconv.Itoa(int(width)) + "px"
+135 data.Document.Style["height"] = strconv.Itoa(int(height)) + "px"
+136
+137 wm := window.NewWindowManager()
+138 wm.FPSCounterOn = true
+139
+140 wm.OpenWindow(width, height)
+141 defer wm.CloseWindow()
+142
+143 evts := map[string]element.EventList{}
+144
+145 eventStore := &evts
+146
+147 state := map[string]element.State{}
+148
+149 shouldStop := false
+150
+151 // var hash []byte
+152 var rd []element.State
+153
+154 lastChange := time.Now()
+155
+156 // Main game loop
+157 for !wm.WindowShouldClose() && !shouldStop {
+158 // fmt.Println("######################")
+159 rl.BeginDrawing()
+160 if !shouldStop && debug {
+161 shouldStop = true
+162 }
+163 // Check if the window size has changed
+164 newWidth := int32(rl.GetScreenWidth())
+165 newHeight := int32(rl.GetScreenHeight())
+166
+167 resize := false
+168
+169 if newWidth != width || newHeight != height {
+170 resize = true
+171 rl.ClearBackground(rl.RayWhite)
+172 // Window has been resized, handle the event
+173 width = newWidth
+174 height = newHeight
+175
+176 data.CSS.Width = float32(width)
+177 data.CSS.Height = float32(height)
+178
+179 data.Document.Style["width"] = strconv.Itoa(int(width)) + "px"
+180 data.Document.Style["height"] = strconv.Itoa(int(height)) + "px"
+181 }
+182
+183 // newHash, _ := hashStruct(&data.Document.Children[0])
+184 eventStore = events.GetEvents(&data.Document.Children[0], &state, eventStore)
+185 for _, v := range *eventStore {
+186 if v.Event.MouseOver {
+187
+188 if v.Event.Target.TagName == "body" || v.Event.Target.TagName == "html" {
+189 continue
+190 } else {
+191 w := state[v.Event.Target.Properties.Id].Width
+192 h := state[v.Event.Target.Properties.Id].Height
+193 x := state[v.Event.Target.Properties.Id].X
+194 y := state[v.Event.Target.Properties.Id].Y
@@ -233,55 +233,55 @@
-196 data.CSS.ComputeNodeStyle(&newDoc, &state)
-197 rd = data.Render(newDoc, &state)
-198 wm.LoadTextures(rd)
-199
-200 // AddHTML(&newDoc)
-201 // fmt.Println(newDoc.QuerySelector("body").InnerHTML)
-202
-203 AddHTML(&data.Document)
-204 fmt.Println(time.Since(lastChange))
-205 }
-206 wm.Draw(rd)
-207
-208 // could use a return value that indicates whether or not a event has ran to ramp/deramp fps based on activity
-209
-210 events.RunEvents(eventStore)
-211 // ran := events.RunEvents(eventStore)
-212
-213 if time.Since(lastChange) > 5*time.Second {
-214 if wm.FPS != 1 {
-215 wm.SetFPS(1)
-216 }
-217 }
-218
-219 rl.EndDrawing()
-220 }
-221}
-222
-223func CopyNode(c cstyle.CSS, node element.Node, parent *element.Node) element.Node {
-224 n := element.Node{}
-225 n.TagName = node.TagName
-226 n.InnerText = node.InnerText
-227 n.Style = node.Style
-228 n.Id = node.Id
-229 n.ClassList = node.ClassList
-230 n.Href = node.Href
-231 n.Src = node.Src
-232 n.Title = node.Title
-233 n.Attribute = node.Attribute
-234 n.Value = node.Value
-235 n.ScrollY = node.ScrollY
-236 n.InnerHTML = node.InnerHTML
-237 n.OuterHTML = node.OuterHTML
-238 n.Properties.Id = node.Properties.Id
-239 n.Properties.Focusable = node.Properties.Focusable
-240 n.Properties.Focused = node.Properties.Focused
-241 n.Properties.Editable = node.Properties.Editable
-242 n.Properties.Hover = node.Properties.Hover
-243 n.Properties.Selected = node.Properties.Selected
-244
-245 n.Parent = parent
-246
-247 n.Style = c.GetStyles(n)
-248
-249 for _, v := range node.Children {
-250 n.Children = append(n.Children, CopyNode(c, v, &n))
+196 el := getElementByPropId(&data.Document.Children[0], v.Event.Target.Properties.Id)
+197
+198 if el != nil {
+199 data.CSS.ComputeNodeStyle(el, &state)
+200
+201 if w != state[v.Event.Target.Properties.Id].Width &&
+202 h != state[v.Event.Target.Properties.Id].Height &&
+203 x != state[v.Event.Target.Properties.Id].X &&
+204 y != state[v.Event.Target.Properties.Id].Y {
+205 fmt.Println("RELOAD")
+206 } else {
+207 fmt.Println("SWAP")
+208 }
+209
+210 }
+211
+212 }
+213
+214 }
+215
+216 }
+217 if resize {
+218 if wm.FPS != 30 {
+219 wm.SetFPS(30)
+220 }
+221 lastChange = time.Now()
+222 // hash = newHash
+223 newDoc := CopyNode(data.CSS, data.Document.Children[0], &data.Document)
+224
+225 newDoc = data.CSS.Transform(newDoc)
+226
+227 data.CSS.ComputeNodeStyle(&newDoc, &state)
+228 rd = data.Render(newDoc, &state)
+229 wm.LoadTextures(rd)
+230
+231 // AddHTML(&newDoc)
+232 // fmt.Println(newDoc.QuerySelector("body").InnerHTML)
+233
+234 AddHTML(&data.Document)
+235 fmt.Println(time.Since(lastChange))
+236 }
+237 wm.Draw(rd)
+238
+239 // could use a return value that indicates whether or not a event has ran to ramp/deramp fps based on activity
+240
+241 events.RunEvents(eventStore)
+242 // ran := events.RunEvents(eventStore)
+243
+244 if time.Since(lastChange) > 5*time.Second {
+245 if wm.FPS != 1 {
+246 wm.SetFPS(1)
+247 }
+248 }
+249
+250 rl.EndDrawing()
@@ -289,84 +289,84 @@
-252 return n
-253}
-254
-255func CreateNode(node *html.Node, parent *element.Node) {
-256 if node.Type == html.ElementNode {
-257 newNode := parent.CreateElement(node.Data)
-258 for _, attr := range node.Attr {
-259 if attr.Key == "class" {
-260 classes := strings.Split(attr.Val, " ")
-261 for _, class := range classes {
-262 newNode.ClassList.Add(class)
-263 }
-264 } else if attr.Key == "id" {
-265 newNode.Id = attr.Val
-266 } else if attr.Key == "contenteditable" && (attr.Val == "" || attr.Val == "true") {
-267 newNode.Properties.Editable = true
-268 } else if attr.Key == "href" {
-269 newNode.Href = attr.Val
-270 } else if attr.Key == "src" {
-271 newNode.Src = attr.Val
-272 } else if attr.Key == "title" {
-273 newNode.Title = attr.Val
-274 } else {
-275 newNode.SetAttribute(attr.Key, attr.Val)
-276 }
-277 }
-278 newNode.InnerText = strings.TrimSpace(utils.GetInnerText(node))
-279 // Recursively traverse child nodes
-280 for child := node.FirstChild; child != nil; child = child.NextSibling {
-281 if child.Type == html.ElementNode {
-282 CreateNode(child, &newNode)
-283 }
-284 }
-285 parent.AppendChild(newNode)
-286
-287 } else {
-288 for child := node.FirstChild; child != nil; child = child.NextSibling {
-289 if child.Type == html.ElementNode {
-290 CreateNode(child, parent)
-291 }
-292 }
-293 }
-294}
-295
-296func AddHTML(n *element.Node) {
-297 // Head is not renderable
-298 n.InnerHTML = utils.InnerHTML(*n)
-299 tag, closing := utils.NodeToHTML(*n)
-300 n.OuterHTML = tag + n.InnerHTML + closing
-301 for i := range n.Children {
-302 AddHTML(&n.Children[i])
-303 }
-304}
-305
-306func parseHTMLFromFile(path string) ([]string, []string, *html.Node) {
-307 file, _ := os.Open(path)
-308 defer file.Close()
-309
-310 scanner := bufio.NewScanner(file)
-311 var htmlContent string
-312
-313 for scanner.Scan() {
-314 htmlContent += scanner.Text() + "\n"
-315 }
-316
-317 htmlContent = removeHTMLComments(htmlContent)
-318
-319 doc, _ := html.Parse(strings.NewReader(encapsulateText(removeWhitespaceBetweenTags(htmlContent))))
-320
-321 // Extract stylesheet link tags and style tags
-322 stylesheets := extractStylesheets(doc, filepath.Dir(path))
-323 styleTags := extractStyleTags(doc)
-324
-325 return stylesheets, styleTags, doc
-326}
-327
-328func extractStylesheets(n *html.Node, baseDir string) []string {
-329 var stylesheets []string
-330
-331 var dfs func(*html.Node)
-332 dfs = func(node *html.Node) {
-333 if node.Type == html.ElementNode && node.Data == "link" {
-334 var href string
-335 isStylesheet := false
+252}
+253
+254func CopyNode(c cstyle.CSS, node element.Node, parent *element.Node) element.Node {
+255 n := element.Node{}
+256 n.TagName = node.TagName
+257 n.InnerText = node.InnerText
+258 n.Style = node.Style
+259 n.Id = node.Id
+260 n.ClassList = node.ClassList
+261 n.Href = node.Href
+262 n.Src = node.Src
+263 n.Title = node.Title
+264 n.Attribute = node.Attribute
+265 n.Value = node.Value
+266 n.ScrollY = node.ScrollY
+267 n.InnerHTML = node.InnerHTML
+268 n.OuterHTML = node.OuterHTML
+269 n.Properties.Id = node.Properties.Id
+270 n.Properties.Focusable = node.Properties.Focusable
+271 n.Properties.Focused = node.Properties.Focused
+272 n.Properties.Editable = node.Properties.Editable
+273 n.Properties.Hover = node.Properties.Hover
+274 n.Properties.Selected = node.Properties.Selected
+275
+276 n.Parent = parent
+277
+278 n.Style = c.GetStyles(n)
+279
+280 for _, v := range node.Children {
+281 n.Children = append(n.Children, CopyNode(c, v, &n))
+282 }
+283 return n
+284}
+285
+286func CreateNode(node *html.Node, parent *element.Node) {
+287 if node.Type == html.ElementNode {
+288 newNode := parent.CreateElement(node.Data)
+289 for _, attr := range node.Attr {
+290 if attr.Key == "class" {
+291 classes := strings.Split(attr.Val, " ")
+292 for _, class := range classes {
+293 newNode.ClassList.Add(class)
+294 }
+295 } else if attr.Key == "id" {
+296 newNode.Id = attr.Val
+297 } else if attr.Key == "contenteditable" && (attr.Val == "" || attr.Val == "true") {
+298 newNode.Properties.Editable = true
+299 } else if attr.Key == "href" {
+300 newNode.Href = attr.Val
+301 } else if attr.Key == "src" {
+302 newNode.Src = attr.Val
+303 } else if attr.Key == "title" {
+304 newNode.Title = attr.Val
+305 } else {
+306 newNode.SetAttribute(attr.Key, attr.Val)
+307 }
+308 }
+309 newNode.InnerText = strings.TrimSpace(utils.GetInnerText(node))
+310 // Recursively traverse child nodes
+311 for child := node.FirstChild; child != nil; child = child.NextSibling {
+312 if child.Type == html.ElementNode {
+313 CreateNode(child, &newNode)
+314 }
+315 }
+316 parent.AppendChild(newNode)
+317
+318 } else {
+319 for child := node.FirstChild; child != nil; child = child.NextSibling {
+320 if child.Type == html.ElementNode {
+321 CreateNode(child, parent)
+322 }
+323 }
+324 }
+325}
+326
+327func AddHTML(n *element.Node) {
+328 // Head is not renderable
+329 n.InnerHTML = utils.InnerHTML(*n)
+330 tag, closing := utils.NodeToHTML(*n)
+331 n.OuterHTML = tag + n.InnerHTML + closing
+332 for i := range n.Children {
+333 AddHTML(&n.Children[i])
+334 }
+335}
@@ -374,18 +374,18 @@
-337 for _, attr := range node.Attr {
-338 if attr.Key == "rel" && attr.Val == "stylesheet" {
-339 isStylesheet = true
-340 } else if attr.Key == "href" {
-341 href = attr.Val
-342 }
-343 }
-344
-345 if isStylesheet {
-346 resolvedHref := localizePath(baseDir, href)
-347 stylesheets = append(stylesheets, resolvedHref)
-348 }
-349 }
-350
-351 for c := node.FirstChild; c != nil; c = c.NextSibling {
-352 dfs(c)
-353 }
-354 }
+337func parseHTMLFromFile(path string) ([]string, []string, *html.Node) {
+338 file, _ := os.Open(path)
+339 defer file.Close()
+340
+341 scanner := bufio.NewScanner(file)
+342 var htmlContent string
+343
+344 for scanner.Scan() {
+345 htmlContent += scanner.Text() + "\n"
+346 }
+347
+348 htmlContent = removeHTMLComments(htmlContent)
+349
+350 doc, _ := html.Parse(strings.NewReader(encapsulateText(removeWhitespaceBetweenTags(htmlContent))))
+351
+352 // Extract stylesheet link tags and style tags
+353 stylesheets := extractStylesheets(doc, filepath.Dir(path))
+354 styleTags := extractStyleTags(doc)
@@ -393,34 +393,34 @@
-356 dfs(n)
-357 return stylesheets
-358}
-359
-360func extractStyleTags(n *html.Node) []string {
-361 var styleTags []string
-362
-363 var dfs func(*html.Node)
-364 dfs = func(node *html.Node) {
-365 if node.Type == html.ElementNode && node.Data == "style" {
-366 var styleContent strings.Builder
-367 for c := node.FirstChild; c != nil; c = c.NextSibling {
-368 if c.Type == html.TextNode {
-369 styleContent.WriteString(c.Data)
-370 }
-371 }
-372 styleTags = append(styleTags, styleContent.String())
-373 }
-374
-375 for c := node.FirstChild; c != nil; c = c.NextSibling {
-376 dfs(c)
-377 }
-378 }
-379
-380 dfs(n)
-381 return styleTags
-382}
-383
-384func localizePath(rootPath, filePath string) string {
-385 // Check if the file path has a scheme, indicating it's a URL
-386 u, err := url.Parse(filePath)
-387 if err == nil && u.Scheme != "" {
-388 return filePath
-389 }
+356 return stylesheets, styleTags, doc
+357}
+358
+359func extractStylesheets(n *html.Node, baseDir string) []string {
+360 var stylesheets []string
+361
+362 var dfs func(*html.Node)
+363 dfs = func(node *html.Node) {
+364 if node.Type == html.ElementNode && node.Data == "link" {
+365 var href string
+366 isStylesheet := false
+367
+368 for _, attr := range node.Attr {
+369 if attr.Key == "rel" && attr.Val == "stylesheet" {
+370 isStylesheet = true
+371 } else if attr.Key == "href" {
+372 href = attr.Val
+373 }
+374 }
+375
+376 if isStylesheet {
+377 resolvedHref := localizePath(baseDir, href)
+378 stylesheets = append(stylesheets, resolvedHref)
+379 }
+380 }
+381
+382 for c := node.FirstChild; c != nil; c = c.NextSibling {
+383 dfs(c)
+384 }
+385 }
+386
+387 dfs(n)
+388 return stylesheets
+389}
@@ -428,2 +428,2 @@
-391 // Join the root path and the file path to create an absolute path
-392 absPath := filepath.Join(rootPath, filePath)
+391func extractStyleTags(n *html.Node) []string {
+392 var styleTags []string
@@ -431,30 +431,30 @@
-394 // If the absolute path is the same as the original path, return it
-395 if absPath == filePath {
-396 return filePath
-397 }
-398
-399 return "./" + absPath
-400}
-401
-402func encapsulateText(htmlString string) string {
-403 openOpen := regexp.MustCompile(`(<\w+[^>]*>)([^<]+)(<\w+[^>]*>)`)
-404 closeOpen := regexp.MustCompile(`(</\w+[^>]*>)([^<]+)(<\w+[^>]*>)`)
-405 closeClose := regexp.MustCompile(`(<\/\w+[^>]*>)([^<]+)(<\/\w+[^>]*>)`)
-406 a := matchFactory(openOpen)
-407 t := openOpen.ReplaceAllStringFunc(htmlString, a)
-408 // fmt.Println(t)
-409 b := matchFactory(closeOpen)
-410 u := closeOpen.ReplaceAllStringFunc(t, b)
-411 // fmt.Println(u)
-412 c := matchFactory(closeClose)
-413 v := closeClose.ReplaceAllStringFunc(u, c)
-414 // fmt.Println(v)
-415 return v
-416}
-417
-418func matchFactory(re *regexp.Regexp) func(string) string {
-419 return func(match string) string {
-420 submatches := re.FindStringSubmatch(match)
-421 if len(submatches) != 4 {
-422 return match
-423 }
+394 var dfs func(*html.Node)
+395 dfs = func(node *html.Node) {
+396 if node.Type == html.ElementNode && node.Data == "style" {
+397 var styleContent strings.Builder
+398 for c := node.FirstChild; c != nil; c = c.NextSibling {
+399 if c.Type == html.TextNode {
+400 styleContent.WriteString(c.Data)
+401 }
+402 }
+403 styleTags = append(styleTags, styleContent.String())
+404 }
+405
+406 for c := node.FirstChild; c != nil; c = c.NextSibling {
+407 dfs(c)
+408 }
+409 }
+410
+411 dfs(n)
+412 return styleTags
+413}
+414
+415func localizePath(rootPath, filePath string) string {
+416 // Check if the file path has a scheme, indicating it's a URL
+417 u, err := url.Parse(filePath)
+418 if err == nil && u.Scheme != "" {
+419 return filePath
+420 }
+421
+422 // Join the root path and the file path to create an absolute path
+423 absPath := filepath.Join(rootPath, filePath)
@@ -462,22 +462,22 @@
-425 // Process submatches
-426 if len(removeWhitespace(submatches[2])) > 0 {
-427 return submatches[1] + "<notaspan>" + submatches[2] + "</notaspan>" + submatches[3]
-428 } else {
-429 return match
-430 }
-431 }
-432}
-433func removeWhitespace(htmlString string) string {
-434 // Remove extra white space
-435 reSpaces := regexp.MustCompile(`\s+`)
-436 htmlString = reSpaces.ReplaceAllString(htmlString, " ")
-437
-438 // Trim leading and trailing white space
-439 htmlString = strings.TrimSpace(htmlString)
-440
-441 return htmlString
-442}
-443
-444func removeHTMLComments(htmlString string) string {
-445 re := regexp.MustCompile(`<!--[\s\S]*?-->`)
-446 return re.ReplaceAllString(htmlString, "")
+425 // If the absolute path is the same as the original path, return it
+426 if absPath == filePath {
+427 return filePath
+428 }
+429
+430 return "./" + absPath
+431}
+432
+433func encapsulateText(htmlString string) string {
+434 openOpen := regexp.MustCompile(`(<\w+[^>]*>)([^<]+)(<\w+[^>]*>)`)
+435 closeOpen := regexp.MustCompile(`(</\w+[^>]*>)([^<]+)(<\w+[^>]*>)`)
+436 closeClose := regexp.MustCompile(`(<\/\w+[^>]*>)([^<]+)(<\/\w+[^>]*>)`)
+437 a := matchFactory(openOpen)
+438 t := openOpen.ReplaceAllStringFunc(htmlString, a)
+439 // fmt.Println(t)
+440 b := matchFactory(closeOpen)
+441 u := closeOpen.ReplaceAllStringFunc(t, b)
+442 // fmt.Println(u)
+443 c := matchFactory(closeClose)
+444 v := closeClose.ReplaceAllStringFunc(u, c)
+445 // fmt.Println(v)
+446 return v
@@ -486,23 +486,69 @@
-449// important to allow the notspans to be injected, the spaces after removing the comments cause the regexp to fail
-450func removeWhitespaceBetweenTags(html string) string {
-451 // Create a regular expression to match spaces between angle brackets
-452 re := regexp.MustCompile(`>\s+<`)
-453 // Replace all matches of spaces between angle brackets with "><"
-454 return re.ReplaceAllString(html, "><")
-455}
-456
-457// Function to hash a struct using SHA-256
-458func hashStruct(s interface{}) ([]byte, error) {
-459 // Convert struct to JSON
-460 jsonData, err := json.Marshal(s)
-461 if err != nil {
-462 return nil, err
-463 }
-464
-465 // Hash the JSON data using SHA-256
-466 hasher := sha256.New()
-467 hasher.Write(jsonData)
-468 hash := hasher.Sum(nil)
-469
-470 return hash, nil
-471}
+449func matchFactory(re *regexp.Regexp) func(string) string {
+450 return func(match string) string {
+451 submatches := re.FindStringSubmatch(match)
+452 if len(submatches) != 4 {
+453 return match
+454 }
+455
+456 // Process submatches
+457 if len(removeWhitespace(submatches[2])) > 0 {
+458 return submatches[1] + "<notaspan>" + submatches[2] + "</notaspan>" + submatches[3]
+459 } else {
+460 return match
+461 }
+462 }
+463}
+464func removeWhitespace(htmlString string) string {
+465 // Remove extra white space
+466 reSpaces := regexp.MustCompile(`\s+`)
+467 htmlString = reSpaces.ReplaceAllString(htmlString, " ")
+468
+469 // Trim leading and trailing white space
+470 htmlString = strings.TrimSpace(htmlString)
+471
+472 return htmlString
+473}
+474
+475func removeHTMLComments(htmlString string) string {
+476 re := regexp.MustCompile(`<!--[\s\S]*?-->`)
+477 return re.ReplaceAllString(htmlString, "")
+478}
+479
+480// important to allow the notspans to be injected, the spaces after removing the comments cause the regexp to fail
+481func removeWhitespaceBetweenTags(html string) string {
+482 // Create a regular expression to match spaces between angle brackets
+483 re := regexp.MustCompile(`>\s+<`)
+484 // Replace all matches of spaces between angle brackets with "><"
+485 return re.ReplaceAllString(html, "><")
+486}
+487
+488// Function to hash a struct using SHA-256
+489func hashStruct(s interface{}) ([]byte, error) {
+490 // Convert struct to JSON
+491 jsonData, err := json.Marshal(s)
+492 if err != nil {
+493 return nil, err
+494 }
+495
+496 // Hash the JSON data using SHA-256
+497 hasher := sha256.New()
+498 hasher.Write(jsonData)
+499 hash := hasher.Sum(nil)
+500
+501 return hash, nil
+502}
+503
+504func getElementByPropId(n *element.Node, id string) *element.Node {
+505 if n.Properties.Id == id {
+506 return n
+507 } else if len(n.Children) > 0 {
+508 for i := 0; i < len(n.Children); i++ {
+509 n.Children[i].Parent = n
+510 item := getElementByPropId(&n.Children[i], id)
+511 if item != nil {
+512 return item
+513 }
+514 }
+515 }
+516 return nil
+517}