123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362 |
- package gen
- import (
- "fmt"
- "math/rand"
- "os"
- "path/filepath"
- "strings"
- "git.clearsky.net.au/cody/gex.git/gen/domquery"
- "git.clearsky.net.au/cody/gex.git/gen/img"
- "git.clearsky.net.au/cody/gex.git/gen/layout"
- "git.clearsky.net.au/cody/gex.git/gen/partial"
- )
- var appRuleList cssRuleList
- //var appJsStr string
- func GeneratePages(dir string) error {
- err := processTemplate(dir)
- if err != nil {
- fmt.Println(err)
- return err
- }
- // Process Partials
- err = processPartials(dir)
- if err != nil {
- fmt.Println(err)
- return err
- }
- // Build the layout & blocks
- err = processLayout(dir)
- if err != nil {
- fmt.Println(err)
- return err
- }
- // Process IMG on the generated files
- err = ProcessImg(dir)
- if err != nil {
- fmt.Println(err)
- return err
- }
- // Clean block tags
- err = cleanBlocks(dir)
- if err != nil {
- fmt.Println(err)
- return err
- }
- appRuleList = mergeMediaRules(appRuleList)
- appRuleList = orderRules(appRuleList)
- cssStr := rulesToCSSstr(appRuleList)
- os.WriteFile("app/pub/css/app.gen.css", []byte(cssStr), 0655)
- return nil
- }
- func processTemplate(dir string) error {
- processFile := func(fp string) error {
- if strings.Contains(fp, ".gen.tpl") {
- return nil
- }
- if !strings.Contains(fp, ".tpl") {
- return nil
- }
- // get the html string
- data, err := os.ReadFile(fp)
- if err != nil {
- return err
- }
- htmlStr := string(data)
- // add the scope class to attributes
- className := genRandName(8)
- htmlStr = AddClassAttr(htmlStr, className)
- // get & strip the css rules
- cssStr := ExtractCSS(&htmlStr)
- ruleList := toRuleList(cssStr)
- // scope the rules with css class
- ruleList = scopeSelectors(ruleList, className)
- appRuleList = append(appRuleList, ruleList...)
- // Process JS on the generated file
- htmlStr = ProcessJs(htmlStr, className)
- // write the .gen.html file as
- newPath := strings.Replace(fp, ".tpl", ".gen.tpl", 1)
- return os.WriteFile(newPath, []byte(htmlStr), 0655)
- }
- walk := func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if info.IsDir() {
- return nil
- }
- return processFile(path)
- }
- return filepath.Walk(dir, walk)
- }
- func processPartials(dir string) error {
- processFile := func(fp string) error {
- if !strings.Contains(fp, ".gen.tpl") {
- return nil
- }
- data, err := os.ReadFile(fp)
- if err != nil {
- return err
- }
- htmlStr := string(data)
- htmlStr, err = partial.ProcessHTML(htmlStr, fp)
- if err != nil {
- fmt.Println("\n" + fp)
- return err
- }
- return os.WriteFile(fp, []byte(htmlStr), 0655)
- }
- walk := func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if info.IsDir() {
- return nil
- }
- return processFile(path)
- }
- err := filepath.Walk(dir, walk)
- if err != nil {
- return err
- }
- return nil
- }
- func processLayout(dir string) error {
- processFile := func(fp string) error {
- if !strings.Contains(fp, ".gen.tpl") {
- return nil
- }
- data, err := os.ReadFile(fp)
- if err != nil {
- return err
- }
- htmlStr := string(data)
- htmlStr, err = layout.ProcessHTML(htmlStr, fp)
- if err != nil {
- fmt.Println("\n" + fp)
- return err
- }
- os.WriteFile(fp, []byte(htmlStr), 0655)
- return nil
- }
- walk := func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if info.IsDir() {
- return nil
- }
- return processFile(path)
- }
- filepath.Walk(dir, walk)
- return nil
- }
- func ProcessJs(htmlStr string, className string) string {
- dom := domquery.LoadHTML(htmlStr)
- scripts := dom.QuerySelectorAll("script")
- i := 0
- jsTag := ""
- for _, script := range scripts {
- scriptName := className + fmt.Sprintf("%d", i)
- if script.GetAttribute("inline") != "" {
- continue
- }
- if script.GetAttribute("src") != "" {
- continue
- }
- jsStr := script.InnerHTML()
- funcStr := `if (typeof ` + scriptName + ` === 'undefined') {`
- funcStr += `window.` + scriptName + ` = () => {`
- funcStr += jsStr
- funcStr += `
- if(typeof unload == "undefined")
- return
- const watchInt = setInterval(() => {
- let watch = document.querySelector(".` + className + `");
- if (!watch) {
- unload();
- clearInterval(watchInt);
- }
- },100);
- }
- }
- ` + scriptName + `()
- `
- srcPath := "app/pub/gen/" + scriptName + ".gen.js"
- os.WriteFile(srcPath, []byte(funcStr), 0655)
- jsTag += `<script defer src="/` + srcPath + `"></script>`
- if script.GetAttribute("type") == "module" {
- jsTag = `<script type="module" defer src="/` + srcPath + `"></script>`
- }
- script.Remove()
- i++
- }
- insDiv := dom.QuerySelector("." + className)
- insDiv.SetInnerHTML(jsTag + insDiv.InnerHTML())
- htmlStr = dom.InnerHTML()
- return htmlStr
- }
- func ProcessImg(dir string) error {
- processFile := func(fp string) error {
- htmlDir := filepath.Dir(fp)
- if !strings.Contains(fp, ".gen.tpl") {
- return nil
- }
- // get the html string
- data, err := os.ReadFile(fp)
- if err != nil {
- return err
- }
- htmlStr := string(data)
- document := domquery.LoadHTML(htmlStr)
- imgTags := document.QuerySelectorAll("img")
- for _, tag := range imgTags {
- if !(tag.HasAttribute("webp") && tag.HasAttribute("src")) {
- continue
- }
- img.Process(htmlDir, tag)
- }
- htmlStr = document.InnerHTML()
- os.WriteFile(fp, []byte(htmlStr), 0655)
- return nil
- }
- walk := func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if info.IsDir() {
- return nil
- }
- return processFile(path)
- }
- return filepath.Walk(dir, walk)
- }
- func cleanBlocks(dir string) error {
- processFile := func(fp string) error {
- if !strings.Contains(fp, ".gen.tpl") {
- return nil
- }
- // get the html string
- data, err := os.ReadFile(fp)
- if err != nil {
- return err
- }
- htmlStr := string(data)
- dom := domquery.LoadHTML(htmlStr)
- var clean func()
- clean = func() {
- blocks := dom.QuerySelectorAll("block")
- // grab the top block only as blocks is invalid after a SetOuterHTML event
- for _, block := range blocks {
- block.SetOuterHTML(block.InnerHTML())
- clean()
- return
- }
- }
- clean()
- htmlStr = dom.InnerHTML()
- os.WriteFile(fp, []byte(htmlStr), 0655)
- return nil
- }
- walk := func(dir string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if info.IsDir() {
- return nil
- }
- return processFile(dir)
- }
- return filepath.Walk(dir, walk)
- }
- // generate a random string to use as a class name
- func genRandName(length int) string {
- const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
- b := make([]byte, length)
- for i := range b {
- b[i] = charset[rand.Intn(len(charset))]
- }
- return string(b)
- }
|