diff --git a/app/appearance/langs/en_US.json b/app/appearance/langs/en_US.json index 83ec85f13..63fcde474 100644 --- a/app/appearance/langs/en_US.json +++ b/app/appearance/langs/en_US.json @@ -1,5 +1,5 @@ { - "buildIn": "Build-in", + "builtIn": "Built-in", "endDate": "End date", "needLogin": "This function needs to be logged in to use", "calcResultCountAll": "COUNT", diff --git a/app/appearance/langs/es_ES.json b/app/appearance/langs/es_ES.json index a8b3032dd..adb676cb8 100644 --- a/app/appearance/langs/es_ES.json +++ b/app/appearance/langs/es_ES.json @@ -1,5 +1,5 @@ { - "buildIn": "Incorporado", + "builtIn": "Incorporado", "endDate": "Fecha de finalización", "needLogin": "Esta función requiere iniciar sesión en la cuenta antes de poder usarla", "calcResultCountAll": "CONTAR", diff --git a/app/appearance/langs/fr_FR.json b/app/appearance/langs/fr_FR.json index f1eafc1ca..b58378864 100644 --- a/app/appearance/langs/fr_FR.json +++ b/app/appearance/langs/fr_FR.json @@ -1,5 +1,5 @@ { - "buildIn": "Intégré", + "builtIn": "Intégré", "endDate": "Date de fin", "needLogin": "La fonctionnalité nécessite un numéro de compte de connexion avant de pouvoir être utilisée", "calcResultCountAll": "COUNT", diff --git a/app/appearance/langs/zh_CHT.json b/app/appearance/langs/zh_CHT.json index aca30915d..d13e3670f 100644 --- a/app/appearance/langs/zh_CHT.json +++ b/app/appearance/langs/zh_CHT.json @@ -1,5 +1,5 @@ { - "buildIn": "內置", + "builtIn": "內置", "endDate": "結束日期", "needLogin": "該功能需要登錄賬號後才能使用", "calcResultCountAll": "行計數", diff --git a/app/appearance/langs/zh_CN.json b/app/appearance/langs/zh_CN.json index 2c3544342..bc7f9e016 100644 --- a/app/appearance/langs/zh_CN.json +++ b/app/appearance/langs/zh_CN.json @@ -1,5 +1,5 @@ { - "buildIn": "内置", + "builtIn": "内置", "endDate": "结束时间", "needLogin": "该功能需要登录账号后才能使用", "calcResultCountAll": "行计数", diff --git a/app/src/menus/commonMenuItem.ts b/app/src/menus/commonMenuItem.ts index c0e27b0bf..5419b225c 100644 --- a/app/src/menus/commonMenuItem.ts +++ b/app/src/menus/commonMenuItem.ts @@ -6,7 +6,6 @@ import {confirmDialog} from "../dialog/confirmDialog"; import {getSearch, isMobile, isValidAttrName} from "../util/functions"; import {isLocalPath, movePathTo, moveToPath, pathPosix} from "../util/pathName"; import {MenuItem} from "./Menu"; -import {hasClosestByClassName} from "../protyle/util/hasClosest"; import {saveExport} from "../protyle/export"; import {openByMobile, writeText} from "../protyle/util/compatibility"; import {fetchPost, fetchSyncPost} from "../util/fetch"; @@ -202,7 +201,7 @@ const genAttr = (attrs: IObject, focusName = "bookmark", cb: (dialog: Dialog, rm
- ${window.siyuan.languages.buildIn} + ${window.siyuan.languages.builtIn}
diff --git a/kernel/av/av.go b/kernel/av/av.go index 7a9e4eb36..c9109d0fb 100644 --- a/kernel/av/av.go +++ b/kernel/av/av.go @@ -59,6 +59,7 @@ const ( KeyTypeDate KeyType = "date" KeyTypeSelect KeyType = "select" KeyTypeMSelect KeyType = "mSelect" + KeyTypeURL KeyType = "url" ) // Key 描述了属性视图属性列的基础结构。 @@ -97,6 +98,7 @@ type Value struct { Number *ValueNumber `json:"number,omitempty"` Date *ValueDate `json:"date,omitempty"` MSelect []*ValueSelect `json:"mSelect,omitempty"` + URL *ValueURL `json:"url,omitempty"` } func (value *Value) ToJSONString() string { @@ -222,6 +224,10 @@ type ValueSelect struct { Color string `json:"color"` } +type ValueURL struct { + Content string `json:"content"` +} + // View 描述了视图的结构。 type View struct { ID string `json:"id"` // 视图 ID diff --git a/kernel/av/table.go b/kernel/av/table.go index 82c928c31..7d430569b 100644 --- a/kernel/av/table.go +++ b/kernel/av/table.go @@ -379,6 +379,8 @@ func (table *Table) CalcCols() { table.calcColSelect(col, i) case KeyTypeMSelect: table.calcColMSelect(col, i) + case KeyTypeURL: + table.calcColURL(col, i) } } } @@ -813,6 +815,69 @@ func (table *Table) calcColText(col *TableColumn, colIndex int) { } } +func (table *Table) calcColURL(col *TableColumn, colIndex int) { + switch col.Calc.Operator { + case CalcOperatorCountAll: + col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)} + case CalcOperatorCountValues: + countValues := 0 + for _, row := range table.Rows { + if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.URL && "" != row.Cells[colIndex].Value.URL.Content { + countValues++ + } + } + col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)} + case CalcOperatorCountUniqueValues: + countUniqueValues := 0 + uniqueValues := map[string]bool{} + for _, row := range table.Rows { + if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.URL && "" != row.Cells[colIndex].Value.URL.Content { + if !uniqueValues[row.Cells[colIndex].Value.URL.Content] { + uniqueValues[row.Cells[colIndex].Value.URL.Content] = true + countUniqueValues++ + } + } + } + col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)} + case CalcOperatorCountEmpty: + countEmpty := 0 + for _, row := range table.Rows { + if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.URL || "" == row.Cells[colIndex].Value.URL.Content { + countEmpty++ + } + } + col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)} + case CalcOperatorCountNotEmpty: + countNotEmpty := 0 + for _, row := range table.Rows { + if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.URL && "" != row.Cells[colIndex].Value.URL.Content { + countNotEmpty++ + } + } + col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)} + case CalcOperatorPercentEmpty: + countEmpty := 0 + for _, row := range table.Rows { + if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.URL || "" == row.Cells[colIndex].Value.URL.Content { + countEmpty++ + } + } + if 0 < len(table.Rows) { + col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)} + } + case CalcOperatorPercentNotEmpty: + countNotEmpty := 0 + for _, row := range table.Rows { + if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.URL && "" != row.Cells[colIndex].Value.URL.Content { + countNotEmpty++ + } + } + if 0 < len(table.Rows) { + col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)} + } + } +} + func (table *Table) calcColBlock(col *TableColumn, colIndex int) { switch col.Calc.Operator { case CalcOperatorCountAll: diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index ff587ae33..74adc59e8 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -711,7 +711,7 @@ func addAttributeViewColumn(operation *Operation) (err error) { keyType := av.KeyType(operation.Typ) switch keyType { - case av.KeyTypeText, av.KeyTypeNumber, av.KeyTypeDate, av.KeyTypeSelect, av.KeyTypeMSelect: + case av.KeyTypeText, av.KeyTypeNumber, av.KeyTypeDate, av.KeyTypeSelect, av.KeyTypeMSelect, av.KeyTypeURL: key := av.NewKey(operation.ID, operation.Name, keyType) attrView.KeyValues = append(attrView.KeyValues, &av.KeyValues{Key: key}) @@ -741,7 +741,7 @@ func updateAttributeViewColumn(operation *Operation) (err error) { colType := av.KeyType(operation.Typ) switch colType { - case av.KeyTypeText, av.KeyTypeNumber, av.KeyTypeDate, av.KeyTypeSelect, av.KeyTypeMSelect: + case av.KeyTypeText, av.KeyTypeNumber, av.KeyTypeDate, av.KeyTypeSelect, av.KeyTypeMSelect, av.KeyTypeURL: for _, keyValues := range attrView.KeyValues { if keyValues.Key.ID == operation.ID { keyValues.Key.Name = operation.Name