From 9f8f327c74a51662b06337637da26e95e57677ad Mon Sep 17 00:00:00 2001 From: Rodrigo Stewart Date: Tue, 31 Dec 2024 23:30:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0page=20margin?= =?UTF-8?q?=E5=92=8Cnumber=20(#48)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apipara.go | 49 ++++++++++++++++++ structnum.go | 76 +++++++++++++++++++++++++++ structpara.go | 1 + structsect.go | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 264 insertions(+) create mode 100644 structnum.go diff --git a/apipara.go b/apipara.go index 15fe00d..ed146ba 100644 --- a/apipara.go +++ b/apipara.go @@ -78,3 +78,52 @@ func (p *Paragraph) Style(val string) *Paragraph { p.Properties.Style = &Style{Val: val} return p } + +// NumPr number properties +func (p *Paragraph) NumPr(numID, ilvl string) *Paragraph { + if p.Properties == nil { + p.Properties = &ParagraphProperties{} + } + // Initialize run properties if not exist + if p.Properties.RunProperties == nil { + p.Properties.RunProperties = &RunProperties{} + } + p.Properties.NumProperties = &NumProperties{ + NumID: &NumID{ + Val: numID, + }, + Ilvl: &Ilevel{ + Val: ilvl, + }, + } + return p +} + +// NumFont sets the font for numbering +func (p *Paragraph) NumFont(ascii, eastAsia, hansi, hint string) *Paragraph { + if p.Properties == nil { + p.Properties = &ParagraphProperties{} + } + if p.Properties.RunProperties == nil { + p.Properties.RunProperties = &RunProperties{} + } + p.Properties.RunProperties.Fonts = &RunFonts{ + ASCII: ascii, + EastAsia: eastAsia, + HAnsi: hansi, + Hint: hint, + } + return p +} + +// NumSize sets the size for numbering +func (p *Paragraph) NumSize(size string) *Paragraph { + if p.Properties == nil { + p.Properties = &ParagraphProperties{} + } + if p.Properties.RunProperties == nil { + p.Properties.RunProperties = &RunProperties{} + } + p.Properties.RunProperties.Size = &Size{Val: size} + return p +} diff --git a/structnum.go b/structnum.go new file mode 100644 index 0000000..0e239a7 --- /dev/null +++ b/structnum.go @@ -0,0 +1,76 @@ +/* + Copyright (c) 2024 l0g1n + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package docx + +import ( + "encoding/xml" + "io" +) + +// NumProperties show the number properties +type NumProperties struct { + XMLName xml.Name `xml:"w:numPr,omitempty"` + NumID *NumID + Ilvl *Ilevel +} + +// NumID show the number id +type NumID struct { + XMLName xml.Name `xml:"w:numId,omitempty"` + Val string `xml:"w:val,attr"` +} + +// Ilevel show the level +type Ilevel struct { + XMLName xml.Name `xml:"w:ilvl,omitempty"` + Val string `xml:"w:val,attr"` +} + +// UnmarshalXML ... +func (n *NumProperties) UnmarshalXML(d *xml.Decoder, _ xml.StartElement) error { + for { + t, err := d.Token() + if err == io.EOF { + break + } + if err != nil { + return err + } + + if tt, ok := t.(xml.StartElement); ok { + switch tt.Name.Local { + case "numId": + var value NumID + value.Val = getAtt(tt.Attr, "val") + n.NumID = &value + case "ilvl": + var value Ilevel + value.Val = getAtt(tt.Attr, "val") + n.Ilvl = &value + default: + err = d.Skip() // skip unsupported tags + if err != nil { + return err + } + continue + } + } + } + + return nil +} diff --git a/structpara.go b/structpara.go index 8d60d7b..8b5d31e 100644 --- a/structpara.go +++ b/structpara.go @@ -32,6 +32,7 @@ type ParagraphProperties struct { XMLName xml.Name `xml:"w:pPr,omitempty"` Tabs *Tabs Spacing *Spacing + NumProperties *NumProperties Ind *Ind Justification *Justification Shade *Shade diff --git a/structsect.go b/structsect.go index 3fac075..cc66873 100644 --- a/structsect.go +++ b/structsect.go @@ -28,6 +28,9 @@ import ( type SectPr struct { XMLName xml.Name `xml:"w:sectPr,omitempty"` // properties of the document, including paper size PgSz *PgSz `xml:"w:pgSz,omitempty"` + PgMar *PgMar `xml:"w:pgMar,omitempty"` + Cols *Cols `xml:"w:cols,omitempty"` + DocGrid *DocGrid `xml:"w:docGrid,omitempty"` } // PgSz show the paper size @@ -36,6 +39,28 @@ type PgSz struct { H int `xml:"w:h,attr"` // high of paper } +// PgMar show the page margin +type PgMar struct { + Top int `xml:"w:top,attr"` + Left int `xml:"w:left,attr"` + Bottom int `xml:"w:bottom,attr"` + Right int `xml:"w:right,attr"` + Header int `xml:"w:header,attr"` + Footer int `xml:"w:footer,attr"` + Gutter int `xml:"w:gutter,attr"` +} + +// Cols show the number of columns +type Cols struct { + Space int `xml:"w:space,attr"` +} + +// DocGrid show the document grid +type DocGrid struct { + Type string `xml:"w:type,attr"` + LinePitch int `xml:"w:linePitch,attr"` +} + // UnmarshalXML ... func (sect *SectPr) UnmarshalXML(d *xml.Decoder, _ xml.StartElement) error { for { @@ -55,6 +80,27 @@ func (sect *SectPr) UnmarshalXML(d *xml.Decoder, _ xml.StartElement) error { return err } sect.PgSz = &value + case "pgMar": + var value PgMar + err = d.DecodeElement(&value, &tt) + if err != nil && !strings.HasPrefix(err.Error(), "expected") { + return err + } + sect.PgMar = &value + case "cols": + var value Cols + err = d.DecodeElement(&value, &tt) + if err != nil && !strings.HasPrefix(err.Error(), "expected") { + return err + } + sect.Cols = &value + case "docGrid": + var value DocGrid + err = d.DecodeElement(&value, &tt) + if err != nil && !strings.HasPrefix(err.Error(), "expected") { + return err + } + sect.DocGrid = &value default: err = d.Skip() // skip unsupported tags if err != nil { @@ -90,3 +136,95 @@ func (pgsz *PgSz) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { _, err = d.Token() return err } + +// UnmarshalXML ... +func (pgmar *PgMar) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + var err error + + for _, attr := range start.Attr { + switch attr.Name.Local { + case "top": + pgmar.Top, err = strconv.Atoi(attr.Value) + if err != nil { + return err + } + case "left": + pgmar.Left, err = strconv.Atoi(attr.Value) + if err != nil { + return err + } + case "bottom": + pgmar.Bottom, err = strconv.Atoi(attr.Value) + if err != nil { + return err + } + case "right": + pgmar.Right, err = strconv.Atoi(attr.Value) + if err != nil { + return err + } + case "header": + pgmar.Header, err = strconv.Atoi(attr.Value) + if err != nil { + return err + } + case "footer": + pgmar.Footer, err = strconv.Atoi(attr.Value) + if err != nil { + return err + } + case "gutter": + pgmar.Gutter, err = strconv.Atoi(attr.Value) + if err != nil { + return err + } + default: + // ignore other attributes now + } + } + // Consume the end element + _, err = d.Token() + return err +} + +// UnmarshalXML ... +func (cols *Cols) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + var err error + + for _, attr := range start.Attr { + switch attr.Name.Local { + case "space": + cols.Space, err = strconv.Atoi(attr.Value) + if err != nil { + return err + } + default: + // ignore other attributes now + } + } + // Consume the end element + _, err = d.Token() + return err +} + +// UnmarshalXML ... +func (dg *DocGrid) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + var err error + + for _, attr := range start.Attr { + switch attr.Name.Local { + case "linePitch": + dg.LinePitch, err = strconv.Atoi(attr.Value) + if err != nil { + return err + } + case "type": + dg.Type = attr.Value + default: + // ignore other attributes now + } + } + // Consume the end element + _, err = d.Token() + return err +}