diff --git a/apipara.go b/apipara.go
index 12bee30..4151631 100644
--- a/apipara.go
+++ b/apipara.go
@@ -11,3 +11,19 @@ func (f *Docx) AddParagraph() *Paragraph {
return p
}
+
+// Justification allows to set para's horizonal alignment
+//
+// w:jc 属性的取值可以是以下之一:
+// start:左对齐。
+// center:居中对齐。
+// end:右对齐。
+// both:两端对齐。
+// distribute:分散对齐。
+func (p *Paragraph) Justification(val string) *Paragraph {
+ if p.Properties == nil {
+ p.Properties = &ParagraphProperties{}
+ }
+ p.Properties.Justification = &Justification{Val: val}
+ return p
+}
diff --git a/apirun.go b/apirun.go
index 182db8f..067fc4e 100644
--- a/apirun.go
+++ b/apirun.go
@@ -1,5 +1,7 @@
package docxlib
+import "encoding/xml"
+
// Color allows to set run color
func (r *Run) Color(color string) *Run {
r.RunProperties.Color = &Color{
@@ -17,3 +19,35 @@ func (r *Run) Size(size string) *Run {
return r
}
+
+// Justification allows to set run's horizonal alignment
+//
+// w:jc 属性的取值可以是以下之一:
+// start:左对齐。
+// center:居中对齐。
+// end:右对齐。
+// both:两端对齐。
+// distribute:分散对齐。
+func (r *Run) Justification(val string) *Run {
+ r.RunProperties.Justification = &Justification{
+ Val: val,
+ }
+
+ return r
+}
+
+// AddTab add a tab in front of the run
+func (r *Run) AddTab() *Run {
+ r.FrontTab = append(r.FrontTab, struct {
+ XMLName xml.Name "xml:\"w:tab,omitempty\""
+ }{})
+ return r
+}
+
+// AppendTab add a tab after the run
+func (r *Run) AppendTab() *Run {
+ r.RearTab = append(r.RearTab, struct {
+ XMLName xml.Name "xml:\"w:tab,omitempty\""
+ }{})
+ return r
+}
diff --git a/apitext.go b/apitext.go
index c556aa6..3442f6d 100644
--- a/apitext.go
+++ b/apitext.go
@@ -1,7 +1,25 @@
package docxlib
+import "encoding/xml"
+
+// AddTab adds tab to para
+func (p *Paragraph) AddTab() *Run {
+ run := &Run{
+ RunProperties: &RunProperties{},
+ FrontTab: []struct {
+ XMLName xml.Name "xml:\"w:tab,omitempty\""
+ }{{}},
+ }
+ p.Children = append(p.Children, ParagraphChild{Run: run})
+ return run
+}
+
// AddText adds text to paragraph
func (p *Paragraph) AddText(text string) *Run {
+ if text == "\t" {
+ return p.AddTab()
+ }
+
t := &Text{
Text: text,
}
diff --git a/cmd/main/main.go b/cmd/main/main.go
index 32843b1..b1541ac 100644
--- a/cmd/main/main.go
+++ b/cmd/main/main.go
@@ -19,36 +19,41 @@ func main() {
w := docxlib.NewA4()
// add new paragraph
- para1 := w.AddParagraph()
+ para1 := w.AddParagraph().Justification("distribute")
// add text
- para1.AddText("test")
+ para1.AddText("test").Justification("distribute")
+ para1.AddText("test font size").Size("44").Justification("distribute")
+ para1.AddText("test color").Color("808080").Justification("distribute")
- para1.AddText("test font size").Size("44")
- para1.AddText("test color").Color("808080")
- para2 := w.AddParagraph()
- para2.AddText("test font size and color").Size("44").Color("ff0000")
+ para2 := w.AddParagraph().Justification("end")
+ para2.AddText("test font size and color").Size("44").Color("ff0000").Justification("end")
nextPara := w.AddParagraph()
nextPara.AddLink("google", `http://google.com`)
- para3 := w.AddParagraph()
+ para3 := w.AddParagraph().Justification("center")
// add text
- para3.AddText("直接粘贴 inline")
+ para3.AddText("一行2个 inline").Size("44").Justification("center")
- para4 := w.AddParagraph()
+ para4 := w.AddParagraph().Justification("center")
r, err := para4.AddInlineDrawingFrom("testdata/fumiama.JPG")
if err != nil {
panic(err)
}
- r.Drawing.Inline.Size(r.Drawing.Inline.Extent.CX/2, r.Drawing.Inline.Extent.CY/2)
+ r.Drawing.Inline.Size(r.Drawing.Inline.Extent.CX*4/5, r.Drawing.Inline.Extent.CY*4/5)
+ para4.AddTab().AddTab()
r, err = para4.AddInlineDrawingFrom("testdata/fumiama2x.webp")
if err != nil {
panic(err)
}
- r.Drawing.Inline.Size(r.Drawing.Inline.Extent.CX/2, r.Drawing.Inline.Extent.CY/2)
+ r.Drawing.Inline.Size(r.Drawing.Inline.Extent.CX*4/5, r.Drawing.Inline.Extent.CY*4/5)
- para5 := w.AddParagraph()
- _, err = para5.AddInlineDrawingFrom("testdata/fumiamayoko.png")
+ para5 := w.AddParagraph().Justification("center")
+ // add text
+ para5.AddText("一行1个 横向 inline").Size("44").Justification("center")
+
+ para6 := w.AddParagraph()
+ _, err = para6.AddInlineDrawingFrom("testdata/fumiamayoko.png")
if err != nil {
panic(err)
}
diff --git a/structdoc_test.go b/structdoc_test.go
index f9fa4fa..7386045 100644
--- a/structdoc_test.go
+++ b/structdoc_test.go
@@ -40,9 +40,6 @@ func TestUnmarshalPlainStructure(t *testing.T) {
if child.Link == nil && child.Properties == nil && child.Run == nil {
t.Fatalf("There are Paragraph children with all fields nil")
}
- if child.Run != nil && child.Run.Text == nil && child.Run.InstrText == "" {
- t.Fatalf("We have a run with no text")
- }
if child.Link != nil && child.Link.ID == "" {
t.Fatalf("We have a link without ID")
}
@@ -572,10 +569,11 @@ func TestMarshalDrawingStructure(t *testing.T) {
// add new paragraph
para1 := w.AddParagraph()
// add text
- para1.AddText("直接粘贴 inline")
+ para1.AddText("直接粘贴 inline").AddTab().Justification("center")
- para2 := w.AddParagraph()
+ para2 := w.AddParagraph().Justification("center")
para2.AddInlineDrawingFrom("testdata/fumiama.JPG")
+ para2.AddTab().AddTab().AppendTab().AppendTab()
para2.AddInlineDrawingFrom("testdata/fumiama2x.webp")
para3 := w.AddParagraph()
diff --git a/structpara.go b/structpara.go
index 0ee3bef..6b5887a 100644
--- a/structpara.go
+++ b/structpara.go
@@ -6,6 +6,35 @@ import (
"strings"
)
+type ParagraphProperties struct {
+ XMLName xml.Name `xml:"w:pPr,omitempty"`
+ Justification *Justification `xml:"w:jc,omitempty"`
+}
+
+func (p *ParagraphProperties) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
+ for {
+ t, err := d.Token()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return err
+ }
+ switch tt := t.(type) {
+ case xml.StartElement:
+ switch tt.Name.Local {
+ case "jc":
+ p.Justification = &Justification{Val: getAtt(tt.Attr, "val")}
+ default:
+ continue
+ }
+ }
+
+ }
+ return nil
+
+}
+
type ParagraphChild struct {
Link *Hyperlink `xml:"w:hyperlink,omitempty"`
Run *Run `xml:"w:r,omitempty"`
@@ -13,8 +42,9 @@ type ParagraphChild struct {
}
type Paragraph struct {
- XMLName xml.Name `xml:"w:p,omitempty"`
- Children []ParagraphChild // Children will generate an unnecessary tag ... and we skip it by a self-defined xml.Marshaler
+ XMLName xml.Name `xml:"w:p,omitempty"`
+ Properties *ParagraphProperties
+ Children []ParagraphChild // Children will generate an unnecessary tag ... and we skip it by a self-defined xml.Marshaler
file *Docx
}
@@ -51,6 +81,12 @@ func (p *Paragraph) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
if err != nil {
return err
}
+ if p.Properties != nil {
+ err = e.Encode(p.Properties)
+ if err != nil {
+ return err
+ }
+ }
for _, c := range p.Children {
switch {
case c.Link != nil:
@@ -99,13 +135,15 @@ func (p *Paragraph) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var value Run
d.DecodeElement(&value, &start)
elem.Run = &value
- if value.InstrText == "" && value.Text == nil && value.Drawing == nil {
- continue
- }
case "rPr":
var value RunProperties
d.DecodeElement(&value, &start)
elem.Properties = &value
+ case "pPr":
+ var value ParagraphProperties
+ d.DecodeElement(&value, &start)
+ p.Properties = &value
+ continue
default:
continue
}
diff --git a/structrun.go b/structrun.go
index f02a82c..6f50ec3 100644
--- a/structrun.go
+++ b/structrun.go
@@ -10,9 +10,15 @@ import (
type Run struct {
XMLName xml.Name `xml:"w:r,omitempty"`
RunProperties *RunProperties `xml:"w:rPr,omitempty"`
- InstrText string `xml:"w:instrText,omitempty"`
- Text *Text
- Drawing *Drawing
+ FrontTab []struct {
+ XMLName xml.Name `xml:"w:tab,omitempty"`
+ }
+ InstrText string `xml:"w:instrText,omitempty"`
+ Text *Text
+ Drawing *Drawing
+ RearTab []struct {
+ XMLName xml.Name `xml:"w:tab,omitempty"`
+ }
}
func (r *Run) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
@@ -44,6 +50,16 @@ func (r *Run) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var value Drawing
d.DecodeElement(&value, &start)
r.Drawing = &value
+ case "tab":
+ if r.InstrText == "" && r.Text == nil && r.Drawing == nil {
+ r.FrontTab = append(r.FrontTab, struct {
+ XMLName xml.Name "xml:\"w:tab,omitempty\""
+ }{})
+ } else {
+ r.RearTab = append(r.RearTab, struct {
+ XMLName xml.Name "xml:\"w:tab,omitempty\""
+ }{})
+ }
default:
continue
}
@@ -57,11 +73,12 @@ func (r *Run) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
// RunProperties encapsulates visual properties of a run
type RunProperties struct {
- XMLName xml.Name `xml:"w:rPr,omitempty"`
- Color *Color `xml:"w:color,omitempty"`
- Size *Size `xml:"w:sz,omitempty"`
- RunStyle *RunStyle `xml:"w:rStyle,omitempty"`
- Style *Style `xml:"w:pStyle,omitempty"`
+ XMLName xml.Name `xml:"w:rPr,omitempty"`
+ Color *Color `xml:"w:color,omitempty"`
+ Size *Size `xml:"w:sz,omitempty"`
+ RunStyle *RunStyle `xml:"w:rStyle,omitempty"`
+ Style *Style `xml:"w:pStyle,omitempty"`
+ Justification *Justification `xml:"w:jc,omitempty"`
}
func (r *RunProperties) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
@@ -93,6 +110,10 @@ func (r *RunProperties) UnmarshalXML(d *xml.Decoder, start xml.StartElement) err
var value Style
value.Val = getAtt(tt.Attr, "val")
r.Style = &value
+ case "jc":
+ var value Justification
+ value.Val = getAtt(tt.Attr, "val")
+ r.Justification = &value
default:
continue
}
@@ -128,3 +149,16 @@ type Size struct {
XMLName xml.Name `xml:"w:sz"`
Val string `xml:"w:val,attr"`
}
+
+// Justification contains the way of the horizonal alignment
+//
+// w:jc 属性的取值可以是以下之一:
+// start:左对齐。
+// center:居中对齐。
+// end:右对齐。
+// both:两端对齐。
+// distribute:分散对齐。
+type Justification struct {
+ XMLName xml.Name `xml:"w:jc"`
+ Val string `xml:"w:val,attr"`
+}