- Escape XML character in the drop list - Fix incorrect character count limit in the drop list - Fix Excel time parse issue in some case - Fix custom number format month parse issue in some case - Fix corrupted file generated caused by concurrency adding pictures
This commit is contained in:
parent
e9ae9b45b2
commit
7dbf88f221
4
col.go
4
col.go
|
@ -439,10 +439,10 @@ func (f *File) SetColStyle(sheet, columns string, styleID int) error {
|
||||||
for col := start; col <= end; col++ {
|
for col := start; col <= end; col++ {
|
||||||
from, _ := CoordinatesToCellName(col, 1)
|
from, _ := CoordinatesToCellName(col, 1)
|
||||||
to, _ := CoordinatesToCellName(col, rows)
|
to, _ := CoordinatesToCellName(col, rows)
|
||||||
f.SetCellStyle(sheet, from, to, styleID)
|
err = f.SetCellStyle(sheet, from, to, styleID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetColWidth provides a function to set the width of a single column or
|
// SetColWidth provides a function to set the width of a single column or
|
||||||
|
|
|
@ -14,6 +14,7 @@ package excelize
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unicode/utf16"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DataValidationType defined the type of data validation.
|
// DataValidationType defined the type of data validation.
|
||||||
|
@ -111,10 +112,10 @@ func (dd *DataValidation) SetInput(title, msg string) {
|
||||||
// SetDropList data validation list.
|
// SetDropList data validation list.
|
||||||
func (dd *DataValidation) SetDropList(keys []string) error {
|
func (dd *DataValidation) SetDropList(keys []string) error {
|
||||||
formula := "\"" + strings.Join(keys, ",") + "\""
|
formula := "\"" + strings.Join(keys, ",") + "\""
|
||||||
if dataValidationFormulaStrLen < len(formula) {
|
if dataValidationFormulaStrLen < len(utf16.Encode([]rune(formula))) {
|
||||||
return fmt.Errorf(dataValidationFormulaStrLenErr)
|
return fmt.Errorf(dataValidationFormulaStrLenErr)
|
||||||
}
|
}
|
||||||
dd.Formula1 = fmt.Sprintf("<formula1>%s</formula1>", formula)
|
dd.Formula1 = formula
|
||||||
dd.Type = convDataValidationType(typeList)
|
dd.Type = convDataValidationType(typeList)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -123,12 +124,12 @@ func (dd *DataValidation) SetDropList(keys []string) error {
|
||||||
func (dd *DataValidation) SetRange(f1, f2 float64, t DataValidationType, o DataValidationOperator) error {
|
func (dd *DataValidation) SetRange(f1, f2 float64, t DataValidationType, o DataValidationOperator) error {
|
||||||
formula1 := fmt.Sprintf("%f", f1)
|
formula1 := fmt.Sprintf("%f", f1)
|
||||||
formula2 := fmt.Sprintf("%f", f2)
|
formula2 := fmt.Sprintf("%f", f2)
|
||||||
if dataValidationFormulaStrLen+21 < len(dd.Formula1) || dataValidationFormulaStrLen+21 < len(dd.Formula2) {
|
if dataValidationFormulaStrLen < len(utf16.Encode([]rune(dd.Formula1))) || dataValidationFormulaStrLen < len(utf16.Encode([]rune(dd.Formula2))) {
|
||||||
return fmt.Errorf(dataValidationFormulaStrLenErr)
|
return fmt.Errorf(dataValidationFormulaStrLenErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
dd.Formula1 = fmt.Sprintf("<formula1>%s</formula1>", formula1)
|
dd.Formula1 = formula1
|
||||||
dd.Formula2 = fmt.Sprintf("<formula2>%s</formula2>", formula2)
|
dd.Formula2 = formula2
|
||||||
dd.Type = convDataValidationType(t)
|
dd.Type = convDataValidationType(t)
|
||||||
dd.Operator = convDataValidationOperatior(o)
|
dd.Operator = convDataValidationOperatior(o)
|
||||||
return nil
|
return nil
|
||||||
|
@ -148,7 +149,7 @@ func (dd *DataValidation) SetRange(f1, f2 float64, t DataValidationType, o DataV
|
||||||
//
|
//
|
||||||
func (dd *DataValidation) SetSqrefDropList(sqref string, isCurrentSheet bool) error {
|
func (dd *DataValidation) SetSqrefDropList(sqref string, isCurrentSheet bool) error {
|
||||||
if isCurrentSheet {
|
if isCurrentSheet {
|
||||||
dd.Formula1 = fmt.Sprintf("<formula1>%s</formula1>", sqref)
|
dd.Formula1 = sqref
|
||||||
dd.Type = convDataValidationType(typeList)
|
dd.Type = convDataValidationType(typeList)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
27
date.go
27
date.go
|
@ -17,11 +17,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
nanosInADay = float64((24 * time.Hour) / time.Nanosecond)
|
||||||
dayNanoseconds = 24 * time.Hour
|
dayNanoseconds = 24 * time.Hour
|
||||||
maxDuration = 290 * 364 * dayNanoseconds
|
maxDuration = 290 * 364 * dayNanoseconds
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
excel1900Epoc = time.Date(1899, time.December, 30, 0, 0, 0, 0, time.UTC)
|
||||||
|
excel1904Epoc = time.Date(1904, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||||
excelMinTime1900 = time.Date(1899, time.December, 31, 0, 0, 0, 0, time.UTC)
|
excelMinTime1900 = time.Date(1899, time.December, 31, 0, 0, 0, 0, time.UTC)
|
||||||
excelBuggyPeriodStart = time.Date(1900, time.March, 1, 0, 0, 0, 0, time.UTC).Add(-time.Nanosecond)
|
excelBuggyPeriodStart = time.Date(1900, time.March, 1, 0, 0, 0, 0, time.UTC).Add(-time.Nanosecond)
|
||||||
)
|
)
|
||||||
|
@ -131,12 +134,11 @@ func doTheFliegelAndVanFlandernAlgorithm(jd int) (day, month, year int) {
|
||||||
// timeFromExcelTime provides a function to convert an excelTime
|
// timeFromExcelTime provides a function to convert an excelTime
|
||||||
// representation (stored as a floating point number) to a time.Time.
|
// representation (stored as a floating point number) to a time.Time.
|
||||||
func timeFromExcelTime(excelTime float64, date1904 bool) time.Time {
|
func timeFromExcelTime(excelTime float64, date1904 bool) time.Time {
|
||||||
const MDD int64 = 106750 // Max time.Duration Days, aprox. 290 years
|
|
||||||
var date time.Time
|
var date time.Time
|
||||||
var intPart = int64(excelTime)
|
var wholeDaysPart = int(excelTime)
|
||||||
// Excel uses Julian dates prior to March 1st 1900, and Gregorian
|
// Excel uses Julian dates prior to March 1st 1900, and Gregorian
|
||||||
// thereafter.
|
// thereafter.
|
||||||
if intPart <= 61 {
|
if wholeDaysPart <= 61 {
|
||||||
const OFFSET1900 = 15018.0
|
const OFFSET1900 = 15018.0
|
||||||
const OFFSET1904 = 16480.0
|
const OFFSET1904 = 16480.0
|
||||||
const MJD0 float64 = 2400000.5
|
const MJD0 float64 = 2400000.5
|
||||||
|
@ -148,23 +150,14 @@ func timeFromExcelTime(excelTime float64, date1904 bool) time.Time {
|
||||||
}
|
}
|
||||||
return date
|
return date
|
||||||
}
|
}
|
||||||
var floatPart = excelTime - float64(intPart)
|
var floatPart = excelTime - float64(wholeDaysPart)
|
||||||
var dayNanoSeconds float64 = 24 * 60 * 60 * 1000 * 1000 * 1000
|
|
||||||
if date1904 {
|
if date1904 {
|
||||||
date = time.Date(1904, 1, 1, 0, 0, 0, 0, time.UTC)
|
date = excel1904Epoc
|
||||||
} else {
|
} else {
|
||||||
date = time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC)
|
date = excel1900Epoc
|
||||||
}
|
}
|
||||||
|
durationPart := time.Duration(nanosInADay * floatPart)
|
||||||
// Duration is limited to aprox. 290 years
|
return date.AddDate(0, 0, wholeDaysPart).Add(durationPart)
|
||||||
for intPart > MDD {
|
|
||||||
durationDays := time.Duration(MDD) * time.Hour * 24
|
|
||||||
date = date.Add(durationDays)
|
|
||||||
intPart = intPart - MDD
|
|
||||||
}
|
|
||||||
durationDays := time.Duration(intPart) * time.Hour * 24
|
|
||||||
durationPart := time.Duration(dayNanoSeconds * floatPart)
|
|
||||||
return date.Add(durationDays).Add(durationPart)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExcelDateToTime converts a float-based excel date representation to a time.Time.
|
// ExcelDateToTime converts a float-based excel date representation to a time.Time.
|
||||||
|
|
3
sheet.go
3
sheet.go
|
@ -72,12 +72,13 @@ func (f *File) contentTypesReader() *xlsxTypes {
|
||||||
|
|
||||||
if f.ContentTypes == nil {
|
if f.ContentTypes == nil {
|
||||||
f.ContentTypes = new(xlsxTypes)
|
f.ContentTypes = new(xlsxTypes)
|
||||||
|
f.ContentTypes.Lock()
|
||||||
|
defer f.ContentTypes.Unlock()
|
||||||
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML("[Content_Types].xml")))).
|
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML("[Content_Types].xml")))).
|
||||||
Decode(f.ContentTypes); err != nil && err != io.EOF {
|
Decode(f.ContentTypes); err != nil && err != io.EOF {
|
||||||
log.Printf("xml decode error: %s", err)
|
log.Printf("xml decode error: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return f.ContentTypes
|
return f.ContentTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -996,6 +996,7 @@ func parseTime(v string, format string) string {
|
||||||
{"mm", "01"},
|
{"mm", "01"},
|
||||||
{"am/pm", "pm"},
|
{"am/pm", "pm"},
|
||||||
{"m/", "1/"},
|
{"m/", "1/"},
|
||||||
|
{"m", "1"},
|
||||||
{"%%%%", "January"},
|
{"%%%%", "January"},
|
||||||
{"&&&&", "Monday"},
|
{"&&&&", "Monday"},
|
||||||
}
|
}
|
||||||
|
@ -1005,6 +1006,7 @@ func parseTime(v string, format string) string {
|
||||||
{"\\ ", " "},
|
{"\\ ", " "},
|
||||||
{"\\.", "."},
|
{"\\.", "."},
|
||||||
{"\\", ""},
|
{"\\", ""},
|
||||||
|
{"\"", ""},
|
||||||
}
|
}
|
||||||
// It is the presence of the "am/pm" indicator that determines if this is
|
// It is the presence of the "am/pm" indicator that determines if this is
|
||||||
// a 12 hour or 24 hours time format, not the number of 'h' characters.
|
// a 12 hour or 24 hours time format, not the number of 'h' characters.
|
||||||
|
|
|
@ -436,8 +436,8 @@ type DataValidation struct {
|
||||||
ShowInputMessage bool `xml:"showInputMessage,attr,omitempty"`
|
ShowInputMessage bool `xml:"showInputMessage,attr,omitempty"`
|
||||||
Sqref string `xml:"sqref,attr"`
|
Sqref string `xml:"sqref,attr"`
|
||||||
Type string `xml:"type,attr,omitempty"`
|
Type string `xml:"type,attr,omitempty"`
|
||||||
Formula1 string `xml:",innerxml"`
|
Formula1 string `xml:"formula1,omitempty"`
|
||||||
Formula2 string `xml:",innerxml"`
|
Formula2 string `xml:"formula2,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// xlsxC collection represents a cell in the worksheet. Information about the
|
// xlsxC collection represents a cell in the worksheet. Information about the
|
||||||
|
|
Loading…
Reference in New Issue