diff --git a/premailer/element.go b/premailer/element.go index 25aa848..7dc9a24 100644 --- a/premailer/element.go +++ b/premailer/element.go @@ -2,12 +2,14 @@ package premailer import ( "fmt" + "strings" + "github.com/PuerkitoBio/goquery" "github.com/vanng822/css" - "sort" - "strings" ) +type void struct{} + type elementRules struct { element *goquery.Selection rules []*styleRule @@ -17,33 +19,53 @@ type elementRules struct { func (er *elementRules) inline() { inline, _ := er.element.Attr("style") - var inlineStyles map[string]*css.CSSStyleDeclaration + inlineStyles := make([]*css.CSSStyleDeclaration, 0) if inline != "" { inlineStyles = css.ParseBlock(inline) } - + // we collect all occurences + orders := make([]string, 0) styles := make(map[string]string) for _, rule := range er.rules { - for prop, s := range rule.styles { + for _, s := range rule.styles { + prop := s.Property styles[prop] = s.Value + orders = append(orders, prop) } } if len(inlineStyles) > 0 { - for prop, s := range inlineStyles { + for _, s := range inlineStyles { + prop := s.Property styles[prop] = s.Value + orders = append(orders, prop) + } + } + + // now collect the order of property + // each prop will be unique and the last one + // should have the highest priority + // We could inline them all but this will make output cleaner + props := make([]string, 0) + seen := make(map[string]void) + for i := len(orders) - 1; i >= 0; i-- { + prop := orders[i] + if _, ok := seen[prop]; !ok { + seen[prop] = void{} + props = append(props, prop) } } final := make([]string, 0, len(styles)) - for p, v := range styles { + for i := len(props) - 1; i >= 0; i-- { + p := props[i] + v := styles[p] final = append(final, fmt.Sprintf("%s:%s", p, v)) if er.cssToAttributes { er.style_to_basic_html_attribute(p, v) } } - sort.Strings(final) style := strings.Join(final, ";") if style != "" { er.element.SetAttr("style", style) diff --git a/premailer/premailer.go b/premailer/premailer.go index c6404db..1da5efe 100644 --- a/premailer/premailer.go +++ b/premailer/premailer.go @@ -68,14 +68,14 @@ func (pr *premailer) sortRules() { pr.leftover = append(pr.leftover, rule) continue } - normalStyles := make(map[string]*css.CSSStyleDeclaration) - importantStyles := make(map[string]*css.CSSStyleDeclaration) + normalStyles := make([]*css.CSSStyleDeclaration, 0) + importantStyles := make([]*css.CSSStyleDeclaration, 0) - for prop, s := range rule.Style.Styles { + for _, s := range rule.Style.Styles { if s.Important == 1 { - importantStyles[prop] = s + importantStyles = append(importantStyles, s) } else { - normalStyles[prop] = s + normalStyles = append(normalStyles, s) } } diff --git a/premailer/premailer_from_bytes_test.go b/premailer/premailer_from_bytes_test.go index e0af413..99859d3 100644 --- a/premailer/premailer_from_bytes_test.go +++ b/premailer/premailer_from_bytes_test.go @@ -43,7 +43,7 @@ func TestPremailerBasicHTMLBytes(t *testing.T) { result_html, err := p.Transform() assert.Nil(t, err) - assert.Contains(t, result_html, "

Hi!

") + assert.Contains(t, result_html, "

Hi!

") assert.Contains(t, result_html, "

There

") assert.Contains(t, result_html, "

Hello

") assert.Contains(t, result_html, "

Yes!

") diff --git a/premailer/premailer_from_file_test.go b/premailer/premailer_from_file_test.go index 0fa78e1..6bd15ec 100644 --- a/premailer/premailer_from_file_test.go +++ b/premailer/premailer_from_file_test.go @@ -12,7 +12,7 @@ func TestBasicHTMLFromFile(t *testing.T) { result_html, err := p.Transform() assert.Nil(t, err) - assert.Contains(t, result_html, "

Hi!

") + assert.Contains(t, result_html, "

Hi!

") assert.Contains(t, result_html, "

There

") assert.Contains(t, result_html, "

Hello

") assert.Contains(t, result_html, "

Yes!

") diff --git a/premailer/premailer_test.go b/premailer/premailer_test.go index 9899d5f..8b374f5 100644 --- a/premailer/premailer_test.go +++ b/premailer/premailer_test.go @@ -43,7 +43,7 @@ func TestBasicHTML(t *testing.T) { result_html, err := p.Transform() assert.Nil(t, err) - assert.Contains(t, result_html, "

Hi!

") + assert.Contains(t, result_html, "

Hi!

") assert.Contains(t, result_html, "

There

") assert.Contains(t, result_html, "

Hello

") assert.Contains(t, result_html, "

Yes!

") @@ -275,7 +275,7 @@ func TestWithMediaRule(t *testing.T) { assert.Contains(t, result_html, "@media all and (min-width: 62em){") assert.Contains(t, result_html, "font-size: 55px !important;") assert.Contains(t, result_html, "line-height: 60px !important;") - assert.Contains(t, result_html, "padding-bottom: 5px !important;") + assert.Contains(t, result_html, "padding-bottom: 5px !important") assert.Contains(t, result_html, "padding-top: 0 !important") } diff --git a/premailer/style_rule.go b/premailer/style_rule.go index 5cc9e4b..de5221f 100644 --- a/premailer/style_rule.go +++ b/premailer/style_rule.go @@ -7,5 +7,5 @@ import ( type styleRule struct { specificity *specificity selector string - styles map[string]*css.CSSStyleDeclaration + styles []*css.CSSStyleDeclaration } diff --git a/premailer/util.go b/premailer/util.go index a72975d..d69a4a2 100644 --- a/premailer/util.go +++ b/premailer/util.go @@ -6,9 +6,9 @@ import ( func copyRule(selector string, rule *css.CSSRule) *css.CSSRule { // copy rule for each selector - styles := make(map[string]*css.CSSStyleDeclaration) - for prop, s := range rule.Style.Styles { - styles[prop] = css.NewCSSStyleDeclaration(s.Property, s.Value, s.Important) + styles := make([]*css.CSSStyleDeclaration, 0) + for _, s := range rule.Style.Styles { + styles = append(styles, css.NewCSSStyleDeclaration(s.Property, s.Value, s.Important)) } copiedStyle := css.CSSStyleRule{SelectorText: selector, Styles: styles} copiedRule := &css.CSSRule{Type: rule.Type, Style: copiedStyle}