mirror of
https://github.com/siyuan-note/siyuan.git
synced 2026-02-25 16:34:06 +01:00
🎨 Element attribute names are uniformly lowercase English letters https://github.com/siyuan-note/siyuan/issues/16604 (#16657)
部分属性名大写字母改为小写 兼容旧版带大写字母的属性名 更新用户指南说明 优化性能 统一前后端验证属性名的逻辑 改进验证属性名格式报错信息
This commit is contained in:
parent
e1f6b83d35
commit
2d1618e639
27 changed files with 10420 additions and 10359 deletions
|
|
@ -19,13 +19,13 @@ package model
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/lute/ast"
|
||||
"github.com/88250/lute/editor"
|
||||
"github.com/88250/lute/lex"
|
||||
"github.com/88250/lute/parse"
|
||||
"github.com/araddon/dateparse"
|
||||
"github.com/siyuan-note/siyuan/kernel/cache"
|
||||
|
|
@ -35,6 +35,32 @@ import (
|
|||
"github.com/siyuan-note/siyuan/kernel/util"
|
||||
)
|
||||
|
||||
// isValidAttrName 验证属性名是否合法
|
||||
func isValidAttrName(name string) bool {
|
||||
if len(name) == 0 {
|
||||
return false
|
||||
}
|
||||
// 首字符必须是小写字母
|
||||
if name[0] < 'a' || name[0] > 'z' {
|
||||
return false
|
||||
}
|
||||
// 自定义属性 custom- 之后的首个字符必须是小写字母
|
||||
if strings.HasPrefix(name, "custom-") {
|
||||
if len(name) <= 7 || name[7] < 'a' || name[7] > 'z' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
// 后续字符只能是小写字母、数字、连字符
|
||||
for i := 1; i < len(name); i++ {
|
||||
c := name[i]
|
||||
if c == '-' || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') {
|
||||
continue
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func SetBlockReminder(id string, timed string) (err error) {
|
||||
if !IsSubscriber() {
|
||||
if "ios" == util.Container {
|
||||
|
|
@ -205,68 +231,64 @@ func setNodeAttrsWithTx(tx *Transaction, node *ast.Node, tree *parse.Tree, nameV
|
|||
|
||||
func setNodeAttrs0(node *ast.Node, nameValues map[string]string) (oldAttrs map[string]string, err error) {
|
||||
oldAttrs = parse.IAL2Map(node.KramdownIAL)
|
||||
|
||||
for name := range nameValues {
|
||||
for i := 0; i < len(name); i++ {
|
||||
if !lex.IsASCIILetterNumHyphen(name[i]) {
|
||||
err = errors.New(fmt.Sprintf(Conf.Language(25), node.ID))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if tag, ok := nameValues["tags"]; ok {
|
||||
var tags []string
|
||||
tmp := strings.Split(tag, ",")
|
||||
for _, t := range tmp {
|
||||
t = util.RemoveInvalid(t)
|
||||
t = strings.TrimSpace(t)
|
||||
if "" != t {
|
||||
tags = append(tags, t)
|
||||
}
|
||||
}
|
||||
tags = gulu.Str.RemoveDuplicatedElem(tags)
|
||||
if 0 < len(tags) {
|
||||
nameValues["tags"] = strings.Join(tags, ",")
|
||||
}
|
||||
}
|
||||
|
||||
normalizeKeysToLower(nameValues)
|
||||
newAttrs := maps.Clone(oldAttrs)
|
||||
|
||||
for name, value := range nameValues {
|
||||
value = util.RemoveInvalidRetainCtrl(value)
|
||||
value = strings.TrimSpace(value)
|
||||
value = strings.TrimSuffix(value, ",")
|
||||
lowerName := strings.ToLower(name)
|
||||
// 转换为小写再验证属性名
|
||||
if !isValidAttrName(lowerName) {
|
||||
err = errors.New(Conf.Language(25) + " [" + node.ID + "]")
|
||||
return
|
||||
}
|
||||
|
||||
// 处理文档标签 https://github.com/siyuan-note/siyuan/issues/13311
|
||||
if lowerName == "tags" {
|
||||
var tags []string
|
||||
tmp := strings.Split(value, ",")
|
||||
for _, t := range tmp {
|
||||
t = util.RemoveInvalid(t)
|
||||
t = strings.TrimSpace(t)
|
||||
if "" != t {
|
||||
tags = append(tags, t)
|
||||
}
|
||||
}
|
||||
tags = gulu.Str.RemoveDuplicatedElem(tags)
|
||||
if 0 < len(tags) {
|
||||
value = strings.Join(tags, ",")
|
||||
} else {
|
||||
value = ""
|
||||
}
|
||||
}
|
||||
|
||||
if "" == value {
|
||||
node.RemoveIALAttr(name)
|
||||
// 删除属性
|
||||
if name != lowerName {
|
||||
if _, exists := newAttrs[name]; exists {
|
||||
// 仅删除完全匹配的包含大写字母的属性
|
||||
delete(newAttrs, name)
|
||||
continue
|
||||
}
|
||||
}
|
||||
delete(newAttrs, lowerName)
|
||||
} else {
|
||||
node.SetIALAttr(name, value)
|
||||
// 添加或更新属性
|
||||
// 删除大小写完全匹配的属性
|
||||
delete(newAttrs, name)
|
||||
// 保存小写的属性 https://github.com/siyuan-note/siyuan/issues/16447
|
||||
newAttrs[lowerName] = value
|
||||
}
|
||||
}
|
||||
|
||||
if oldAttrs["tags"] != nameValues["tags"] {
|
||||
node.KramdownIAL = parse.Map2IAL(newAttrs)
|
||||
|
||||
if oldAttrs["tags"] != newAttrs["tags"] {
|
||||
ReloadTag()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// normalizeKeysToLower 将 nameValues 的键统一为小写 https://github.com/siyuan-note/siyuan/issues/16447
|
||||
func normalizeKeysToLower(nameValues map[string]string) {
|
||||
newMap := make(map[string]string, len(nameValues))
|
||||
for name, value := range nameValues {
|
||||
lower := strings.ToLower(name)
|
||||
newMap[lower] = value
|
||||
}
|
||||
|
||||
for k := range nameValues {
|
||||
delete(nameValues, k)
|
||||
}
|
||||
|
||||
for k, v := range newMap {
|
||||
nameValues[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
func pushBroadcastAttrTransactions(oldAttrs map[string]string, node *ast.Node) {
|
||||
newAttrs := parse.IAL2Map(node.KramdownIAL)
|
||||
data := map[string]interface{}{"old": oldAttrs, "new": newAttrs}
|
||||
|
|
@ -294,15 +316,15 @@ func ResetBlockAttrs(id string, nameValues map[string]string) (err error) {
|
|||
}
|
||||
|
||||
for name := range nameValues {
|
||||
for i := 0; i < len(name); i++ {
|
||||
if !lex.IsASCIILetterNumHyphen(name[i]) {
|
||||
return errors.New(fmt.Sprintf(Conf.Language(25), id))
|
||||
}
|
||||
if !isValidAttrName(name) {
|
||||
return errors.New(Conf.Language(25) + " [" + id + "]")
|
||||
}
|
||||
}
|
||||
|
||||
node.ClearIALAttrs()
|
||||
for name, value := range nameValues {
|
||||
value = util.RemoveInvalidRetainCtrl(value)
|
||||
value = strings.TrimSpace(value)
|
||||
if "" != value {
|
||||
node.SetIALAttr(name, value)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -245,9 +245,14 @@ func Export2Liandi(id string) (err error) {
|
|||
defer util.PushClearMsg(msgId)
|
||||
|
||||
// 判断帖子是否已经存在,存在则使用更新接口
|
||||
const liandiArticleIdAttrName = "custom-liandi-articleId"
|
||||
const liandiArticleIdAttrName = "custom-liandi-articleid"
|
||||
const liandiArticleIdAttrNameOld = "custom-liandi-articleId" // 兼容旧属性名
|
||||
foundArticle := false
|
||||
// 优先使用新属性名,如果不存在则尝试旧属性名
|
||||
articleId := tree.Root.IALAttr(liandiArticleIdAttrName)
|
||||
if "" == articleId {
|
||||
articleId = tree.Root.IALAttr(liandiArticleIdAttrNameOld)
|
||||
}
|
||||
if "" != articleId {
|
||||
result := gulu.Ret.NewResult()
|
||||
request := httpclient.NewCloudRequest30s()
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ import (
|
|||
"github.com/88250/lute"
|
||||
"github.com/88250/lute/ast"
|
||||
"github.com/88250/lute/editor"
|
||||
"github.com/88250/lute/lex"
|
||||
"github.com/88250/lute/parse"
|
||||
"github.com/siyuan-note/filelock"
|
||||
"github.com/siyuan-note/logging"
|
||||
|
|
@ -1736,11 +1735,9 @@ func (tx *Transaction) doSetAttrs(operation *Operation) (ret *TxErr) {
|
|||
|
||||
var invalidNames []string
|
||||
for name := range attrs {
|
||||
for i := 0; i < len(name); i++ {
|
||||
if !lex.IsASCIILetterNumHyphen(name[i]) {
|
||||
logging.LogWarnf("invalid attr name [%s]", name)
|
||||
invalidNames = append(invalidNames, name)
|
||||
}
|
||||
if !isValidAttrName(name) {
|
||||
logging.LogWarnf("invalid attr name [%s]", name)
|
||||
invalidNames = append(invalidNames, name)
|
||||
}
|
||||
}
|
||||
for _, name := range invalidNames {
|
||||
|
|
@ -1748,6 +1745,7 @@ func (tx *Transaction) doSetAttrs(operation *Operation) (ret *TxErr) {
|
|||
}
|
||||
|
||||
for name, value := range attrs {
|
||||
name := strings.ToLower(name)
|
||||
if "" == value {
|
||||
node.RemoveIALAttr(name)
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue