Skip to content

Commit

Permalink
Table Borders implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
gomutex committed Feb 2, 2024
1 parent 16686dd commit f35ee90
Show file tree
Hide file tree
Showing 5 changed files with 371 additions and 2 deletions.
39 changes: 39 additions & 0 deletions oxml/elements/border_position.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package elements

// TableBorderPosition represents the position of a border in a table.
type TableBorderPosition string

const (
TableBorderPositionLeft TableBorderPosition = "w:left"
TableBorderPositionRight TableBorderPosition = "w:right"
TableBorderPositionTop TableBorderPosition = "w:top"
TableBorderPositionBottom TableBorderPosition = "w:bottom"
TableBorderPositionInsideH TableBorderPosition = "w:insideH"
TableBorderPositionInsideV TableBorderPosition = "w:insideV"
)

// TableCellBorderPosition represents the position of a border in a table cell.
type TableCellBorderPosition int

const (
TableCellBorderPositionLeft TableCellBorderPosition = 1
TableCellBorderPositionRight TableCellBorderPosition = 2
TableCellBorderPositionTop TableCellBorderPosition = 3
TableCellBorderPositionBottom TableCellBorderPosition = 4
TableCellBorderPositionInsideH TableCellBorderPosition = 5
TableCellBorderPositionInsideV TableCellBorderPosition = 6
TableCellBorderPositionTl2br TableCellBorderPosition = 7
TableCellBorderPositionTr2bl TableCellBorderPosition = 8
)

// ParagraphBorderPosition represents the position of a border in a paragraph.
type ParagraphBorderPosition int

const (
ParagraphBorderPositionLeft ParagraphBorderPosition = 1
ParagraphBorderPositionRight ParagraphBorderPosition = 2
ParagraphBorderPositionTop ParagraphBorderPosition = 3
ParagraphBorderPositionBottom ParagraphBorderPosition = 4
ParagraphBorderPositionBetween ParagraphBorderPosition = 5
ParagraphBorderPositionBar ParagraphBorderPosition = 6
)
37 changes: 37 additions & 0 deletions oxml/elements/border_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package elements

type BorderType string

const (
BorderTypeNil BorderType = "nil"
BorderTypeNone BorderType = "none"
BorderTypeSingle BorderType = "single"
BorderTypeThick BorderType = "thick"
BorderTypeDouble BorderType = "double"
BorderTypeDotted BorderType = "dotted"
BorderTypeDashed BorderType = "dashed"
BorderTypeDotDash BorderType = "dotDash"
BorderTypeDotDotDash BorderType = "dotDotDash"
BorderTypeTriple BorderType = "triple"
BorderTypeThinThickSmallGap BorderType = "thinThickSmallGap"
BorderTypeThickThinSmallGap BorderType = "thickThinSmallGap"
BorderTypeThinThickThinSmallGap BorderType = "thinThickThinSmallGap"
BorderTypeThinThickMediumGap BorderType = "thinThickMediumGap"
BorderTypeThickThinMediumGap BorderType = "thickThinMediumGap"
BorderTypeThinThickThinMediumGap BorderType = "thinThickThinMediumGap"
BorderTypeThinThickLargeGap BorderType = "thinThickLargeGap"
BorderTypeThickThinLargeGap BorderType = "thickThinLargeGap"
BorderTypeThinThickThinLargeGap BorderType = "thinThickThinLargeGap"
BorderTypeWave BorderType = "wave"
BorderTypeDoubleWave BorderType = "doubleWave"
BorderTypeDashSmallGap BorderType = "dashSmallGap"
BorderTypeDashDotStroked BorderType = "dashDotStroked"
BorderTypeThreeDEmboss BorderType = "threeDEmboss"
BorderTypeThreeDEngrave BorderType = "threeDEngrave"
BorderTypeOutset BorderType = "outset"
BorderTypeInset BorderType = "inset"
BorderTypeApples BorderType = "apples"
BorderTypeArchedScallops BorderType = "archedScallops"
BorderTypeBabyPacifier BorderType = "babyPacifier"
BorderTypeBabyRattle BorderType = "babyRattle"
)
204 changes: 204 additions & 0 deletions oxml/elements/table_borders.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
package elements

import (
"encoding/xml"
"strconv"
)

type TableBorderElement struct {
BorderType BorderType
Position TableBorderPosition
Size uint64
Space uint64
Color string
}

type TableBorders struct {
Top *TableBorderElement
Bottom *TableBorderElement
Left *TableBorderElement
Right *TableBorderElement
InsideH *TableBorderElement
InsideV *TableBorderElement
}

// DefaulTableBorderElement creates a new TableBorderElement instance with default values.
// It sets the default border type to single, size to 2, space to 0, color to "000000",
// and position to TableBorderPositionBottom.
func DefaulTableBorderElement() *TableBorderElement {
return &TableBorderElement{
BorderType: BorderTypeSingle,
Size: 2,
Space: 0,
Color: "000000",
Position: TableBorderPositionBottom,
}
}

// NewTableBorderElement returns a new table border with the given properties.
func NewTableBorderElement(borderType BorderType, size uint64, color string, position TableBorderPosition, space uint64) *TableBorderElement {
return &TableBorderElement{
BorderType: borderType,
Size: size,
Color: color,
Position: position,
Space: space,
}
}

func DefaultTableBorders() *TableBorders {
return &TableBorders{}
}

// MarshalXML implements the xml.Marshaler interface for TableBorderElement.
func (t *TableBorderElement) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
start.Name.Local = string(t.Position)

start.Attr = append(start.Attr, xml.Attr{Name: xml.Name{Local: "w:val"}, Value: string(t.BorderType)})
start.Attr = append(start.Attr, xml.Attr{Name: xml.Name{Local: "w:sz"}, Value: strconv.FormatInt(int64(t.Size), 10)})
start.Attr = append(start.Attr, xml.Attr{Name: xml.Name{Local: "w:space"}, Value: strconv.FormatInt(int64(t.Space), 10)})
start.Attr = append(start.Attr, xml.Attr{Name: xml.Name{Local: "w:color"}, Value: t.Color})

return e.EncodeElement("", start)
}

func (t *TableBorderElement) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) {

switch start.Name.Local {
case "top":
t.Position = TableBorderPositionTop
case "bottom":
t.Position = TableBorderPositionBottom
case "right":
t.Position = TableBorderPositionRight
case "left":
t.Position = TableBorderPositionLeft
case "insideH":
t.Position = TableBorderPositionInsideH
case "insideV":
t.Position = TableBorderPositionInsideV
}

for _, attr := range start.Attr {
switch attr.Name.Local {
case "sz":
valueStr := attr.Value
if valueStr != "" {
value, err := strconv.ParseUint(valueStr, 10, 0)
if err != nil {
return err
}
t.Size = value
}
case "space":
valueStr := attr.Value
if valueStr != "" {
value, err := strconv.ParseUint(valueStr, 10, 0)
if err != nil {
return err
}
t.Space = value
}
case "val":
t.BorderType = BorderType(attr.Value)
case "color":
t.Color = attr.Value
}
}

return d.Skip() // Skipping the inner content
}

func (t *TableBorders) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
start.Name.Local = "tblBorders"

if err := e.EncodeToken(start); err != nil {
return err
}
// Marshal each border individually
if t.Top != nil {
if err := e.Encode(t.Top); err != nil {
return err
}
}
if t.Left != nil {
if err := e.Encode(t.Left); err != nil {
return err
}
}
if t.Bottom != nil {
if err := e.Encode(t.Bottom); err != nil {
return err
}
}
if t.Right != nil {
if err := e.Encode(t.Right); err != nil {
return err
}
}
if t.InsideH != nil {
if err := e.Encode(t.InsideH); err != nil {
return err
}
}
if t.InsideV != nil {
if err := e.Encode(t.InsideV); err != nil {
return err
}
}

return e.EncodeToken(xml.EndElement{Name: start.Name})

}

func (t *TableBorders) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {

// Loop through each element within tblBorders
for {
token, err := d.Token()
if err != nil {
return err
}
switch elem := token.(type) {
case xml.StartElement:
switch elem.Name.Local {
case "top":

t.Top = &TableBorderElement{}
if err := d.DecodeElement(t.Top, &elem); err != nil {
return err
}
case "left":
t.Left = &TableBorderElement{}
if err := d.DecodeElement(t.Left, &elem); err != nil {
return err
}
case "bottom":
t.Bottom = &TableBorderElement{}
if err := d.DecodeElement(t.Bottom, &elem); err != nil {
return err
}
case "right":
t.Right = &TableBorderElement{}
if err := d.DecodeElement(t.Right, &elem); err != nil {
return err
}
case "insideH":
t.InsideH = &TableBorderElement{}
if err := d.DecodeElement(t.InsideH, &elem); err != nil {
return err
}
case "insideV":
t.InsideV = &TableBorderElement{}
if err := d.DecodeElement(t.InsideV, &elem); err != nil {
return err
}
}

case xml.EndElement:
if elem == start.End() {
return nil
}
}
}
}
78 changes: 78 additions & 0 deletions oxml/elements/table_borders_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package elements

import (
"encoding/xml"
"testing"
)

func TestTableBorderElementMarshaling(t *testing.T) {
tblBorder := DefaulTableBorderElement()
tblBorder.BorderType = BorderTypeSingle
tblBorder.Color = "000000"
tblBorder.Position = TableBorderPositionTop
tblBorder.Space = 0
tblBorder.Size = 2
xmlData, err := xml.Marshal(tblBorder)
if err != nil {
t.Fatalf("Error marshaling TableBorders to XML: %v", err)
}

var unmarshalledTableBorder TableBorderElement
err = xml.Unmarshal(xmlData, &unmarshalledTableBorder)
if err != nil {
t.Fatalf("Error unmarshaling XML to TableBorder: %v", err)
}

if unmarshalledTableBorder.Position != tblBorder.Position {
t.Errorf("Expected TableBorder Position value %s, got %s", tblBorder.Position, unmarshalledTableBorder.Position)
}

if unmarshalledTableBorder.BorderType != tblBorder.BorderType {
t.Errorf("Expected TableBorder BorderType value %s, got %s", tblBorder.BorderType, unmarshalledTableBorder.BorderType)
}

if unmarshalledTableBorder.Color != tblBorder.Color {
t.Errorf("Expected TableBorder Color value %s, got %s", tblBorder.Color, unmarshalledTableBorder.Color)
}

if unmarshalledTableBorder.Size != tblBorder.Size {
t.Errorf("Expected TableBorder Size value %v, got %v", tblBorder.Size, unmarshalledTableBorder.Size)
}

}

func TestTableBordersMarshaling(t *testing.T) {
tblBorders := DefaultTableBorders()
tblBorders.Bottom = DefaulTableBorderElement()
xmlData, err := xml.Marshal(tblBorders)
if err != nil {
t.Fatalf("Error marshaling TableBorders to XML: %v", err)
}

var unmarshalledTableBorders TableBorders
err = xml.Unmarshal(xmlData, &unmarshalledTableBorders)
if err != nil {
t.Fatalf("Error unmarshaling XML to TableBorders: %v", err)
}

if unmarshalledTableBorders.Bottom == nil {
t.Fatalf("Error unmarshaling XML to TableBorders: Top got nil value")
}

if unmarshalledTableBorders.Bottom.Position != tblBorders.Bottom.Position {
t.Errorf("Expected TableBorder Position value %s, got %s", tblBorders.Bottom.Position, unmarshalledTableBorders.Bottom.Position)
}

if unmarshalledTableBorders.Bottom.BorderType != tblBorders.Bottom.BorderType {
t.Errorf("Expected TableBorder BorderType value %s, got %s", tblBorders.Bottom.BorderType, unmarshalledTableBorders.Bottom.BorderType)
}

if unmarshalledTableBorders.Bottom.Color != tblBorders.Bottom.Color {
t.Errorf("Expected TableBorder Color value %s, got %s", tblBorders.Bottom.Color, unmarshalledTableBorders.Bottom.Color)
}

if unmarshalledTableBorders.Bottom.Size != tblBorders.Bottom.Size {
t.Errorf("Expected TableBorder Size value %v, got %v", tblBorders.Bottom.Size, unmarshalledTableBorders.Bottom.Size)
}

}
15 changes: 13 additions & 2 deletions oxml/elements/table_property.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ type TableProperty struct {
Style *TableStyle
Indent *TableIndent
Margins *TableCellMargins

// Borders TableBorders // TODO: implement borders
Borders *TableBorders
}

func DefaultTableProperty() *TableProperty {
Expand Down Expand Up @@ -65,6 +64,12 @@ func (t *TableProperty) MarshalXML(e *xml.Encoder, start xml.StartElement) (err
}
}

if t.Borders != nil {
if err = e.EncodeElement(t.Borders, xml.StartElement{Name: xml.Name{Local: "w:tblBorders"}}); err != nil {
return err
}
}

return e.EncodeToken(xml.EndElement{Name: start.Name})
}

Expand Down Expand Up @@ -114,6 +119,12 @@ func (t *TableProperty) UnmarshalXML(d *xml.Decoder, start xml.StartElement) err
return err
}
t.Margins = &tblCellMargins
case xml.Name{Space: constants.WMLNamespace, Local: "tblBorders"}, xml.Name{Space: constants.AltWMLNamespace, Local: "tblBorders"}:
tblBorders := TableBorders{}
if err := d.DecodeElement(tblBorders, &elem); err != nil {
return err
}
t.Borders = &tblBorders
default:
if err = d.Skip(); err != nil {
return err
Expand Down

0 comments on commit f35ee90

Please sign in to comment.