diff --git a/app/theme/twentyseventeen/script.go b/app/theme/twentyseventeen/script.go
index 3f98a62..611edb0 100644
--- a/app/theme/twentyseventeen/script.go
+++ b/app/theme/twentyseventeen/script.go
@@ -21,9 +21,9 @@ func pushScripts(h *wp.Handle) {
[]string{"twentyseventeen-style"}, "20191025", "")
}
- scriptloader.AddData("twentyseventeen-ie8", "conditional", "lt IE 9")
+ scriptloader.AddScriptData("twentyseventeen-ie8", "conditional", "lt IE 9")
scriptloader.EnqueueScripts("html5", "/assets/js/html5.js", nil, "20161020", false)
- scriptloader.AddData("html5", "conditional", "lt IE 9")
+ scriptloader.AddScriptData("html5", "conditional", "lt IE 9")
scriptloader.EnqueueScripts("twentyseventeen-skip-link-focus-fix", "/assets/js/skip-link-focus-fix.js",
nil, "20161114", true)
diff --git a/app/theme/twentyseventeen/twentyseventeen.go b/app/theme/twentyseventeen/twentyseventeen.go
index 0027cdd..0325a0f 100644
--- a/app/theme/twentyseventeen/twentyseventeen.go
+++ b/app/theme/twentyseventeen/twentyseventeen.go
@@ -43,7 +43,7 @@ func configs(h *wp.Handle) {
components.WidgetArea(h)
pushScripts(h)
h.PushRender(constraints.AllStats, wp.NewHandleFn(calCustomHeader, 10.005, "calCustomHeader"))
- h.SetComponentsArgs(widgets.Widget, map[string]string{
+ wp.SetComponentsArgs(h, widgets.Widget, map[string]string{
"{$before_widget}": ``,
})
diff --git a/app/theme/wp/components.go b/app/theme/wp/components.go
index 8c59ae4..c91d131 100644
--- a/app/theme/wp/components.go
+++ b/app/theme/wp/components.go
@@ -190,7 +190,7 @@ func MergeComponentsArgsForMap[K comparable, V any](h *Handle, name string, m ma
}
}
-func (h *Handle) SetComponentsArgs(key string, value any) {
+func SetComponentsArgs(h *Handle, key string, value any) {
h.componentsArgs[key] = value
}
diff --git a/app/theme/wp/scriptloader/defaultscriptload.go b/app/theme/wp/scriptloader/defaultscriptload.go
index 6cc8a6c..db13a89 100644
--- a/app/theme/wp/scriptloader/defaultscriptload.go
+++ b/app/theme/wp/scriptloader/defaultscriptload.go
@@ -366,121 +366,121 @@ func defaultTranslate() {
}
func defaultAddData() {
- AddData("json2", "conditional", `lt IE 8`)
- AddData("wp-embed-template-ie", "conditional", `lte IE 8`)
- AddData("wp-block-library-theme", "path", `wp-includes/css/dist/block-library/theme.min.css`)
- AddData("wp-block-editor", "path", `/wp-includes/css/dist/block-editor/style.min.css`)
- AddData("wp-block-library", "path", `/wp-includes/css/dist/block-library/style.min.css`)
- AddData("wp-block-directory", "path", `/wp-includes/css/dist/block-directory/style.min.css`)
- AddData("wp-components", "path", `/wp-includes/css/dist/components/style.min.css`)
- AddData("wp-edit-post", "path", `/wp-includes/css/dist/edit-post/style.min.css`)
- AddData("wp-editor", "path", `/wp-includes/css/dist/editor/style.min.css`)
- AddData("wp-format-library", "path", `/wp-includes/css/dist/format-library/style.min.css`)
- AddData("wp-list-reusable-blocks", "path", `/wp-includes/css/dist/list-reusable-blocks/style.min.css`)
- AddData("wp-reusable-blocks", "path", `/wp-includes/css/dist/reusable-blocks/style.min.css`)
- AddData("wp-nux", "path", `/wp-includes/css/dist/nux/style.min.css`)
- AddData("wp-widgets", "path", `/wp-includes/css/dist/widgets/style.min.css`)
- AddData("wp-edit-widgets", "path", `/wp-includes/css/dist/edit-widgets/style.min.css`)
- AddData("wp-customize-widgets", "path", `/wp-includes/css/dist/customize-widgets/style.min.css`)
- AddData("wp-edit-site", "path", `/wp-includes/css/dist/edit-site/style.min.css`)
- AddData("common", "rtl", `replace`)
- AddData("common", "suffix", `.min`)
- AddData("forms", "rtl", `replace`)
- AddData("forms", "suffix", `.min`)
- AddData("admin-menu", "rtl", `replace`)
- AddData("admin-menu", "suffix", `.min`)
- AddData("dashboard", "rtl", `replace`)
- AddData("dashboard", "suffix", `.min`)
- AddData("list-tables", "rtl", `replace`)
- AddData("list-tables", "suffix", `.min`)
- AddData("edit", "rtl", `replace`)
- AddData("edit", "suffix", `.min`)
- AddData("revisions", "rtl", `replace`)
- AddData("revisions", "suffix", `.min`)
- AddData("media", "rtl", `replace`)
- AddData("media", "suffix", `.min`)
- AddData("themes", "rtl", `replace`)
- AddData("themes", "suffix", `.min`)
- AddData("about", "rtl", `replace`)
- AddData("about", "suffix", `.min`)
- AddData("nav-menus", "rtl", `replace`)
- AddData("nav-menus", "suffix", `.min`)
- AddData("widgets", "rtl", `replace`)
- AddData("widgets", "suffix", `.min`)
- AddData("site-icon", "rtl", `replace`)
- AddData("site-icon", "suffix", `.min`)
- AddData("l10n", "rtl", `replace`)
- AddData("l10n", "suffix", `.min`)
- AddData("install", "rtl", `replace`)
- AddData("install", "suffix", `.min`)
- AddData("wp-color-picker", "rtl", `replace`)
- AddData("wp-color-picker", "suffix", `.min`)
- AddData("customize-controls", "rtl", `replace`)
- AddData("customize-controls", "suffix", `.min`)
- AddData("customize-widgets", "rtl", `replace`)
- AddData("customize-widgets", "suffix", `.min`)
- AddData("customize-nav-menus", "rtl", `replace`)
- AddData("customize-nav-menus", "suffix", `.min`)
- AddData("customize-preview", "rtl", `replace`)
- AddData("customize-preview", "suffix", `.min`)
- AddData("login", "rtl", `replace`)
- AddData("login", "suffix", `.min`)
- AddData("site-health", "rtl", `replace`)
- AddData("site-health", "suffix", `.min`)
- AddData("buttons", "rtl", `replace`)
- AddData("buttons", "suffix", `.min`)
- AddData("admin-bar", "rtl", `replace`)
- AddData("admin-bar", "suffix", `.min`)
- AddData("wp-auth-check", "rtl", `replace`)
- AddData("wp-auth-check", "suffix", `.min`)
- AddData("editor-buttons", "rtl", `replace`)
- AddData("editor-buttons", "suffix", `.min`)
- AddData("media-views", "rtl", `replace`)
- AddData("media-views", "suffix", `.min`)
- AddData("wp-pointer", "rtl", `replace`)
- AddData("wp-pointer", "suffix", `.min`)
- AddData("wp-jquery-ui-dialog", "rtl", `replace`)
- AddData("wp-jquery-ui-dialog", "suffix", `.min`)
- AddData("wp-reset-editor-styles", "rtl", `replace`)
- AddData("wp-reset-editor-styles", "suffix", `.min`)
- AddData("wp-editor-classic-layout-styles", "rtl", `replace`)
- AddData("wp-editor-classic-layout-styles", "suffix", `.min`)
- AddData("wp-block-library-theme", "rtl", `replace`)
- AddData("wp-block-library-theme", "suffix", `.min`)
- AddData("wp-edit-blocks", "rtl", `replace`)
- AddData("wp-edit-blocks", "suffix", `.min`)
- AddData("wp-block-editor", "rtl", `replace`)
- AddData("wp-block-editor", "suffix", `.min`)
- AddData("wp-block-library", "rtl", `replace`)
- AddData("wp-block-library", "suffix", `.min`)
- AddData("wp-block-directory", "rtl", `replace`)
- AddData("wp-block-directory", "suffix", `.min`)
- AddData("wp-components", "rtl", `replace`)
- AddData("wp-components", "suffix", `.min`)
- AddData("wp-customize-widgets", "rtl", `replace`)
- AddData("wp-customize-widgets", "suffix", `.min`)
- AddData("wp-edit-post", "rtl", `replace`)
- AddData("wp-edit-post", "suffix", `.min`)
- AddData("wp-edit-site", "rtl", `replace`)
- AddData("wp-edit-site", "suffix", `.min`)
- AddData("wp-edit-widgets", "rtl", `replace`)
- AddData("wp-edit-widgets", "suffix", `.min`)
- AddData("wp-editor", "rtl", `replace`)
- AddData("wp-editor", "suffix", `.min`)
- AddData("wp-format-library", "rtl", `replace`)
- AddData("wp-format-library", "suffix", `.min`)
- AddData("wp-list-reusable-blocks", "rtl", `replace`)
- AddData("wp-list-reusable-blocks", "suffix", `.min`)
- AddData("wp-reusable-blocks", "rtl", `replace`)
- AddData("wp-reusable-blocks", "suffix", `.min`)
- AddData("wp-nux", "rtl", `replace`)
- AddData("wp-nux", "suffix", `.min`)
- AddData("wp-widgets", "rtl", `replace`)
- AddData("wp-widgets", "suffix", `.min`)
- AddData("deprecated-media", "rtl", `replace`)
- AddData("deprecated-media", "suffix", `.min`)
- AddData("farbtastic", "rtl", `replace`)
- AddData("farbtastic", "suffix", `.min`)
+ AddScriptData("json2", "conditional", `lt IE 8`)
+ AddScriptData("wp-embed-template-ie", "conditional", `lte IE 8`)
+ AddScriptData("wp-block-library-theme", "path", `wp-includes/css/dist/block-library/theme.min.css`)
+ AddScriptData("wp-block-editor", "path", `/wp-includes/css/dist/block-editor/style.min.css`)
+ AddScriptData("wp-block-library", "path", `/wp-includes/css/dist/block-library/style.min.css`)
+ AddScriptData("wp-block-directory", "path", `/wp-includes/css/dist/block-directory/style.min.css`)
+ AddScriptData("wp-components", "path", `/wp-includes/css/dist/components/style.min.css`)
+ AddScriptData("wp-edit-post", "path", `/wp-includes/css/dist/edit-post/style.min.css`)
+ AddScriptData("wp-editor", "path", `/wp-includes/css/dist/editor/style.min.css`)
+ AddScriptData("wp-format-library", "path", `/wp-includes/css/dist/format-library/style.min.css`)
+ AddScriptData("wp-list-reusable-blocks", "path", `/wp-includes/css/dist/list-reusable-blocks/style.min.css`)
+ AddScriptData("wp-reusable-blocks", "path", `/wp-includes/css/dist/reusable-blocks/style.min.css`)
+ AddScriptData("wp-nux", "path", `/wp-includes/css/dist/nux/style.min.css`)
+ AddScriptData("wp-widgets", "path", `/wp-includes/css/dist/widgets/style.min.css`)
+ AddScriptData("wp-edit-widgets", "path", `/wp-includes/css/dist/edit-widgets/style.min.css`)
+ AddScriptData("wp-customize-widgets", "path", `/wp-includes/css/dist/customize-widgets/style.min.css`)
+ AddScriptData("wp-edit-site", "path", `/wp-includes/css/dist/edit-site/style.min.css`)
+ AddScriptData("common", "rtl", `replace`)
+ AddScriptData("common", "suffix", `.min`)
+ AddScriptData("forms", "rtl", `replace`)
+ AddScriptData("forms", "suffix", `.min`)
+ AddScriptData("admin-menu", "rtl", `replace`)
+ AddScriptData("admin-menu", "suffix", `.min`)
+ AddScriptData("dashboard", "rtl", `replace`)
+ AddScriptData("dashboard", "suffix", `.min`)
+ AddScriptData("list-tables", "rtl", `replace`)
+ AddScriptData("list-tables", "suffix", `.min`)
+ AddScriptData("edit", "rtl", `replace`)
+ AddScriptData("edit", "suffix", `.min`)
+ AddScriptData("revisions", "rtl", `replace`)
+ AddScriptData("revisions", "suffix", `.min`)
+ AddScriptData("media", "rtl", `replace`)
+ AddScriptData("media", "suffix", `.min`)
+ AddScriptData("themes", "rtl", `replace`)
+ AddScriptData("themes", "suffix", `.min`)
+ AddScriptData("about", "rtl", `replace`)
+ AddScriptData("about", "suffix", `.min`)
+ AddScriptData("nav-menus", "rtl", `replace`)
+ AddScriptData("nav-menus", "suffix", `.min`)
+ AddScriptData("widgets", "rtl", `replace`)
+ AddScriptData("widgets", "suffix", `.min`)
+ AddScriptData("site-icon", "rtl", `replace`)
+ AddScriptData("site-icon", "suffix", `.min`)
+ AddScriptData("l10n", "rtl", `replace`)
+ AddScriptData("l10n", "suffix", `.min`)
+ AddScriptData("install", "rtl", `replace`)
+ AddScriptData("install", "suffix", `.min`)
+ AddScriptData("wp-color-picker", "rtl", `replace`)
+ AddScriptData("wp-color-picker", "suffix", `.min`)
+ AddScriptData("customize-controls", "rtl", `replace`)
+ AddScriptData("customize-controls", "suffix", `.min`)
+ AddScriptData("customize-widgets", "rtl", `replace`)
+ AddScriptData("customize-widgets", "suffix", `.min`)
+ AddScriptData("customize-nav-menus", "rtl", `replace`)
+ AddScriptData("customize-nav-menus", "suffix", `.min`)
+ AddScriptData("customize-preview", "rtl", `replace`)
+ AddScriptData("customize-preview", "suffix", `.min`)
+ AddScriptData("login", "rtl", `replace`)
+ AddScriptData("login", "suffix", `.min`)
+ AddScriptData("site-health", "rtl", `replace`)
+ AddScriptData("site-health", "suffix", `.min`)
+ AddScriptData("buttons", "rtl", `replace`)
+ AddScriptData("buttons", "suffix", `.min`)
+ AddScriptData("admin-bar", "rtl", `replace`)
+ AddScriptData("admin-bar", "suffix", `.min`)
+ AddScriptData("wp-auth-check", "rtl", `replace`)
+ AddScriptData("wp-auth-check", "suffix", `.min`)
+ AddScriptData("editor-buttons", "rtl", `replace`)
+ AddScriptData("editor-buttons", "suffix", `.min`)
+ AddScriptData("media-views", "rtl", `replace`)
+ AddScriptData("media-views", "suffix", `.min`)
+ AddScriptData("wp-pointer", "rtl", `replace`)
+ AddScriptData("wp-pointer", "suffix", `.min`)
+ AddScriptData("wp-jquery-ui-dialog", "rtl", `replace`)
+ AddScriptData("wp-jquery-ui-dialog", "suffix", `.min`)
+ AddScriptData("wp-reset-editor-styles", "rtl", `replace`)
+ AddScriptData("wp-reset-editor-styles", "suffix", `.min`)
+ AddScriptData("wp-editor-classic-layout-styles", "rtl", `replace`)
+ AddScriptData("wp-editor-classic-layout-styles", "suffix", `.min`)
+ AddScriptData("wp-block-library-theme", "rtl", `replace`)
+ AddScriptData("wp-block-library-theme", "suffix", `.min`)
+ AddScriptData("wp-edit-blocks", "rtl", `replace`)
+ AddScriptData("wp-edit-blocks", "suffix", `.min`)
+ AddScriptData("wp-block-editor", "rtl", `replace`)
+ AddScriptData("wp-block-editor", "suffix", `.min`)
+ AddScriptData("wp-block-library", "rtl", `replace`)
+ AddScriptData("wp-block-library", "suffix", `.min`)
+ AddScriptData("wp-block-directory", "rtl", `replace`)
+ AddScriptData("wp-block-directory", "suffix", `.min`)
+ AddScriptData("wp-components", "rtl", `replace`)
+ AddScriptData("wp-components", "suffix", `.min`)
+ AddScriptData("wp-customize-widgets", "rtl", `replace`)
+ AddScriptData("wp-customize-widgets", "suffix", `.min`)
+ AddScriptData("wp-edit-post", "rtl", `replace`)
+ AddScriptData("wp-edit-post", "suffix", `.min`)
+ AddScriptData("wp-edit-site", "rtl", `replace`)
+ AddScriptData("wp-edit-site", "suffix", `.min`)
+ AddScriptData("wp-edit-widgets", "rtl", `replace`)
+ AddScriptData("wp-edit-widgets", "suffix", `.min`)
+ AddScriptData("wp-editor", "rtl", `replace`)
+ AddScriptData("wp-editor", "suffix", `.min`)
+ AddScriptData("wp-format-library", "rtl", `replace`)
+ AddScriptData("wp-format-library", "suffix", `.min`)
+ AddScriptData("wp-list-reusable-blocks", "rtl", `replace`)
+ AddScriptData("wp-list-reusable-blocks", "suffix", `.min`)
+ AddScriptData("wp-reusable-blocks", "rtl", `replace`)
+ AddScriptData("wp-reusable-blocks", "suffix", `.min`)
+ AddScriptData("wp-nux", "rtl", `replace`)
+ AddScriptData("wp-nux", "suffix", `.min`)
+ AddScriptData("wp-widgets", "rtl", `replace`)
+ AddScriptData("wp-widgets", "suffix", `.min`)
+ AddScriptData("deprecated-media", "rtl", `replace`)
+ AddScriptData("deprecated-media", "suffix", `.min`)
+ AddScriptData("farbtastic", "rtl", `replace`)
+ AddScriptData("farbtastic", "suffix", `.min`)
}
diff --git a/app/theme/wp/scriptloader/defaultstyles.go b/app/theme/wp/scriptloader/defaultstyles.go
index ca2e026..4c0f9ed 100644
--- a/app/theme/wp/scriptloader/defaultstyles.go
+++ b/app/theme/wp/scriptloader/defaultstyles.go
@@ -2,6 +2,6 @@ package scriptloader
import "github.com/fthvgb1/wp-go/safety"
-func defaultStyles(m *safety.Map[string, *Script], suffix string) {
+func defaultStyles(m *safety.Map[string, *Style], suffix string) {
}
diff --git a/app/theme/wp/scriptloader/head.go b/app/theme/wp/scriptloader/head.go
index 8dca1e2..906b8a4 100644
--- a/app/theme/wp/scriptloader/head.go
+++ b/app/theme/wp/scriptloader/head.go
@@ -1,10 +1,15 @@
package scriptloader
import (
+ "encoding/json"
+ "github.com/fthvgb1/wp-go/app/cmd/reload"
+ "github.com/fthvgb1/wp-go/app/pkg/config"
"github.com/fthvgb1/wp-go/app/pkg/logs"
"github.com/fthvgb1/wp-go/app/theme/wp"
"github.com/fthvgb1/wp-go/helper/slice"
+ str "github.com/fthvgb1/wp-go/helper/strings"
"os"
+ "path/filepath"
)
type _style struct {
@@ -50,13 +55,62 @@ func MaybeInlineStyles(h *wp.Handle) {
if totalInlineSize+i.size > totalInlineLimit {
break
}
- css, err := os.ReadFile(i.path)
- if err != nil {
- logs.Error(err, "read file ", i.path)
- continue
- }
+ path := filepath.Join(i.path)
+ css := reload.GetAnyValMapBy("script-loader-MaybeInlineStyles", i.handle, path, func(a string) string {
+ css, err := os.ReadFile(i.path)
+ if err != nil {
+ logs.Error(err, "read file ", i.path)
+ return ""
+ }
+ return string(css)
+ })
+
s, _ := __styles.Load(i.handle)
s.Src = ""
- s.Extra["after"] = append(s.Extra["after"], string(css))
+ a := s.Extra["after"]
+ if a == nil {
+ a = []string{}
+ }
+ slice.Unshift(&a, css)
+ s.Extra["after"] = a
}
}
+
+func emojiDetectionScript(h *wp.Handle) {
+ settings := map[string]any{
+ "baseUrl": "https://s.w.org/images/core/emoji/14.0.0/72x72/",
+ "ext": ".png",
+ "svgUrl": "https://s.w.org/images/core/emoji/14.0.0/svg/", "svgExt": ".svg",
+ "source": map[string]any{
+ "concatemoji": "/wp-includes/js/wp-emoji-release.min.js?ver=6.2.2",
+ },
+ }
+ setting, _ := json.Marshal(settings)
+ dir := config.GetConfig().WpDir
+ emotion := reload.GetAnyValBys("script-loader-emoji", struct{}{}, func(_ struct{}) string {
+ f, err := os.ReadFile(dir)
+ if err != nil {
+ logs.Error(err, "load emoji css fail", dir)
+ return ""
+ }
+ return string(f)
+ })
+ s := str.Join("window._wpemojiSettings = ", string(setting), "\n", emotion)
+ PrintInlineScriptTag(h, s, nil)
+}
+
+func PrintInlineScriptTag(h *wp.Handle, script string, attr map[string]string) {
+ ss := wp.GetComponentsArgs(h, "inlineScript", "")
+ s := str.NewBuilder()
+ s.WriteString(ss)
+ s.WriteString("\n", script)
+ wp.SetComponentsArgs(h, "inlineScript", s.String())
+}
+
+func PrintStyles(h *wp.Handle) {
+
+}
diff --git a/app/theme/wp/scriptloader/scriptloader.go b/app/theme/wp/scriptloader/scriptloader.go
index 93974a9..349aafd 100644
--- a/app/theme/wp/scriptloader/scriptloader.go
+++ b/app/theme/wp/scriptloader/scriptloader.go
@@ -3,25 +3,19 @@ package scriptloader
import (
"encoding/json"
"fmt"
- "github.com/dlclark/regexp2"
"github.com/fthvgb1/wp-go/app/cmd/reload"
"github.com/fthvgb1/wp-go/app/theme/wp"
"github.com/fthvgb1/wp-go/app/wpconfig"
"github.com/fthvgb1/wp-go/helper"
"github.com/fthvgb1/wp-go/helper/maps"
- "github.com/fthvgb1/wp-go/helper/number"
"github.com/fthvgb1/wp-go/helper/slice"
str "github.com/fthvgb1/wp-go/helper/strings"
"github.com/fthvgb1/wp-go/safety"
- "html"
- "math"
"path/filepath"
- "regexp"
- "strconv"
"strings"
)
-var __styles = reload.MapBy(func(m *safety.Map[string, *Script]) {
+var __styles = reload.MapBy(func(m *safety.Map[string, *Style]) {
defaultStyles(m, ".css")
})
var __scripts = reload.MapBy[string, *Script](func(m *safety.Map[string, *Script]) {
@@ -30,6 +24,14 @@ var __scripts = reload.MapBy[string, *Script](func(m *safety.Map[string, *Script
})
+type Style struct {
+ Dependencies
+}
+
+type Script struct {
+ Dependencies
+}
+
func addScript(handle string, src string, deps []string, ver string, args any) {
script := NewScript(handle, src, deps, ver, args)
__scripts.Store(handle, script)
@@ -52,18 +54,14 @@ func localize(handle, objectname string, l10n map[string]any) string {
}
func AddStaticLocalize(handle, objectname string, l10n map[string]any) {
- AddData(handle, "data", localize(handle, objectname, l10n))
+ AddScriptData(handle, "data", localize(handle, objectname, l10n))
}
func AddDynamicLocalize(h *wp.Handle, handle, objectname string, l10n map[string]any) {
AddDynamicData(h, handle, "data", localize(handle, objectname, l10n))
}
-func getData(handle, key string) string {
- h, ok := __scripts.Load(handle)
- if !ok {
- return ""
- }
- return strings.Join(h.Extra[key], "\n")
+func (d *Dependencies) getData(key string) string {
+ return strings.Join(d.Extra[key], "\n")
}
func GetData(h *wp.Handle, handle, key string) string {
hh, ok := __scripts.Load(handle)
@@ -75,14 +73,10 @@ func GetData(h *wp.Handle, handle, key string) string {
return strings.Join(d, "\n")
}
-func AddData(handle, key, data string, t ...int) {
+func AddScriptData(handle, key, data string) {
var s *Script
var ok bool
- if t != nil {
- s, ok = __styles.Load(handle)
- } else {
- s, ok = __scripts.Load(handle)
- }
+ s, ok = __scripts.Load(handle)
if !ok {
s = NewScript(handle, "", nil, "", nil)
}
@@ -99,18 +93,19 @@ func AddInlineScript(handle, data, position string) {
if position != "after" {
position = "before"
}
- AddData(handle, position, data)
+ AddScriptData(handle, position, data)
}
func AddInlineStyle(handle, data string) {
if handle == "" || data == "" {
return
}
- AddData(handle, "after", data, style)
+ AddScriptData(handle, "after", data, style)
}
func InlineScripts(handle, position string, display bool) string {
- ss := getData(handle, position)
+ v, _ := __scripts.Load(handle)
+ ss := v.getData(position)
if ss == "" {
return ""
}
@@ -164,7 +159,7 @@ func EnqueueScript(handle, src string, deps []string, ver string, inFooter bool)
AddScript(h[0], src, deps, ver, nil)
}
if inFooter {
- AddData(h[0], "group", "1")
+ AddScriptData(h[0], "group", "1")
}
enqueue(handle, script)
}
@@ -199,7 +194,7 @@ func GetThemeFileUri(file string) string {
return filepath.Join("/wp-content/themes", wpconfig.GetOption("template"), file)
}
-type Script struct {
+type Dependencies struct {
Handle string `json:"handle,omitempty"`
Src string `json:"src,omitempty"`
Deps []string `json:"deps,omitempty"`
@@ -211,7 +206,7 @@ type Script struct {
}
func NewScript(handle string, src string, deps []string, ver string, args any) *Script {
- return &Script{Handle: handle, Src: src, Deps: deps, Ver: ver, Args: args}
+ return &Script{Dependencies{Handle: handle, Src: src, Deps: deps, Ver: ver, Args: args}}
}
func AddDynamicData(h *wp.Handle, handle, key, data string) {
@@ -255,995 +250,106 @@ func SetTranslation(handle, domain, path string) {
hh.TranslationsPath = path
}
-var __elements = map[string]string{
- "link": "a:where(:not(.wp-element-button))", // The `where` is needed to lower the specificity.
- "heading": "h1, h2, h3, h4, h5, h6",
- "h1": "h1",
- "h2": "h2",
- "h3": "h3",
- "h4": "h4",
- "h5": "h5",
- "h6": "h6",
- // We have the .wp-block-button__link class so that this will target older buttons that have been serialized.
- "button": ".wp-element-button, .wp-block-button__link",
- // The block classes are necessary to target older content that won't use the new class names.
- "caption": ".wp-element-caption, .wp-block-audio figcaption, .wp-block-embed figcaption, .wp-block-gallery figcaption, .wp-block-image figcaption, .wp-block-table figcaption, .wp-block-video figcaption",
- "cite": "cite",
-}
-
-const RootBlockSelector = "body"
-
-type node struct {
- Path []string
- Selector string
- Name string
-}
-
-var __validElementPseudoSelectors = map[string][]string{
- "link": {":link", ":any-link", ":visited", ":hover", ":focus", ":active"},
- "button": {":link", ":any-link", ":visited", ":hover", ":focus", ":active"},
-}
-
-var blockSupportFeatureLevelSelectors = map[string]string{
- "__experimentalBorder": "border",
- "color": "color",
- "spacing": "spacing",
- "typography": "typography",
-}
-
-func appendToSelector(selector, toAppend, position string) string {
- s := strings.Split(selector, ",")
- if position == "" {
- position = "right"
- }
- return strings.Join(slice.Map(s, func(t string) string {
- var l, r string
- if position == "right" {
- l = t
- r = toAppend
- } else {
- l = toAppend
- r = t
- }
- return str.Join(l, r)
- }), ",")
-}
-
-func __removeComment(m map[string]any) {
- delete(m, "//")
- for _, v := range m {
- mm, ok := v.(map[string]any)
- if ok {
- __removeComment(mm)
- }
- }
-}
-
-func scopeSelector(scope, selector string) string {
- scopes := strings.Split(scope, ",")
- selectors := strings.Split(selector, ",")
- var a []string
- for _, outer := range scopes {
- outer = strings.TrimSpace(outer)
- for _, inner := range selectors {
- inner = strings.TrimSpace(inner)
- if outer != "" && inner != "" {
- a = append(a, str.Join(outer, " ", inner))
- } else if outer == "" {
- a = append(a, inner)
- } else if inner == "" {
- a = append(a, outer)
- }
- }
- }
- return strings.Join(a, ", ")
-}
-
-func getBlockNodes(m map[string]any) []map[string]any {
- selectors, _ := maps.GetStrAnyVal[map[string]any](m, "blocks_metadata")
- mm, _ := maps.GetStrAnyVal[map[string]any](m, "theme_json.styles.blocks")
- var nodes []map[string]any
- for k, v := range mm {
- vv, ok := v.(map[string]any)
- if !ok {
+func (item *__parseLoadItem) allDeps(handles []string, recursion bool, group int) bool {
+ for _, handle := range handles {
+ parts := strings.Split(handle, "?")
+ queued := slice.IsContained(item.todo, parts[0])
+ handle = parts[0]
+ moved := item.setGroup(handle, group)
+ if queued || !moved {
continue
}
- s, _ := maps.GetStrAnyVal[string](selectors, str.Join(k, ".supports.selector"))
- d, _ := maps.GetStrAnyVal[string](selectors, str.Join(k, ".duotone"))
- f, _ := maps.GetStrAnyVal[string](selectors, str.Join(k, ".features"))
- n, ok := maps.GetStrAnyVal[map[string]any](vv, "variations")
- var variationSelectors []node
- if ok {
- for variation := range n {
- ss, _ := maps.GetStrAnyVal[string](selectors, str.Join(k, ".styleVariations.", variation))
- variationSelectors = append(variationSelectors, node{
- Path: []string{"styles", "blocks", k, "variations", variation},
- Selector: ss,
- })
- }
- }
- nodes = append(nodes, map[string]any{
- "name": k,
- "path": []string{"styles", "blocks", k},
- "selector": s,
- "duotone": d,
- "features": f,
- "variations": variationSelectors,
- })
- e, ok := maps.GetStrAnyVal[map[string]any](vv, "elements")
+ newGroup := item.groups[handle]
+ keepGoing := true
+ h, ok := __styles.Load(handle)
if !ok {
- continue
+ keepGoing = false
}
- for element, vvv := range e {
- _, ok = vvv.(map[string]any)
- if !ok {
+ if len(h.Deps) > 0 && len(slice.Diff(h.Deps, __styles.Keys())) > 0 {
+ keepGoing = false
+ }
+ if len(h.Deps) > 0 && item.allDeps(h.Deps, true, newGroup) {
+ keepGoing = false
+ }
+ if !keepGoing {
+ if recursion {
+ return false
+ } else {
continue
}
- key := str.Join(k, ".elements.", element)
- selector, _ := maps.GetStrAnyVal[string](selectors, key)
- nodes = append(nodes, map[string]any{
- "path": []string{"styles", "blocks", k, "elements", element},
- "selector": selector,
- })
- if val, ok := __validElementPseudoSelectors[element]; ok {
- for _, ss := range val {
- _, ok = maps.GetStrAnyVal[string](vv, str.Join("elements.", ss))
- if !ok {
- continue
- }
- nodes = append(nodes, map[string]any{
- "path": []string{"styles", "blocks", k, "elements", element},
- "selector": appendToSelector(selector, ss, ""),
- })
- }
+ }
+ if len(parts) > 1 {
+ item.args[handle] = parts[1]
+ }
+ item.todo = append(item.todo, handle)
+ }
+ return true
+}
+
+type __parseLoadItem struct {
+ todo []string
+ done []string
+ groups map[string]int
+ args map[string]string
+}
+
+func newParseLoadItem() *__parseLoadItem {
+ return &__parseLoadItem{
+ groups: map[string]int{},
+ args: map[string]string{},
+ }
+}
+
+func (item *__parseLoadItem) setGroup(handle string, group int) bool {
+ if v, ok := item.groups[handle]; ok && v <= group {
+ return false
+ }
+ item.groups[handle] = group
+ return true
+}
+
+func DoStyleItems(h *wp.Handle, handles []string, group int) []string {
+ item := newParseLoadItem()
+ item.allDeps(handles, false, 0)
+ for i, handle := range item.todo {
+ _, ok := __styles.Load(handle)
+ if !slice.IsContained(item.done, handle) && ok {
+ if DoStyleItem(h, item, handle, group) {
+ item.done = append(item.done, handle)
}
+ slice.Delete(&item.todo, i)
}
}
- return nodes
+ return item.done
}
-func getSettingNodes(m, setting map[string]any) []node {
- var nodes []node
- nodes = append(nodes, node{
- Path: []string{"settings"},
- Selector: RootBlockSelector,
- })
- selectors, _ := maps.GetStrAnyVal[map[string]any](m, "blocks_metadata")
- s, ok := maps.GetStrAnyVal[map[string]any](setting, "settings.blocks")
- if !ok {
- return nil
+func DoStyleItem(h *wp.Handle, item *__parseLoadItem, handle string, group int) bool {
+ obj, _ := __styles.Load(handle)
+ ver := obj.Ver
+ if v, ok := item.args[handle]; ok {
+ ver = helper.Or(ver == "", v, str.Join(ver, "&", v))
}
- for name := range s {
- selector, ok := maps.GetStrAnyVal[string](selectors, str.Join(name, ".supports.selector"))
- if ok {
- nodes = append(nodes, node{
- Path: []string{"settings", "blocks", name},
- Selector: selector,
- })
- }
+ src := obj.Src
+ var condBefore, condAfter, conditional string
+ if v, ok := obj.Extra["conditional"]; ok && v != nil {
+ conditional = v[0]
}
- return nodes
+ if conditional != "" {
+ condBefore = str.Join("\n")
+ condAfter = "\n"
+ }
+ inlineStyle := PrintInline(item, handle)
+
+ return true
}
-type ThemeJson struct {
- blocksMetaData map[string]any
- themeJson map[string]any
-}
-
-var validOrigins = []string{"default", "blocks", "theme", "custom"}
-
-var layoutSelectorReg = regexp.MustCompile(`^[a-zA-Z0-9\-. *+>:()]*$`)
-
-var validDisplayModes = []string{"block", "flex", "grid"}
-
-func (j ThemeJson) getLayoutStyles(nodes node) string {
- //todo current theme supports disable-layout-styles
- var blockType map[string]any
- var s strings.Builder
- if nodes.Name != "" {
- v, ok := maps.GetStrAnyVal[map[string]any](j.blocksMetaData, nodes.Name)
- if ok {
- vv, ok := maps.GetStrAnyVal[map[string]any](v, "supports.__experimentalLayout")
- if ok && vv == nil {
- return ""
- }
- blockType = vv
- }
- }
- gap, hasBlockGapSupport := maps.GetStrAnyVal[map[string]any](j.themeJson, "settings.spacing.blockGap")
- if gap == nil {
- hasBlockGapSupport = false
- }
- _, ok := maps.GetStrAnyVal[map[string]any](j.themeJson, strings.Join(nodes.Path, "."))
- if !ok {
+func PrintInline(item *__parseLoadItem, handle string) string {
+ sty, _ := __styles.Load(handle)
+ out := sty.getData("after")
+ if out == "" {
return ""
}
- layoutDefinitions, ok := maps.GetStrAnyVal[map[string]any](j.themeJson, "settings.layout.definitions")
- if !ok {
- return ""
- }
- blockGapValue := ""
- if !hasBlockGapSupport {
- if RootBlockSelector == nodes.Selector {
- blockGapValue = "0.5em"
- }
- if blockType != nil {
- blockGapValue, _ = maps.GetStrAnyVal[string](blockType, "supports.spacing.blockGap.__experimentalDefault")
- }
- } else {
- //todo getPropertyValue()
- }
- if blockGapValue != "" {
- for key, v := range layoutDefinitions {
- definition, ok := v.(map[string]any)
- if !ok {
- continue
- }
- if !hasBlockGapSupport && "flex" != key {
- continue
- }
- className := maps.GetStrAnyValWithDefaults(definition, "className", "")
- spacingRules := maps.GetStrAnyValWithDefaults(definition, "spacingStyles", []any{})
- if className == "" || spacingRules == nil {
- continue
- }
- for _, rule := range spacingRules {
- var declarations []declaration
- spacingRule, ok := rule.(map[string]any)
- if !ok {
- continue
- }
- selector := maps.GetStrAnyValWithDefaults(spacingRule, "selector", "")
- rules := maps.GetStrAnyValWithDefaults(spacingRule, "rules", map[string]any(nil))
- if selector != "" && !layoutSelectorReg.MatchString(selector) || rules == nil {
- continue
- }
- for property, v := range rules {
- value, ok := v.(string)
- if !ok || value == "" {
- value = blockGapValue
- }
- if isSafeCssDeclaration(property, value) {
- declarations = append(declarations, declaration{property, value})
- }
- }
- format := ""
- if !hasBlockGapSupport {
- format = helper.Or(RootBlockSelector == nodes.Selector, ":where(.%[2]s%[3]s)", ":where(%[1]s.%[2]s%[3]s)")
- } else {
- format = helper.Or(RootBlockSelector == nodes.Selector, "%s .%s%s", "%s.%s%s")
- }
- layoutSelector := fmt.Sprintf(format, nodes.Selector, className, selector)
- s.WriteString(toRuleset(layoutSelector, declarations))
- }
- }
- }
-
- if RootBlockSelector == nodes.Selector {
- for _, v := range layoutDefinitions {
- definition, ok := v.(map[string]any)
- if !ok {
- continue
- }
- className := maps.GetStrAnyValWithDefaults(definition, "className", "")
- baseStyleRules := maps.GetStrAnyValWithDefaults(definition, "baseStyles", []any{})
- if className == "" || nil == baseStyleRules {
- continue
- }
- displayMode := maps.GetStrAnyValWithDefaults(definition, "displayMode", "")
- if displayMode != "" && slice.IsContained(validDisplayModes, displayMode) {
- layoutSelector := str.Join(nodes.Selector, " .", className)
- s.WriteString(toRuleset(layoutSelector, []declaration{{"display", displayMode}}))
- }
- for _, rule := range baseStyleRules {
- var declarations []declaration
- r, ok := rule.(map[string]any)
- if !ok {
- continue
- }
- selector := maps.GetStrAnyValWithDefaults(r, "selector", "")
- rules := maps.GetStrAnyValWithDefaults(r, "rules", map[string]any(nil))
- if selector != "" && !layoutSelectorReg.MatchString(selector) || rules == nil {
- continue
- }
- for property, value := range rules {
- val, ok := value.(string)
- if !ok || val == "" {
- continue
- }
- if isSafeCssDeclaration(property, val) {
- declarations = append(declarations, declaration{property, val})
- }
- }
- layoutSelector := str.Join(nodes.Selector, " .", className, selector)
- s.WriteString(toRuleset(layoutSelector, declarations))
- }
- }
- }
-
+ s := str.NewBuilder()
+ s.Sprintf("\n", handle)
return s.String()
}
-
-func isSafeCssDeclaration(name, value string) bool {
- css := str.Join(name, ": ", value)
- s := safeCSSFilterAttr(css)
- return "" != html.EscapeString(s)
-}
-
-var kses = regexp.MustCompile(`[\x00-\x08\x0B\x0C\x0E-\x1F]`)
-var ksesop = regexp.MustCompile(`\\\\+0+`)
-
-func KsesNoNull(s string, op ...bool) string {
- s = kses.ReplaceAllString(s, "")
- ops := true
- if len(op) > 0 {
- ops = op[0]
- }
- if ops {
- s = ksesop.ReplaceAllString(s, "")
- }
- return s
-}
-
-var allowedProtocols = []string{
- "http", "https", "ftp", "ftps", "mailto", "news", "irc", "irc6", "ircs", "gopher", "nntp",
- "feed", "telnet", "mms", "rtsp", "sms", "svn", "tel", "fax", "xmpp", "webcal", "urn",
-}
-
-var allowCssAttr = []string{
- "background", "background-color", "background-image", "background-position", "background-size", "background-attachment", "background-blend-mode",
- "border", "border-radius", "border-width", "border-color", "border-style", "border-right", "border-right-color",
- "border-right-style", "border-right-width", "border-bottom", "border-bottom-color", "border-bottom-left-radius",
- "border-bottom-right-radius", "border-bottom-style", "border-bottom-width", "border-bottom-right-radius",
- "border-bottom-left-radius", "border-left", "border-left-color", "border-left-style", "border-left-width",
- "border-top", "border-top-color", "border-top-left-radius", "border-top-right-radius", "border-top-style",
- "border-top-width", "border-top-left-radius", "border-top-right-radius", "border-spacing", "border-collapse",
- "caption-side", "columns", "column-count", "column-fill", "column-gap", "column-rule", "column-span", "column-width",
- "color", "filter", "font", "font-family", "font-size", "font-style", "font-variant", "font-weight",
- "letter-spacing", "line-height", "text-align", "text-decoration", "text-indent", "text-transform", "height",
- "min-height", "max-height", "width", "min-width", "max-width", "margin", "margin-right", "margin-bottom",
- "margin-left", "margin-top", "margin-block-start", "margin-block-end", "margin-inline-start", "margin-inline-end",
- "padding", "padding-right", "padding-bottom", "padding-left", "padding-top", "padding-block-start",
- "padding-block-end", "padding-inline-start", "padding-inline-end", "flex", "flex-basis", "flex-direction",
- "flex-flow", "flex-grow", "flex-shrink", "flex-wrap", "gap", "column-gap", "row-gap", "grid-template-columns",
- "grid-auto-columns", "grid-column-start", "grid-column-end", "grid-column-gap", "grid-template-rows",
- "grid-auto-rows", "grid-row-start", "grid-row-end", "grid-row-gap", "grid-gap", "justify-content", "justify-items",
- "justify-self", "align-content", "align-items", "align-self", "clear", "cursor", "direction", "float",
- "list-style-type", "object-fit", "object-position", "overflow", "vertical-align", "position", "top", "right",
- "bottom", "left", "z-index", "aspect-ratio", "--*",
-}
-var allowCssAttrMap = slice.FilterAndToMap(allowCssAttr, func(t string) (string, struct{}, bool) {
- return t, struct{}{}, true
-})
-
-var __strReg = regexp.MustCompile(`^--[a-zA-Z0-9-_]+$`)
-var cssUrlDataTypes = []string{"background", "background-image", "cursor", "list-style", "list-style-image"}
-var cssGradientDataTypes = []string{"background", "background-image"}
-var __allowCSSReg = regexp2.MustCompile(`\b(?:var|calc|min|max|minmax|clamp)(\((?:[^()]|(?!1))*\))`, regexp2.None)
-var __disallowCSSReg = regexp.MustCompile(`[\\(&=}]|/\*`)
-
-func safeCSSFilterAttr(css string) string {
- css = KsesNoNull(css)
- css = strings.TrimSpace(css)
- css = str.Replaces(css, []string{"\n", "\r", "\t", ""})
- cssArr := strings.Split(css, ";")
- var isCustomVar, found, urlAttr, gradientAttr bool
- var cssValue string
- var ss strings.Builder
- for _, s := range cssArr {
- if s == "" {
- continue
- }
- if !strings.Contains(s, ":") {
- found = true
- } else {
- parts := strings.SplitN(s, ":", 2)
- selector := strings.TrimSpace(parts[0])
- if maps.IsExists(allowCssAttrMap, "--*") {
- i := __strReg.FindStringIndex(selector)
- if len(i) > 0 && i[0] > 0 {
- isCustomVar = true
- allowCssAttr = append(allowCssAttr, selector)
- }
- }
- if maps.IsExists(allowCssAttrMap, selector) {
- found = true
- urlAttr = slice.IsContained(cssUrlDataTypes, selector)
- gradientAttr = slice.IsContained(cssGradientDataTypes, selector)
- }
- if isCustomVar {
- cssValue = strings.TrimSpace(parts[1])
- urlAttr = cssValue[0:4] == "url("
- gradientAttr = strings.Contains(cssValue, "-gradient(")
- }
- }
-
- if found {
- //todo wtf 🤮
- if urlAttr {
-
- }
- if gradientAttr {
-
- }
- cssTest, _ := __allowCSSReg.Replace(s, "", 0, -1)
- isAllow := !__disallowCSSReg.MatchString(cssTest)
- if isAllow {
- ss.WriteString(s)
- ss.WriteString(";")
- }
- }
-
- }
- return strings.TrimRight(ss.String(), ";")
-}
-
-func (j ThemeJson) getStyletSheet(types, origins []string, options map[string]string) string {
- if origins == nil {
- origins = append(validOrigins)
- }
- styleNodes := getStyleNodes(j)
- settingsNodes := getSettingNodes(j.blocksMetaData, j.themeJson)
- rootStyleKey, _ := slice.SearchFirst(styleNodes, func(n node) bool {
- return n.Selector == RootBlockSelector
- })
- rootSettingsKey, _ := slice.SearchFirst(settingsNodes, func(n node) bool {
- return n.Selector == RootBlockSelector
- })
- if os, ok := options["scope"]; ok {
- for i := range settingsNodes {
- settingsNodes[i].Selector = scopeSelector(os, settingsNodes[i].Selector)
- }
- for i := range styleNodes {
- styleNodes[i].Selector = scopeSelector(os, styleNodes[i].Selector)
- }
- }
- if or, ok := options["root_selector"]; ok && or != "" {
- if rootSettingsKey > -1 {
- settingsNodes[rootSettingsKey].Selector = or
- }
- if rootStyleKey > -1 && rootStyleKey < len(settingsNodes) {
- settingsNodes[rootStyleKey].Selector = or
- }
- }
- stylesSheet := ""
- if slice.IsContained(types, "variables") {
- stylesSheet = j.getCssVariables(settingsNodes, origins)
- }
-
- if slice.IsContained(types, "styles") {
- stylesSheet = j.getCssVariables(settingsNodes, origins)
- if rootStyleKey > -1 {
- //todo getRootLayoutRules
- stylesSheet = str.Join(stylesSheet)
- }
- } else if slice.IsContained(types, "base-layout-styles") {
- rootSelector := RootBlockSelector
- columnsSelector := ".wp-block-columns"
- scope, ok := options["scope"]
- if ok && scope != "" {
- rootSelector = scopeSelector(scope, rootSelector)
- columnsSelector = scopeSelector(scope, columnsSelector)
- }
- rs, ok := options["root_selector"]
- if ok && rs != "" {
- rootSelector = rs
- }
- baseStylesNodes := []node{
- {
- Path: []string{"styles"},
- Selector: rootSelector,
- },
- {
- Path: []string{"styles", "blocks", "core/columns"},
- Selector: columnsSelector,
- Name: "core/columns",
- },
- }
- for _, stylesNode := range baseStylesNodes {
- stylesSheet = str.Join(stylesSheet, j.getLayoutStyles(stylesNode))
- }
- }
-
- if slice.IsContained(types, "presets") {
- stylesSheet = str.Join(stylesSheet, j.getPresetClasses(settingsNodes, origins))
- }
-
- return stylesSheet
-}
-
-func (j ThemeJson) getPresetClasses(nodes []node, origins []string) string {
- var presetRules strings.Builder
- for _, n := range nodes {
- if n.Selector == "" {
- continue
- }
- no, ok := maps.GetStrAnyVal[map[string]any](j.themeJson, strings.Join(n.Path, "."))
- if !ok {
- continue
- }
- presetRules.WriteString(computePresetClasses(no, n.Selector, origins))
- }
- return presetRules.String()
-}
-
-func computePresetClasses(m map[string]any, selector string, origins []string) string {
- if selector == RootBlockSelector {
- selector = ""
- }
- var s strings.Builder
- for _, meta := range presetsMetadata {
- slugs := getSettingsSlugs(m, meta, origins)
- for class, property := range meta.classes {
- for _, slug := range slugs {
- cssVar := strings.ReplaceAll(meta.cssVars, "$slug", slug)
- className := strings.ReplaceAll(class, "$slug", slug)
- s.WriteString(toRuleset(appendToSelector(selector, className, ""), []declaration{
- {property, str.Join("var(", cssVar, ") !important")},
- }))
- }
- }
- }
- return s.String()
-}
-
-func getSettingsSlugs(settings map[string]any, meta presetMeta, origins []string) map[string]string {
- if origins == nil {
- origins = validOrigins
- }
-
- presetPerOrigin, ok := maps.GetStrAnyVal[map[string]any](settings, strings.Join(meta.path, "."))
- if !ok {
- return nil
- }
- m := map[string]string{}
- for _, origin := range origins {
- o, ok := maps.GetStrAnyVal[[]map[string]string](presetPerOrigin, origin)
- if !ok {
- continue
- }
- for _, mm := range o {
- slug := toKebabCase(mm["slug"])
- m[slug] = slug
- }
- }
- return m
-}
-
-func toKebabCase(s string) string {
- s = strings.ReplaceAll(s, "'", "")
- r, err := __kebabCaseReg.FindStringMatch(s)
- if err != nil {
- return s
- }
- var ss []string
- for r != nil {
- if r.GroupCount() < 1 {
- break
- }
-
- ss = append(ss, r.Groups()[0].String())
- r, _ = __kebabCaseReg.FindNextMatch(r)
- }
-
- return strings.ToLower(strings.Join(ss, "-"))
-}
-
-var __kebabCaseReg = func() *regexp2.Regexp {
- rsLowerRange := "a-z\\xdf-\\xf6\\xf8-\\xff"
- rsNonCharRange := "\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf"
- rsPunctuationRange := "\\x{2000}-\\x{206f}"
- rsSpaceRange := " \\t\\x0b\\f\\xa0\\x{feff}\\n\\r\\x{2028}\\x{2029}\\x{1680}\\x{180e}\\x{2000}\\x{2001}\\x{2002}\\x{2003}\\x{2004}\\x{2005}\\x{2006}\\x{2007}\\x{2008}\\x{2009}\\x{200a}\\x{202f}\\x{205f}\\x{3000}"
- rsUpperRange := "A-Z\\xc0-\\xd6\\xd8-\\xde"
- rsBreakRange := rsNonCharRange + rsPunctuationRange + rsSpaceRange
-
- /** Used to compose unicode capture groups. */
- rsBreak := "[" + rsBreakRange + "]"
- rsDigits := "\\d+" // The last lodash version in GitHub uses a single digit here and expands it when in use.
- rsLower := "[" + rsLowerRange + "]"
- rsMisc := "[^" + rsBreakRange + rsDigits + rsLowerRange + rsUpperRange + "]"
- rsUpper := "[" + rsUpperRange + "]"
-
- /** Used to compose unicode regexes. */
- rsMiscLower := "(?:" + rsLower + "|" + rsMisc + ")"
- rsMiscUpper := "(?:" + rsUpper + "|" + rsMisc + ")"
- rsOrdLower := "\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])"
- rsOrdUpper := "\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])"
-
- reg := strings.Join([]string{
- rsUpper + "?" + rsLower + "+(?=" + strings.Join([]string{rsBreak, rsUpper, "$"}, "|") + ")",
- rsMiscUpper + "+(?=" + strings.Join([]string{rsBreak, rsUpper + rsMiscLower, "$"}, "|") + ")",
- rsUpper + "?" + rsMiscLower + "+",
- rsUpper + "+",
- rsOrdUpper,
- rsOrdLower,
- rsDigits,
- }, "|")
- return regexp2.MustCompile(reg, regexp2.Unicode)
-}()
-
-var presetsMetadata = []presetMeta{
- {
- path: []string{"color", "palette"},
- preventOverride: []string{"color", "defaultPalette"},
- useDefaultNames: false,
- valueKey: "color",
- valueFunc: nil,
- cssVars: "--wp--preset--color--$slug",
- classes: map[string]string{
- ".has-$slug-color": "color",
- ".has-$slug-background-color": "background-color",
- ".has-$slug-border-color": "border-color",
- },
- properties: []string{"color", "background-color", "border-color"},
- }, {
- path: []string{"color", "gradients"},
- preventOverride: []string{"color", "defaultGradients"},
- useDefaultNames: false,
- valueKey: "gradient",
- valueFunc: nil,
- cssVars: "--wp--preset--gradient--$slug",
- classes: map[string]string{
- ".has-$slug-gradient-background": "background",
- },
- properties: []string{"background"},
- }, {
- path: []string{"color", "duotone"},
- preventOverride: []string{"color", "defaultDuotone"},
- useDefaultNames: false,
- valueKey: "",
- valueFunc: wpGetDuotoneFilterProperty,
- cssVars: "--wp--preset--duotone--$slug",
- classes: map[string]string{},
- properties: []string{"filter"},
- }, {
- path: []string{"typography", "fontSizes"},
- preventOverride: []string{},
- useDefaultNames: true,
- valueKey: "",
- valueFunc: wpGetTypographyFontSizeValue,
- cssVars: "--wp--preset--font-size--$slug",
- classes: map[string]string{
- ".has-$slug-font-size": "font-size",
- },
- properties: []string{"font-size"},
- }, {
- path: []string{"typography", "fontFamilies"},
- preventOverride: []string{},
- useDefaultNames: false,
- valueKey: "fontFamily",
- valueFunc: nil,
- cssVars: "--wp--preset--font-family--$slug",
- classes: map[string]string{
- ".has-$slug-font-family": "font-family",
- },
- properties: []string{"font-family"},
- }, {
- path: []string{"spacing", "spacingSizes"},
- preventOverride: []string{},
- useDefaultNames: true,
- valueKey: "size",
- valueFunc: nil,
- cssVars: "--wp--preset--spacing--$slug",
- classes: map[string]string{},
- properties: []string{"padding", "margin"},
- }, {
- path: []string{"shadow", "presets"},
- preventOverride: []string{"shadow", "defaultPresets"},
- useDefaultNames: false,
- valueKey: "shadow",
- valueFunc: nil,
- cssVars: "--wp--preset--shadow--$slug",
- classes: map[string]string{},
- properties: []string{"box-shadow"},
- },
-}
-
-type presetMeta struct {
- path []string
- preventOverride []string
- useDefaultNames bool
- valueFunc func(map[string]string, map[string]any) string
- valueKey string
- cssVars string
- classes map[string]string
- properties []string
-}
-
-type declaration struct {
- name string
- value string
-}
-
-func wpGetDuotoneFilterProperty(preset map[string]string, _ map[string]any) string {
- v, ok := preset["colors"]
- if ok && "unset" == v {
- return "none"
- }
- id, ok := preset["slug"]
- if ok {
- id = str.Join("wp-duotone-", id)
- }
- return str.Join(`url('#`, id, "')")
-}
-
-func wpGetTypographyFontSizeValue(preset map[string]string, m map[string]any) string {
- size, ok := preset["size"]
- if !ok {
- return ""
- }
- if size == "" || size == "0" {
- return size
- }
- origin := "custom"
- if !wpconfig.HasThemeJson() {
- origin = "theme"
- }
- typographySettings, ok := maps.GetStrAnyVal[map[string]any](m, "typography")
- if !ok {
- return size
- }
- fluidSettings, ok := maps.GetStrAnyVal[map[string]any](typographySettings, "fluid")
-
- //todo so complex dying 👻
- _ = fluidSettings
- _ = origin
- return size
-}
-
-var __themeJson = reload.Vars(ThemeJson{})
-
-func GetThemeJson() ThemeJson {
- return __themeJson.Load()
-}
-
-func wpGetTypographyValueAndUnit(value string, options map[string]any) {
- /*options := maps.Merge(options, map[string]any{
- "coerce_to": "",
- "root_size_value": 16,
- "acceptable_units": []string{"rem", "px", "em"},
- })
- u, _ := maps.GetStrAnyVal[[]string](options, "acceptable_units")
- acceptableUnitsGroup := strings.Join(u, "|")*/
-
-}
-
-func computeThemeVars(m map[string]any) []declaration {
- //todo ......
- return nil
-}
-
-func computePresetVars(m map[string]any, origins []string) []declaration {
- var declarations []declaration
- for _, metadatum := range presetsMetadata {
- slug := getSettingsValuesBySlug(m, metadatum, origins)
- for k, v := range slug {
- declarations = append(declarations, declaration{
- name: strings.Replace(metadatum.cssVars, "$slug", k, -1),
- value: v,
- })
- }
- }
- return declarations
-}
-
-func getSettingsValuesBySlug(m map[string]any, meta presetMeta, origins []string) map[string]string {
- perOrigin := maps.GetStrAnyValWithDefaults[map[string]any](m, strings.Join(meta.path, "."), nil)
- r := map[string]string{}
- for _, origin := range origins {
- if vv, ok := maps.GetStrAnyVal[[]map[string]string](perOrigin, origin); ok {
- for _, preset := range vv {
- slug := preset["slug"]
- value := ""
- if vv, ok := preset[meta.valueKey]; ok && vv != "" {
- value = vv
- } else if meta.valueFunc != nil {
- value = meta.valueFunc(preset, m)
- }
- r[slug] = value
- }
- }
- }
- return r
-}
-
-func setSpacingSizes(t ThemeJson) {
- m, _ := maps.GetStrAnyVal[map[string]any](t.themeJson, "settings.spacing.spacingScale")
- unit, _ := maps.GetStrAnyVal[string](m, "unit")
- currentStep, _ := maps.GetStrAnyVal[float64](m, "mediumStep")
- mediumStep := currentStep
- steps, _ := maps.GetStrAnyVal[float64](m, "steps")
- operator, _ := maps.GetStrAnyVal[string](m, "operator")
- increment, _ := maps.GetStrAnyVal[float64](m, "increment")
- stepsMidPoint := math.Round(steps / 2)
- reminder := float64(0)
- xSmallCount := ""
- var sizes []map[string]string
- slug := 40
- for i := stepsMidPoint - 1; i > 0 && slug > 0 && steps > 1; i-- {
- if "+" == operator {
- currentStep -= increment
- } else if increment > 1 {
- currentStep /= increment
- } else {
- currentStep *= increment
- }
- if currentStep <= 0 {
- reminder = i
- break
- }
- name := "small"
- if i != stepsMidPoint-1 {
- name = str.Join(xSmallCount, "X-Small")
- }
- sizes = append(sizes, map[string]string{
- "name": name,
- "slug": number.IntToString(slug),
- "size": fmt.Sprintf("%v%s", number.Round(currentStep, 2), unit),
- })
- if i == stepsMidPoint-2 {
- xSmallCount = strconv.Itoa(2)
- }
- if i < stepsMidPoint-2 {
- n := str.ToInt[int](xSmallCount)
- n++
- xSmallCount = strconv.Itoa(n)
- }
- slug -= 10
- }
- slice.ReverseSelf(sizes)
- sizes = append(sizes, map[string]string{
- "name": "Medium",
- "slug": "50",
- "size": str.Join(number.ToString(mediumStep), unit),
- })
- currentStep = mediumStep
- slug = 60
- xLargeCount := ""
- stepsAbove := steps - stepsMidPoint + reminder
- for aboveMidpointCount := float64(0); aboveMidpointCount < stepsAbove; aboveMidpointCount++ {
- if "+" == operator {
- currentStep += increment
- } else if increment >= 1 {
- currentStep *= increment
- } else {
- currentStep /= increment
- }
- name := "Large"
- if 0 != aboveMidpointCount {
- name = str.Join(xLargeCount, "X-Large")
- }
- sizes = append(sizes, map[string]string{
- "name": name,
- "slug": strconv.Itoa(slug),
- "size": fmt.Sprintf("%v%s", number.Round(currentStep, 2), unit),
- })
- if aboveMidpointCount == 1 {
- xLargeCount = strconv.Itoa(2)
- }
- if aboveMidpointCount > 1 {
- x := str.ToInt[int](xLargeCount)
- x++
- xLargeCount = strconv.Itoa(x)
- }
- slug += 10
- }
- if steps <= 7 {
- for i := 0; i < len(sizes); i++ {
- sizes[i]["name"] = strconv.Itoa(i + 1)
- }
- }
- maps.SetStrAnyVal(t.themeJson, "settings.spacing.spacingSizes.default", sizes)
-}
-
-func (j ThemeJson) getCssVariables(settingNodes []node, origins []string) string {
- var s strings.Builder
- for _, settingNode := range settingNodes {
- if "" == settingNode.Selector {
- continue
- }
- n := maps.GetStrAnyValWithDefaults[map[string]any](j.themeJson, strings.Join(settingNode.Path, "."), nil)
- declarations := computePresetVars(n, origins)
- declarations = append(declarations, computeThemeVars(j.themeJson)...)
- s.WriteString(toRuleset(settingNode.Selector, declarations))
- }
- return s.String()
-}
-
-func toRuleset(selector string, declarations []declaration) string {
- if len(declarations) < 1 {
- return ""
- }
- s := slice.Reduce(declarations, func(t declaration, r string) string {
- return str.Join(r, t.name, ":", t.value, ";")
- }, "")
- return str.Join(selector, "{", s, "}")
-}
-
-func getStyleNodes(t ThemeJson) []node {
- var styleNodes = []node{
- {[]string{"styles"}, "body", ""},
- }
- m := maps.GetStrAnyValWithDefaults[map[string]any](t.themeJson, "styles.elements", nil)
- if len(m) < 1 {
- return nil
- }
- for e, s := range __elements {
- _, ok := m[e]
- if !ok {
- continue
- }
- styleNodes = append(styleNodes, node{[]string{"styles", "elements", e}, s, ""})
- ss, ok := __validElementPseudoSelectors[e]
- if ok {
- for _, sel := range ss {
- if maps.IsExists(__elements, sel) {
- styleNodes = append(styleNodes, node{
- Path: []string{"styles", "elements", e},
- Selector: appendToSelector(s, sel, ""),
- })
- }
- }
- }
- }
- blocks, _ := maps.GetStrAnyVal[map[string]any](t.blocksMetaData, "theme_json.styles.blocks")
- maps.SetStrAnyVal(t.themeJson, "styles.blocks", blocks)
- blockNodes := getBlockNodes(t.blocksMetaData)
- for _, blockNode := range blockNodes {
- p, ok := maps.GetStrAnyVal[[]string](blockNode, "path")
- s, oo := maps.GetStrAnyVal[string](blockNode, "selector")
- if ok && oo {
- _ = append(styleNodes, node{Path: p, Selector: s})
- //styleNodes = append(styleNodes, node{Path: p, Selector: s})
- }
- }
-
- return styleNodes
-}
-
-func GetGlobalStyletSheet() string {
- t := __themeJson.Load()
- var types, origins []string
- if types == nil && !wpconfig.HasThemeJson() {
- types = []string{"variables", "presets", "base-layout-styles"}
- } else if types == nil {
- types = []string{"variables", "styles", "presets"}
- }
- styleSheet := ""
- if slice.IsContained(types, "variables") {
- origins = []string{"default", "theme", "custom"}
- styleSheet = t.getStyletSheet([]string{"variables"}, origins, nil)
- slice.Delete(&types, slice.IndexOf(types, "variables"))
- }
-
- if len(types) > 0 {
- origins = []string{"default", "theme", "custm"}
- if !wpconfig.HasThemeJson() {
- origins = []string{"default"}
- }
- styleSheet = str.Join(styleSheet, t.getStyletSheet(types, origins, nil))
- }
-
- return styleSheet
-}
-
-/*func (j ThemeJson) getStylesForBlock(blockMeta map[string]any) {
- path, _ := maps.GetStrAnyVal[[]string](blockMeta, "path")
- node, _ := maps.GetStrAnyVal[map[string]any](j.themeJson, strings.Join(path, "."))
- useRootPadding := maps.GetStrAnyValWithDefaults(j.themeJson, "settings.useRootPaddingAwareAlignments", false)
- settings, _ := maps.GetStrAnyVal(j.themeJson, "settings")
- is_processing_element := slice.IsContained(path, "elements")
- currentElement := ""
- if is_processing_element {
- currentElement = path[len(path)-1]
- }
- element_pseudo_allowed := __validElementPseudoSelectors[currentElement]
-
-}
-
-func computeStyleProperties(styles, settings, properties, themeJson map[string]any, selector string, useRootPadding bool) {
- if properties == nil {
- //properties =
- }
-}
-*/
diff --git a/app/theme/wp/scriptloader/wtf.go b/app/theme/wp/scriptloader/wtf.go
new file mode 100644
index 0000000..ccd3d5b
--- /dev/null
+++ b/app/theme/wp/scriptloader/wtf.go
@@ -0,0 +1,1011 @@
+package scriptloader
+
+import (
+ "fmt"
+ "github.com/dlclark/regexp2"
+ "github.com/fthvgb1/wp-go/app/cmd/reload"
+ "github.com/fthvgb1/wp-go/app/wpconfig"
+ "github.com/fthvgb1/wp-go/helper"
+ "github.com/fthvgb1/wp-go/helper/maps"
+ "github.com/fthvgb1/wp-go/helper/number"
+ "github.com/fthvgb1/wp-go/helper/slice"
+ str "github.com/fthvgb1/wp-go/helper/strings"
+ "html"
+ "math"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+var __elements = map[string]string{
+ "link": "a:where(:not(.wp-element-button))", // The `where` is needed to lower the specificity.
+ "heading": "h1, h2, h3, h4, h5, h6",
+ "h1": "h1",
+ "h2": "h2",
+ "h3": "h3",
+ "h4": "h4",
+ "h5": "h5",
+ "h6": "h6",
+ // We have the .wp-block-button__link class so that this will target older buttons that have been serialized.
+ "button": ".wp-element-button, .wp-block-button__link",
+ // The block classes are necessary to target older content that won't use the new class names.
+ "caption": ".wp-element-caption, .wp-block-audio figcaption, .wp-block-embed figcaption, .wp-block-gallery figcaption, .wp-block-image figcaption, .wp-block-table figcaption, .wp-block-video figcaption",
+ "cite": "cite",
+}
+
+const RootBlockSelector = "body"
+
+type node struct {
+ Path []string
+ Selector string
+ Name string
+}
+
+var __validElementPseudoSelectors = map[string][]string{
+ "link": {":link", ":any-link", ":visited", ":hover", ":focus", ":active"},
+ "button": {":link", ":any-link", ":visited", ":hover", ":focus", ":active"},
+}
+
+var blockSupportFeatureLevelSelectors = map[string]string{
+ "__experimentalBorder": "border",
+ "color": "color",
+ "spacing": "spacing",
+ "typography": "typography",
+}
+
+func appendToSelector(selector, toAppend, position string) string {
+ s := strings.Split(selector, ",")
+ if position == "" {
+ position = "right"
+ }
+ return strings.Join(slice.Map(s, func(t string) string {
+ var l, r string
+ if position == "right" {
+ l = t
+ r = toAppend
+ } else {
+ l = toAppend
+ r = t
+ }
+ return str.Join(l, r)
+ }), ",")
+}
+
+func __removeComment(m map[string]any) {
+ delete(m, "//")
+ for _, v := range m {
+ mm, ok := v.(map[string]any)
+ if ok {
+ __removeComment(mm)
+ }
+ }
+}
+
+func scopeSelector(scope, selector string) string {
+ scopes := strings.Split(scope, ",")
+ selectors := strings.Split(selector, ",")
+ var a []string
+ for _, outer := range scopes {
+ outer = strings.TrimSpace(outer)
+ for _, inner := range selectors {
+ inner = strings.TrimSpace(inner)
+ if outer != "" && inner != "" {
+ a = append(a, str.Join(outer, " ", inner))
+ } else if outer == "" {
+ a = append(a, inner)
+ } else if inner == "" {
+ a = append(a, outer)
+ }
+ }
+ }
+ return strings.Join(a, ", ")
+}
+
+func getBlockNodes(m map[string]any) []map[string]any {
+ selectors, _ := maps.GetStrAnyVal[map[string]any](m, "blocks_metadata")
+ mm, _ := maps.GetStrAnyVal[map[string]any](m, "theme_json.styles.blocks")
+ var nodes []map[string]any
+ for k, v := range mm {
+ vv, ok := v.(map[string]any)
+ if !ok {
+ continue
+ }
+ s, _ := maps.GetStrAnyVal[string](selectors, str.Join(k, ".supports.selector"))
+ d, _ := maps.GetStrAnyVal[string](selectors, str.Join(k, ".duotone"))
+ f, _ := maps.GetStrAnyVal[string](selectors, str.Join(k, ".features"))
+ n, ok := maps.GetStrAnyVal[map[string]any](vv, "variations")
+ var variationSelectors []node
+ if ok {
+ for variation := range n {
+ ss, _ := maps.GetStrAnyVal[string](selectors, str.Join(k, ".styleVariations.", variation))
+ variationSelectors = append(variationSelectors, node{
+ Path: []string{"styles", "blocks", k, "variations", variation},
+ Selector: ss,
+ })
+ }
+ }
+ nodes = append(nodes, map[string]any{
+ "name": k,
+ "path": []string{"styles", "blocks", k},
+ "selector": s,
+ "duotone": d,
+ "features": f,
+ "variations": variationSelectors,
+ })
+ e, ok := maps.GetStrAnyVal[map[string]any](vv, "elements")
+ if !ok {
+ continue
+ }
+ for element, vvv := range e {
+ _, ok = vvv.(map[string]any)
+ if !ok {
+ continue
+ }
+ key := str.Join(k, ".elements.", element)
+ selector, _ := maps.GetStrAnyVal[string](selectors, key)
+ nodes = append(nodes, map[string]any{
+ "path": []string{"styles", "blocks", k, "elements", element},
+ "selector": selector,
+ })
+ if val, ok := __validElementPseudoSelectors[element]; ok {
+ for _, ss := range val {
+ _, ok = maps.GetStrAnyVal[string](vv, str.Join("elements.", ss))
+ if !ok {
+ continue
+ }
+ nodes = append(nodes, map[string]any{
+ "path": []string{"styles", "blocks", k, "elements", element},
+ "selector": appendToSelector(selector, ss, ""),
+ })
+ }
+ }
+ }
+ }
+ return nodes
+}
+
+func getSettingNodes(m, setting map[string]any) []node {
+ var nodes []node
+ nodes = append(nodes, node{
+ Path: []string{"settings"},
+ Selector: RootBlockSelector,
+ })
+ selectors, _ := maps.GetStrAnyVal[map[string]any](m, "blocks_metadata")
+ s, ok := maps.GetStrAnyVal[map[string]any](setting, "settings.blocks")
+ if !ok {
+ return nil
+ }
+ for name := range s {
+ selector, ok := maps.GetStrAnyVal[string](selectors, str.Join(name, ".supports.selector"))
+ if ok {
+ nodes = append(nodes, node{
+ Path: []string{"settings", "blocks", name},
+ Selector: selector,
+ })
+ }
+ }
+ return nodes
+}
+
+type ThemeJson struct {
+ blocksMetaData map[string]any
+ themeJson map[string]any
+}
+
+var validOrigins = []string{"default", "blocks", "theme", "custom"}
+
+var layoutSelectorReg = regexp.MustCompile(`^[a-zA-Z0-9\-. *+>:()]*$`)
+
+var validDisplayModes = []string{"block", "flex", "grid"}
+
+func (j ThemeJson) getLayoutStyles(nodes node) string {
+ //todo current theme supports disable-layout-styles
+ var blockType map[string]any
+ var s strings.Builder
+ if nodes.Name != "" {
+ v, ok := maps.GetStrAnyVal[map[string]any](j.blocksMetaData, nodes.Name)
+ if ok {
+ vv, ok := maps.GetStrAnyVal[map[string]any](v, "supports.__experimentalLayout")
+ if ok && vv == nil {
+ return ""
+ }
+ blockType = vv
+ }
+ }
+ gap, hasBlockGapSupport := maps.GetStrAnyVal[map[string]any](j.themeJson, "settings.spacing.blockGap")
+ if gap == nil {
+ hasBlockGapSupport = false
+ }
+ _, ok := maps.GetStrAnyVal[map[string]any](j.themeJson, strings.Join(nodes.Path, "."))
+ if !ok {
+ return ""
+ }
+ layoutDefinitions, ok := maps.GetStrAnyVal[map[string]any](j.themeJson, "settings.layout.definitions")
+ if !ok {
+ return ""
+ }
+ blockGapValue := ""
+ if !hasBlockGapSupport {
+ if RootBlockSelector == nodes.Selector {
+ blockGapValue = "0.5em"
+ }
+ if blockType != nil {
+ blockGapValue, _ = maps.GetStrAnyVal[string](blockType, "supports.spacing.blockGap.__experimentalDefault")
+ }
+ } else {
+ //todo getPropertyValue()
+ }
+ if blockGapValue != "" {
+ for key, v := range layoutDefinitions {
+ definition, ok := v.(map[string]any)
+ if !ok {
+ continue
+ }
+ if !hasBlockGapSupport && "flex" != key {
+ continue
+ }
+ className := maps.GetStrAnyValWithDefaults(definition, "className", "")
+ spacingRules := maps.GetStrAnyValWithDefaults(definition, "spacingStyles", []any{})
+ if className == "" || spacingRules == nil {
+ continue
+ }
+ for _, rule := range spacingRules {
+ var declarations []declaration
+ spacingRule, ok := rule.(map[string]any)
+ if !ok {
+ continue
+ }
+ selector := maps.GetStrAnyValWithDefaults(spacingRule, "selector", "")
+ rules := maps.GetStrAnyValWithDefaults(spacingRule, "rules", map[string]any(nil))
+ if selector != "" && !layoutSelectorReg.MatchString(selector) || rules == nil {
+ continue
+ }
+ for property, v := range rules {
+ value, ok := v.(string)
+ if !ok || value == "" {
+ value = blockGapValue
+ }
+ if isSafeCssDeclaration(property, value) {
+ declarations = append(declarations, declaration{property, value})
+ }
+ }
+ format := ""
+ if !hasBlockGapSupport {
+ format = helper.Or(RootBlockSelector == nodes.Selector, ":where(.%[2]s%[3]s)", ":where(%[1]s.%[2]s%[3]s)")
+ } else {
+ format = helper.Or(RootBlockSelector == nodes.Selector, "%s .%s%s", "%s.%s%s")
+ }
+ layoutSelector := fmt.Sprintf(format, nodes.Selector, className, selector)
+ s.WriteString(toRuleset(layoutSelector, declarations))
+ }
+ }
+ }
+
+ if RootBlockSelector == nodes.Selector {
+ for _, v := range layoutDefinitions {
+ definition, ok := v.(map[string]any)
+ if !ok {
+ continue
+ }
+ className := maps.GetStrAnyValWithDefaults(definition, "className", "")
+ baseStyleRules := maps.GetStrAnyValWithDefaults(definition, "baseStyles", []any{})
+ if className == "" || nil == baseStyleRules {
+ continue
+ }
+ displayMode := maps.GetStrAnyValWithDefaults(definition, "displayMode", "")
+ if displayMode != "" && slice.IsContained(validDisplayModes, displayMode) {
+ layoutSelector := str.Join(nodes.Selector, " .", className)
+ s.WriteString(toRuleset(layoutSelector, []declaration{{"display", displayMode}}))
+ }
+ for _, rule := range baseStyleRules {
+ var declarations []declaration
+ r, ok := rule.(map[string]any)
+ if !ok {
+ continue
+ }
+ selector := maps.GetStrAnyValWithDefaults(r, "selector", "")
+ rules := maps.GetStrAnyValWithDefaults(r, "rules", map[string]any(nil))
+ if selector != "" && !layoutSelectorReg.MatchString(selector) || rules == nil {
+ continue
+ }
+ for property, value := range rules {
+ val, ok := value.(string)
+ if !ok || val == "" {
+ continue
+ }
+ if isSafeCssDeclaration(property, val) {
+ declarations = append(declarations, declaration{property, val})
+ }
+ }
+ layoutSelector := str.Join(nodes.Selector, " .", className, selector)
+ s.WriteString(toRuleset(layoutSelector, declarations))
+ }
+ }
+ }
+
+ return s.String()
+}
+
+func isSafeCssDeclaration(name, value string) bool {
+ css := str.Join(name, ": ", value)
+ s := safeCSSFilterAttr(css)
+ return "" != html.EscapeString(s)
+}
+
+var kses = regexp.MustCompile(`[\x00-\x08\x0B\x0C\x0E-\x1F]`)
+var ksesop = regexp.MustCompile(`\\\\+0+`)
+
+func KsesNoNull(s string, op ...bool) string {
+ s = kses.ReplaceAllString(s, "")
+ ops := true
+ if len(op) > 0 {
+ ops = op[0]
+ }
+ if ops {
+ s = ksesop.ReplaceAllString(s, "")
+ }
+ return s
+}
+
+var allowedProtocols = []string{
+ "http", "https", "ftp", "ftps", "mailto", "news", "irc", "irc6", "ircs", "gopher", "nntp",
+ "feed", "telnet", "mms", "rtsp", "sms", "svn", "tel", "fax", "xmpp", "webcal", "urn",
+}
+
+var allowCssAttr = []string{
+ "background", "background-color", "background-image", "background-position", "background-size", "background-attachment", "background-blend-mode",
+ "border", "border-radius", "border-width", "border-color", "border-style", "border-right", "border-right-color",
+ "border-right-style", "border-right-width", "border-bottom", "border-bottom-color", "border-bottom-left-radius",
+ "border-bottom-right-radius", "border-bottom-style", "border-bottom-width", "border-bottom-right-radius",
+ "border-bottom-left-radius", "border-left", "border-left-color", "border-left-style", "border-left-width",
+ "border-top", "border-top-color", "border-top-left-radius", "border-top-right-radius", "border-top-style",
+ "border-top-width", "border-top-left-radius", "border-top-right-radius", "border-spacing", "border-collapse",
+ "caption-side", "columns", "column-count", "column-fill", "column-gap", "column-rule", "column-span", "column-width",
+ "color", "filter", "font", "font-family", "font-size", "font-style", "font-variant", "font-weight",
+ "letter-spacing", "line-height", "text-align", "text-decoration", "text-indent", "text-transform", "height",
+ "min-height", "max-height", "width", "min-width", "max-width", "margin", "margin-right", "margin-bottom",
+ "margin-left", "margin-top", "margin-block-start", "margin-block-end", "margin-inline-start", "margin-inline-end",
+ "padding", "padding-right", "padding-bottom", "padding-left", "padding-top", "padding-block-start",
+ "padding-block-end", "padding-inline-start", "padding-inline-end", "flex", "flex-basis", "flex-direction",
+ "flex-flow", "flex-grow", "flex-shrink", "flex-wrap", "gap", "column-gap", "row-gap", "grid-template-columns",
+ "grid-auto-columns", "grid-column-start", "grid-column-end", "grid-column-gap", "grid-template-rows",
+ "grid-auto-rows", "grid-row-start", "grid-row-end", "grid-row-gap", "grid-gap", "justify-content", "justify-items",
+ "justify-self", "align-content", "align-items", "align-self", "clear", "cursor", "direction", "float",
+ "list-style-type", "object-fit", "object-position", "overflow", "vertical-align", "position", "top", "right",
+ "bottom", "left", "z-index", "aspect-ratio", "--*",
+}
+var allowCssAttrMap = slice.FilterAndToMap(allowCssAttr, func(t string) (string, struct{}, bool) {
+ return t, struct{}{}, true
+})
+
+var __strReg = regexp.MustCompile(`^--[a-zA-Z0-9-_]+$`)
+var cssUrlDataTypes = []string{"background", "background-image", "cursor", "list-style", "list-style-image"}
+var cssGradientDataTypes = []string{"background", "background-image"}
+var __allowCSSReg = regexp2.MustCompile(`\b(?:var|calc|min|max|minmax|clamp)(\((?:[^()]|(?!1))*\))`, regexp2.None)
+var __disallowCSSReg = regexp.MustCompile(`[\\(&=}]|/\*`)
+
+func safeCSSFilterAttr(css string) string {
+ css = KsesNoNull(css)
+ css = strings.TrimSpace(css)
+ css = str.Replaces(css, []string{"\n", "\r", "\t", ""})
+ cssArr := strings.Split(css, ";")
+ var isCustomVar, found, urlAttr, gradientAttr bool
+ var cssValue string
+ var ss strings.Builder
+ for _, s := range cssArr {
+ if s == "" {
+ continue
+ }
+ if !strings.Contains(s, ":") {
+ found = true
+ } else {
+ parts := strings.SplitN(s, ":", 2)
+ selector := strings.TrimSpace(parts[0])
+ if maps.IsExists(allowCssAttrMap, "--*") {
+ i := __strReg.FindStringIndex(selector)
+ if len(i) > 0 && i[0] > 0 {
+ isCustomVar = true
+ allowCssAttr = append(allowCssAttr, selector)
+ }
+ }
+ if maps.IsExists(allowCssAttrMap, selector) {
+ found = true
+ urlAttr = slice.IsContained(cssUrlDataTypes, selector)
+ gradientAttr = slice.IsContained(cssGradientDataTypes, selector)
+ }
+ if isCustomVar {
+ cssValue = strings.TrimSpace(parts[1])
+ urlAttr = cssValue[0:4] == "url("
+ gradientAttr = strings.Contains(cssValue, "-gradient(")
+ }
+ }
+
+ if found {
+ //todo wtf 🤮
+ if urlAttr {
+
+ }
+ if gradientAttr {
+
+ }
+ cssTest, _ := __allowCSSReg.Replace(s, "", 0, -1)
+ isAllow := !__disallowCSSReg.MatchString(cssTest)
+ if isAllow {
+ ss.WriteString(s)
+ ss.WriteString(";")
+ }
+ }
+
+ }
+ return strings.TrimRight(ss.String(), ";")
+}
+
+func (j ThemeJson) getStyletSheet(types, origins []string, options map[string]string) string {
+ if origins == nil {
+ origins = append(validOrigins)
+ }
+ styleNodes := getStyleNodes(j)
+ settingsNodes := getSettingNodes(j.blocksMetaData, j.themeJson)
+ rootStyleKey, _ := slice.SearchFirst(styleNodes, func(n node) bool {
+ return n.Selector == RootBlockSelector
+ })
+ rootSettingsKey, _ := slice.SearchFirst(settingsNodes, func(n node) bool {
+ return n.Selector == RootBlockSelector
+ })
+ if os, ok := options["scope"]; ok {
+ for i := range settingsNodes {
+ settingsNodes[i].Selector = scopeSelector(os, settingsNodes[i].Selector)
+ }
+ for i := range styleNodes {
+ styleNodes[i].Selector = scopeSelector(os, styleNodes[i].Selector)
+ }
+ }
+ if or, ok := options["root_selector"]; ok && or != "" {
+ if rootSettingsKey > -1 {
+ settingsNodes[rootSettingsKey].Selector = or
+ }
+ if rootStyleKey > -1 && rootStyleKey < len(settingsNodes) {
+ settingsNodes[rootStyleKey].Selector = or
+ }
+ }
+ stylesSheet := ""
+ if slice.IsContained(types, "variables") {
+ stylesSheet = j.getCssVariables(settingsNodes, origins)
+ }
+
+ if slice.IsContained(types, "styles") {
+ stylesSheet = j.getCssVariables(settingsNodes, origins)
+ if rootStyleKey > -1 {
+ //todo getRootLayoutRules
+ stylesSheet = str.Join(stylesSheet)
+ }
+ } else if slice.IsContained(types, "base-layout-styles") {
+ rootSelector := RootBlockSelector
+ columnsSelector := ".wp-block-columns"
+ scope, ok := options["scope"]
+ if ok && scope != "" {
+ rootSelector = scopeSelector(scope, rootSelector)
+ columnsSelector = scopeSelector(scope, columnsSelector)
+ }
+ rs, ok := options["root_selector"]
+ if ok && rs != "" {
+ rootSelector = rs
+ }
+ baseStylesNodes := []node{
+ {
+ Path: []string{"styles"},
+ Selector: rootSelector,
+ },
+ {
+ Path: []string{"styles", "blocks", "core/columns"},
+ Selector: columnsSelector,
+ Name: "core/columns",
+ },
+ }
+ for _, stylesNode := range baseStylesNodes {
+ stylesSheet = str.Join(stylesSheet, j.getLayoutStyles(stylesNode))
+ }
+ }
+
+ if slice.IsContained(types, "presets") {
+ stylesSheet = str.Join(stylesSheet, j.getPresetClasses(settingsNodes, origins))
+ }
+
+ return stylesSheet
+}
+
+func (j ThemeJson) getPresetClasses(nodes []node, origins []string) string {
+ var presetRules strings.Builder
+ for _, n := range nodes {
+ if n.Selector == "" {
+ continue
+ }
+ no, ok := maps.GetStrAnyVal[map[string]any](j.themeJson, strings.Join(n.Path, "."))
+ if !ok {
+ continue
+ }
+ presetRules.WriteString(computePresetClasses(no, n.Selector, origins))
+ }
+ return presetRules.String()
+}
+
+func computePresetClasses(m map[string]any, selector string, origins []string) string {
+ if selector == RootBlockSelector {
+ selector = ""
+ }
+ var s strings.Builder
+ for _, meta := range presetsMetadata {
+ slugs := getSettingsSlugs(m, meta, origins)
+ for class, property := range meta.classes {
+ for _, slug := range slugs {
+ cssVar := strings.ReplaceAll(meta.cssVars, "$slug", slug)
+ className := strings.ReplaceAll(class, "$slug", slug)
+ s.WriteString(toRuleset(appendToSelector(selector, className, ""), []declaration{
+ {property, str.Join("var(", cssVar, ") !important")},
+ }))
+ }
+ }
+ }
+ return s.String()
+}
+
+func getSettingsSlugs(settings map[string]any, meta presetMeta, origins []string) map[string]string {
+ if origins == nil {
+ origins = validOrigins
+ }
+
+ presetPerOrigin, ok := maps.GetStrAnyVal[map[string]any](settings, strings.Join(meta.path, "."))
+ if !ok {
+ return nil
+ }
+ m := map[string]string{}
+ for _, origin := range origins {
+ o, ok := maps.GetStrAnyVal[[]map[string]string](presetPerOrigin, origin)
+ if !ok {
+ continue
+ }
+ for _, mm := range o {
+ slug := toKebabCase(mm["slug"])
+ m[slug] = slug
+ }
+ }
+ return m
+}
+
+func toKebabCase(s string) string {
+ s = strings.ReplaceAll(s, "'", "")
+ r, err := __kebabCaseReg.FindStringMatch(s)
+ if err != nil {
+ return s
+ }
+ var ss []string
+ for r != nil {
+ if r.GroupCount() < 1 {
+ break
+ }
+
+ ss = append(ss, r.Groups()[0].String())
+ r, _ = __kebabCaseReg.FindNextMatch(r)
+ }
+
+ return strings.ToLower(strings.Join(ss, "-"))
+}
+
+var __kebabCaseReg = func() *regexp2.Regexp {
+ rsLowerRange := "a-z\\xdf-\\xf6\\xf8-\\xff"
+ rsNonCharRange := "\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf"
+ rsPunctuationRange := "\\x{2000}-\\x{206f}"
+ rsSpaceRange := " \\t\\x0b\\f\\xa0\\x{feff}\\n\\r\\x{2028}\\x{2029}\\x{1680}\\x{180e}\\x{2000}\\x{2001}\\x{2002}\\x{2003}\\x{2004}\\x{2005}\\x{2006}\\x{2007}\\x{2008}\\x{2009}\\x{200a}\\x{202f}\\x{205f}\\x{3000}"
+ rsUpperRange := "A-Z\\xc0-\\xd6\\xd8-\\xde"
+ rsBreakRange := rsNonCharRange + rsPunctuationRange + rsSpaceRange
+
+ /** Used to compose unicode capture groups. */
+ rsBreak := "[" + rsBreakRange + "]"
+ rsDigits := "\\d+" // The last lodash version in GitHub uses a single digit here and expands it when in use.
+ rsLower := "[" + rsLowerRange + "]"
+ rsMisc := "[^" + rsBreakRange + rsDigits + rsLowerRange + rsUpperRange + "]"
+ rsUpper := "[" + rsUpperRange + "]"
+
+ /** Used to compose unicode regexes. */
+ rsMiscLower := "(?:" + rsLower + "|" + rsMisc + ")"
+ rsMiscUpper := "(?:" + rsUpper + "|" + rsMisc + ")"
+ rsOrdLower := "\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])"
+ rsOrdUpper := "\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])"
+
+ reg := strings.Join([]string{
+ rsUpper + "?" + rsLower + "+(?=" + strings.Join([]string{rsBreak, rsUpper, "$"}, "|") + ")",
+ rsMiscUpper + "+(?=" + strings.Join([]string{rsBreak, rsUpper + rsMiscLower, "$"}, "|") + ")",
+ rsUpper + "?" + rsMiscLower + "+",
+ rsUpper + "+",
+ rsOrdUpper,
+ rsOrdLower,
+ rsDigits,
+ }, "|")
+ return regexp2.MustCompile(reg, regexp2.Unicode)
+}()
+
+var presetsMetadata = []presetMeta{
+ {
+ path: []string{"color", "palette"},
+ preventOverride: []string{"color", "defaultPalette"},
+ useDefaultNames: false,
+ valueKey: "color",
+ valueFunc: nil,
+ cssVars: "--wp--preset--color--$slug",
+ classes: map[string]string{
+ ".has-$slug-color": "color",
+ ".has-$slug-background-color": "background-color",
+ ".has-$slug-border-color": "border-color",
+ },
+ properties: []string{"color", "background-color", "border-color"},
+ }, {
+ path: []string{"color", "gradients"},
+ preventOverride: []string{"color", "defaultGradients"},
+ useDefaultNames: false,
+ valueKey: "gradient",
+ valueFunc: nil,
+ cssVars: "--wp--preset--gradient--$slug",
+ classes: map[string]string{
+ ".has-$slug-gradient-background": "background",
+ },
+ properties: []string{"background"},
+ }, {
+ path: []string{"color", "duotone"},
+ preventOverride: []string{"color", "defaultDuotone"},
+ useDefaultNames: false,
+ valueKey: "",
+ valueFunc: wpGetDuotoneFilterProperty,
+ cssVars: "--wp--preset--duotone--$slug",
+ classes: map[string]string{},
+ properties: []string{"filter"},
+ }, {
+ path: []string{"typography", "fontSizes"},
+ preventOverride: []string{},
+ useDefaultNames: true,
+ valueKey: "",
+ valueFunc: wpGetTypographyFontSizeValue,
+ cssVars: "--wp--preset--font-size--$slug",
+ classes: map[string]string{
+ ".has-$slug-font-size": "font-size",
+ },
+ properties: []string{"font-size"},
+ }, {
+ path: []string{"typography", "fontFamilies"},
+ preventOverride: []string{},
+ useDefaultNames: false,
+ valueKey: "fontFamily",
+ valueFunc: nil,
+ cssVars: "--wp--preset--font-family--$slug",
+ classes: map[string]string{
+ ".has-$slug-font-family": "font-family",
+ },
+ properties: []string{"font-family"},
+ }, {
+ path: []string{"spacing", "spacingSizes"},
+ preventOverride: []string{},
+ useDefaultNames: true,
+ valueKey: "size",
+ valueFunc: nil,
+ cssVars: "--wp--preset--spacing--$slug",
+ classes: map[string]string{},
+ properties: []string{"padding", "margin"},
+ }, {
+ path: []string{"shadow", "presets"},
+ preventOverride: []string{"shadow", "defaultPresets"},
+ useDefaultNames: false,
+ valueKey: "shadow",
+ valueFunc: nil,
+ cssVars: "--wp--preset--shadow--$slug",
+ classes: map[string]string{},
+ properties: []string{"box-shadow"},
+ },
+}
+
+type presetMeta struct {
+ path []string
+ preventOverride []string
+ useDefaultNames bool
+ valueFunc func(map[string]string, map[string]any) string
+ valueKey string
+ cssVars string
+ classes map[string]string
+ properties []string
+}
+
+type declaration struct {
+ name string
+ value string
+}
+
+func wpGetDuotoneFilterProperty(preset map[string]string, _ map[string]any) string {
+ v, ok := preset["colors"]
+ if ok && "unset" == v {
+ return "none"
+ }
+ id, ok := preset["slug"]
+ if ok {
+ id = str.Join("wp-duotone-", id)
+ }
+ return str.Join(`url('#`, id, "')")
+}
+
+func wpGetTypographyFontSizeValue(preset map[string]string, m map[string]any) string {
+ size, ok := preset["size"]
+ if !ok {
+ return ""
+ }
+ if size == "" || size == "0" {
+ return size
+ }
+ origin := "custom"
+ if !wpconfig.HasThemeJson() {
+ origin = "theme"
+ }
+ typographySettings, ok := maps.GetStrAnyVal[map[string]any](m, "typography")
+ if !ok {
+ return size
+ }
+ fluidSettings, ok := maps.GetStrAnyVal[map[string]any](typographySettings, "fluid")
+
+ //todo so complex dying 👻
+ _ = fluidSettings
+ _ = origin
+ return size
+}
+
+var __themeJson = reload.Vars(ThemeJson{})
+
+func GetThemeJson() ThemeJson {
+ return __themeJson.Load()
+}
+
+func computeThemeVars(m map[string]any) []declaration {
+ //todo ......
+ return nil
+}
+
+func computePresetVars(m map[string]any, origins []string) []declaration {
+ var declarations []declaration
+ for _, metadatum := range presetsMetadata {
+ slug := getSettingsValuesBySlug(m, metadatum, origins)
+ for k, v := range slug {
+ declarations = append(declarations, declaration{
+ name: strings.Replace(metadatum.cssVars, "$slug", k, -1),
+ value: v,
+ })
+ }
+ }
+ return declarations
+}
+
+func getSettingsValuesBySlug(m map[string]any, meta presetMeta, origins []string) map[string]string {
+ perOrigin := maps.GetStrAnyValWithDefaults[map[string]any](m, strings.Join(meta.path, "."), nil)
+ r := map[string]string{}
+ for _, origin := range origins {
+ if vv, ok := maps.GetStrAnyVal[[]map[string]string](perOrigin, origin); ok {
+ for _, preset := range vv {
+ slug := preset["slug"]
+ value := ""
+ if vv, ok := preset[meta.valueKey]; ok && vv != "" {
+ value = vv
+ } else if meta.valueFunc != nil {
+ value = meta.valueFunc(preset, m)
+ }
+ r[slug] = value
+ }
+ }
+ }
+ return r
+}
+
+func setSpacingSizes(t ThemeJson) {
+ m, _ := maps.GetStrAnyVal[map[string]any](t.themeJson, "settings.spacing.spacingScale")
+ unit, _ := maps.GetStrAnyVal[string](m, "unit")
+ currentStep, _ := maps.GetStrAnyVal[float64](m, "mediumStep")
+ mediumStep := currentStep
+ steps, _ := maps.GetStrAnyVal[float64](m, "steps")
+ operator, _ := maps.GetStrAnyVal[string](m, "operator")
+ increment, _ := maps.GetStrAnyVal[float64](m, "increment")
+ stepsMidPoint := math.Round(steps / 2)
+ reminder := float64(0)
+ xSmallCount := ""
+ var sizes []map[string]string
+ slug := 40
+ for i := stepsMidPoint - 1; i > 0 && slug > 0 && steps > 1; i-- {
+ if "+" == operator {
+ currentStep -= increment
+ } else if increment > 1 {
+ currentStep /= increment
+ } else {
+ currentStep *= increment
+ }
+ if currentStep <= 0 {
+ reminder = i
+ break
+ }
+ name := "small"
+ if i != stepsMidPoint-1 {
+ name = str.Join(xSmallCount, "X-Small")
+ }
+ sizes = append(sizes, map[string]string{
+ "name": name,
+ "slug": number.IntToString(slug),
+ "size": fmt.Sprintf("%v%s", number.Round(currentStep, 2), unit),
+ })
+ if i == stepsMidPoint-2 {
+ xSmallCount = strconv.Itoa(2)
+ }
+ if i < stepsMidPoint-2 {
+ n := str.ToInt[int](xSmallCount)
+ n++
+ xSmallCount = strconv.Itoa(n)
+ }
+ slug -= 10
+ }
+ slice.ReverseSelf(sizes)
+ sizes = append(sizes, map[string]string{
+ "name": "Medium",
+ "slug": "50",
+ "size": str.Join(number.ToString(mediumStep), unit),
+ })
+ currentStep = mediumStep
+ slug = 60
+ xLargeCount := ""
+ stepsAbove := steps - stepsMidPoint + reminder
+ for aboveMidpointCount := float64(0); aboveMidpointCount < stepsAbove; aboveMidpointCount++ {
+ if "+" == operator {
+ currentStep += increment
+ } else if increment >= 1 {
+ currentStep *= increment
+ } else {
+ currentStep /= increment
+ }
+ name := "Large"
+ if 0 != aboveMidpointCount {
+ name = str.Join(xLargeCount, "X-Large")
+ }
+ sizes = append(sizes, map[string]string{
+ "name": name,
+ "slug": strconv.Itoa(slug),
+ "size": fmt.Sprintf("%v%s", number.Round(currentStep, 2), unit),
+ })
+ if aboveMidpointCount == 1 {
+ xLargeCount = strconv.Itoa(2)
+ }
+ if aboveMidpointCount > 1 {
+ x := str.ToInt[int](xLargeCount)
+ x++
+ xLargeCount = strconv.Itoa(x)
+ }
+ slug += 10
+ }
+ if steps <= 7 {
+ for i := 0; i < len(sizes); i++ {
+ sizes[i]["name"] = strconv.Itoa(i + 1)
+ }
+ }
+ maps.SetStrAnyVal(t.themeJson, "settings.spacing.spacingSizes.default", sizes)
+}
+
+func (j ThemeJson) getCssVariables(settingNodes []node, origins []string) string {
+ var s strings.Builder
+ for _, settingNode := range settingNodes {
+ if "" == settingNode.Selector {
+ continue
+ }
+ n := maps.GetStrAnyValWithDefaults[map[string]any](j.themeJson, strings.Join(settingNode.Path, "."), nil)
+ declarations := computePresetVars(n, origins)
+ declarations = append(declarations, computeThemeVars(j.themeJson)...)
+ s.WriteString(toRuleset(settingNode.Selector, declarations))
+ }
+ return s.String()
+}
+
+func toRuleset(selector string, declarations []declaration) string {
+ if len(declarations) < 1 {
+ return ""
+ }
+ s := slice.Reduce(declarations, func(t declaration, r string) string {
+ return str.Join(r, t.name, ":", t.value, ";")
+ }, "")
+ return str.Join(selector, "{", s, "}")
+}
+
+func getStyleNodes(t ThemeJson) []node {
+ var styleNodes = []node{
+ {[]string{"styles"}, "body", ""},
+ }
+ m := maps.GetStrAnyValWithDefaults[map[string]any](t.themeJson, "styles.elements", nil)
+ if len(m) < 1 {
+ return nil
+ }
+ for e, s := range __elements {
+ _, ok := m[e]
+ if !ok {
+ continue
+ }
+ styleNodes = append(styleNodes, node{[]string{"styles", "elements", e}, s, ""})
+ ss, ok := __validElementPseudoSelectors[e]
+ if ok {
+ for _, sel := range ss {
+ if maps.IsExists(__elements, sel) {
+ styleNodes = append(styleNodes, node{
+ Path: []string{"styles", "elements", e},
+ Selector: appendToSelector(s, sel, ""),
+ })
+ }
+ }
+ }
+ }
+ blocks, _ := maps.GetStrAnyVal[map[string]any](t.blocksMetaData, "theme_json.styles.blocks")
+ maps.SetStrAnyVal(t.themeJson, "styles.blocks", blocks)
+ blockNodes := getBlockNodes(t.blocksMetaData)
+ for _, blockNode := range blockNodes {
+ p, ok := maps.GetStrAnyVal[[]string](blockNode, "path")
+ s, oo := maps.GetStrAnyVal[string](blockNode, "selector")
+ if ok && oo {
+ _ = append(styleNodes, node{Path: p, Selector: s})
+ //styleNodes = append(styleNodes, node{Path: p, Selector: s})
+ }
+ }
+
+ return styleNodes
+}
+
+func GetGlobalStyletSheet() string {
+ t := __themeJson.Load()
+ var types, origins []string
+ if types == nil && !wpconfig.HasThemeJson() {
+ types = []string{"variables", "presets", "base-layout-styles"}
+ } else if types == nil {
+ types = []string{"variables", "styles", "presets"}
+ }
+ styleSheet := ""
+ if slice.IsContained(types, "variables") {
+ origins = []string{"default", "theme", "custom"}
+ styleSheet = t.getStyletSheet([]string{"variables"}, origins, nil)
+ slice.Delete(&types, slice.IndexOf(types, "variables"))
+ }
+
+ if len(types) > 0 {
+ origins = []string{"default", "theme", "custm"}
+ if !wpconfig.HasThemeJson() {
+ origins = []string{"default"}
+ }
+ styleSheet = str.Join(styleSheet, t.getStyletSheet(types, origins, nil))
+ }
+
+ return styleSheet
+}
+
+func wpGetTypographyValueAndUnit(value string, options map[string]any) {
+ /*options := maps.Merge(options, map[string]any{
+ "coerce_to": "",
+ "root_size_value": 16,
+ "acceptable_units": []string{"rem", "px", "em"},
+ })
+ u, _ := maps.GetStrAnyVal[[]string](options, "acceptable_units")
+ acceptableUnitsGroup := strings.Join(u, "|")*/
+
+}
+
+/*func (j ThemeJson) getStylesForBlock(blockMeta map[string]any) {
+ path, _ := maps.GetStrAnyVal[[]string](blockMeta, "path")
+ node, _ := maps.GetStrAnyVal[map[string]any](j.themeJson, strings.Join(path, "."))
+ useRootPadding := maps.GetStrAnyValWithDefaults(j.themeJson, "settings.useRootPaddingAwareAlignments", false)
+ settings, _ := maps.GetStrAnyVal(j.themeJson, "settings")
+ is_processing_element := slice.IsContained(path, "elements")
+ currentElement := ""
+ if is_processing_element {
+ currentElement = path[len(path)-1]
+ }
+ element_pseudo_allowed := __validElementPseudoSelectors[currentElement]
+
+}
+
+func computeStyleProperties(styles, settings, properties, themeJson map[string]any, selector string, useRootPadding bool) {
+ if properties == nil {
+ //properties =
+ }
+}
+*/
diff --git a/safety/safemap.go b/safety/safemap.go
index 06a54bf..fcf9b6c 100644
--- a/safety/safemap.go
+++ b/safety/safemap.go
@@ -390,6 +390,15 @@ func (m *Map[K, V]) Range(f func(key K, value V) bool) {
}
}
+func (m *Map[K, V]) Keys() []K {
+ var r []K
+ m.Range(func(key K, _ V) bool {
+ r = append(r, key)
+ return true
+ })
+ return r
+}
+
func (m *Map[K, V]) missLocked() {
m.misses++
if m.misses < len(m.dirty) {