Add PreserveTaxonomyNames flag

Before this commit, taxonomy names were hyphenated, lower-cased and normalized -- then fixed and titleized on the archive page.

So what you entered in the front matter isn't necessarily what you got in the final site.

To preserve backwards compability, `PreserveTaxonomyNames` is default `false`.

Setting it to `true` will preserve what you type (the first characters is made toupper for titles), but normalized in URLs.

This also means that, if you manually construct URLs to the archive pages, you will have to pass the Taxonomy names through the `urlize` func.

Fixes #1180
This commit is contained in:
bep 2015-05-31 20:30:53 +02:00
parent 3ea4df35f2
commit be38acdce7
4 changed files with 80 additions and 50 deletions

View file

@ -57,7 +57,7 @@ Complete documentation is available at http://gohugo.io`,
var hugoCmdV *cobra.Command var hugoCmdV *cobra.Command
//Flags that are to be added to commands. //Flags that are to be added to commands.
var BuildWatch, IgnoreCache, Draft, Future, UglyURLs, Verbose, Logging, VerboseLog, DisableRSS, DisableSitemap, PluralizeListTitles, NoTimes bool var BuildWatch, IgnoreCache, Draft, Future, UglyURLs, Verbose, Logging, VerboseLog, DisableRSS, DisableSitemap, PluralizeListTitles, PreserveTaxonomyNames, NoTimes bool
var Source, CacheDir, Destination, Theme, BaseURL, CfgFile, LogFile, Editor string var Source, CacheDir, Destination, Theme, BaseURL, CfgFile, LogFile, Editor string
//Execute adds all child commands to the root command HugoCmd and sets flags appropriately. //Execute adds all child commands to the root command HugoCmd and sets flags appropriately.
@ -102,6 +102,8 @@ func init() {
HugoCmd.PersistentFlags().BoolVar(&VerboseLog, "verboseLog", false, "verbose logging") HugoCmd.PersistentFlags().BoolVar(&VerboseLog, "verboseLog", false, "verbose logging")
HugoCmd.PersistentFlags().BoolVar(&nitro.AnalysisOn, "stepAnalysis", false, "display memory and timing of different steps of the program") HugoCmd.PersistentFlags().BoolVar(&nitro.AnalysisOn, "stepAnalysis", false, "display memory and timing of different steps of the program")
HugoCmd.PersistentFlags().BoolVar(&PluralizeListTitles, "pluralizeListTitles", true, "Pluralize titles in lists using inflect") HugoCmd.PersistentFlags().BoolVar(&PluralizeListTitles, "pluralizeListTitles", true, "Pluralize titles in lists using inflect")
HugoCmd.PersistentFlags().BoolVar(&PreserveTaxonomyNames, "preserveTaxonomyNames", false, `Preserve taxonomy names as written ("Gérard Depardieu" vs "gerard-depardieu")`)
HugoCmd.Flags().BoolVarP(&BuildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed") HugoCmd.Flags().BoolVarP(&BuildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed")
HugoCmd.Flags().BoolVarP(&NoTimes, "noTimes", "", false, "Don't sync modification time of files") HugoCmd.Flags().BoolVarP(&NoTimes, "noTimes", "", false, "Don't sync modification time of files")
hugoCmdV = HugoCmd hugoCmdV = HugoCmd
@ -147,6 +149,7 @@ func LoadDefaultSettings() {
viper.SetDefault("PygmentsUseClasses", false) viper.SetDefault("PygmentsUseClasses", false)
viper.SetDefault("DisableLiveReload", false) viper.SetDefault("DisableLiveReload", false)
viper.SetDefault("PluralizeListTitles", true) viper.SetDefault("PluralizeListTitles", true)
viper.SetDefault("PreserveTaxonomyNames", false)
viper.SetDefault("FootnoteAnchorPrefix", "") viper.SetDefault("FootnoteAnchorPrefix", "")
viper.SetDefault("FootnoteReturnLinkContents", "") viper.SetDefault("FootnoteReturnLinkContents", "")
viper.SetDefault("NewContentEditor", "") viper.SetDefault("NewContentEditor", "")
@ -189,7 +192,7 @@ func InitializeConfig() {
if hugoCmdV.PersistentFlags().Lookup("disableSitemap").Changed { if hugoCmdV.PersistentFlags().Lookup("disableSitemap").Changed {
viper.Set("DisableSitemap", DisableSitemap) viper.Set("DisableSitemap", DisableSitemap)
} }
if hugoCmdV.PersistentFlags().Lookup("verbose").Changed { if hugoCmdV.PersistentFlags().Lookup("verbose").Changed {
viper.Set("Verbose", Verbose) viper.Set("Verbose", Verbose)
} }
@ -198,6 +201,10 @@ func InitializeConfig() {
viper.Set("PluralizeListTitles", PluralizeListTitles) viper.Set("PluralizeListTitles", PluralizeListTitles)
} }
if hugoCmdV.PersistentFlags().Lookup("preserveTaxonomyNames").Changed {
viper.Set("PreserveTaxonomyNames", PreserveTaxonomyNames)
}
if hugoCmdV.PersistentFlags().Lookup("editor").Changed { if hugoCmdV.PersistentFlags().Lookup("editor").Changed {
viper.Set("NewContentEditor", Editor) viper.Set("NewContentEditor", Editor)
} }

View file

@ -539,6 +539,10 @@ func (p *Page) update(f interface{}) error {
} }
func (p *Page) GetParam(key string) interface{} { func (p *Page) GetParam(key string) interface{} {
return p.getParam(key, true)
}
func (p *Page) getParam(key string, stringToLower bool) interface{} {
v := p.Params[strings.ToLower(key)] v := p.Params[strings.ToLower(key)]
if v == nil { if v == nil {
@ -549,7 +553,10 @@ func (p *Page) GetParam(key string) interface{} {
case bool: case bool:
return cast.ToBool(v) return cast.ToBool(v)
case string: case string:
return strings.ToLower(cast.ToString(v)) if stringToLower {
return strings.ToLower(cast.ToString(v))
}
return cast.ToString(v)
case int64, int32, int16, int8, int: case int64, int32, int16, int8, int:
return cast.ToInt(v) return cast.ToInt(v)
case float64, float32: case float64, float32:
@ -557,7 +564,10 @@ func (p *Page) GetParam(key string) interface{} {
case time.Time: case time.Time:
return cast.ToTime(v) return cast.ToTime(v)
case []string: case []string:
return helpers.SliceToLower(v.([]string)) if stringToLower {
return helpers.SliceToLower(v.([]string))
}
return v.([]string)
case map[string]interface{}: // JSON and TOML case map[string]interface{}: // JSON and TOML
return v return v
case map[interface{}]interface{}: // YAML case map[interface{}]interface{}: // YAML

View file

@ -93,27 +93,28 @@ type targetList struct {
} }
type SiteInfo struct { type SiteInfo struct {
BaseURL template.URL BaseURL template.URL
Taxonomies TaxonomyList Taxonomies TaxonomyList
Authors AuthorList Authors AuthorList
Social SiteSocial Social SiteSocial
Sections Taxonomy Sections Taxonomy
Pages *Pages Pages *Pages
Files []*source.File Files []*source.File
Menus *Menus Menus *Menus
Hugo *HugoInfo Hugo *HugoInfo
Title string Title string
Author map[string]interface{} Author map[string]interface{}
LanguageCode string LanguageCode string
DisqusShortname string DisqusShortname string
Copyright string Copyright string
LastChange time.Time LastChange time.Time
Permalinks PermalinkOverrides Permalinks PermalinkOverrides
Params map[string]interface{} Params map[string]interface{}
BuildDrafts bool BuildDrafts bool
canonifyURLs bool canonifyURLs bool
paginationPageCount uint64 preserveTaxonomyNames bool
Data *map[string]interface{} paginationPageCount uint64
Data *map[string]interface{}
} }
// SiteSocial is a place to put social details on a site level. These are the // SiteSocial is a place to put social details on a site level. These are the
@ -465,19 +466,20 @@ func (s *Site) initializeSiteInfo() {
} }
s.Info = SiteInfo{ s.Info = SiteInfo{
BaseURL: template.URL(helpers.SanitizeURLKeepTrailingSlash(viper.GetString("BaseURL"))), BaseURL: template.URL(helpers.SanitizeURLKeepTrailingSlash(viper.GetString("BaseURL"))),
Title: viper.GetString("Title"), Title: viper.GetString("Title"),
Author: viper.GetStringMap("author"), Author: viper.GetStringMap("author"),
LanguageCode: viper.GetString("languagecode"), LanguageCode: viper.GetString("languagecode"),
Copyright: viper.GetString("copyright"), Copyright: viper.GetString("copyright"),
DisqusShortname: viper.GetString("DisqusShortname"), DisqusShortname: viper.GetString("DisqusShortname"),
BuildDrafts: viper.GetBool("BuildDrafts"), BuildDrafts: viper.GetBool("BuildDrafts"),
canonifyURLs: viper.GetBool("CanonifyURLs"), canonifyURLs: viper.GetBool("CanonifyURLs"),
Pages: &s.Pages, preserveTaxonomyNames: viper.GetBool("PreserveTaxonomyNames"),
Menus: &s.Menus, Pages: &s.Pages,
Params: params, Menus: &s.Menus,
Permalinks: permalinks, Params: params,
Data: &s.Data, Permalinks: permalinks,
Data: &s.Data,
} }
} }
@ -833,21 +835,20 @@ func (s *Site) assembleTaxonomies() {
for _, plural := range taxonomies { for _, plural := range taxonomies {
s.Taxonomies[plural] = make(Taxonomy) s.Taxonomies[plural] = make(Taxonomy)
for _, p := range s.Pages { for _, p := range s.Pages {
vals := p.GetParam(plural) vals := p.getParam(plural, !s.Info.preserveTaxonomyNames)
weight := p.GetParam(plural + "_weight") weight := p.GetParam(plural + "_weight")
if weight == nil { if weight == nil {
weight = 0 weight = 0
} }
if vals != nil { if vals != nil {
if v, ok := vals.([]string); ok { if v, ok := vals.([]string); ok {
for _, idx := range v { for _, idx := range v {
x := WeightedPage{weight.(int), p} x := WeightedPage{weight.(int), p}
s.Taxonomies[plural].Add(idx, x) s.Taxonomies[plural].Add(idx, x, s.Info.preserveTaxonomyNames)
} }
} else if v, ok := vals.(string); ok { } else if v, ok := vals.(string); ok {
x := WeightedPage{weight.(int), p} x := WeightedPage{weight.(int), p}
s.Taxonomies[plural].Add(v, x) s.Taxonomies[plural].Add(v, x, s.Info.preserveTaxonomyNames)
} else { } else {
jww.ERROR.Printf("Invalid %s in %s\n", plural, p.File.Path()) jww.ERROR.Printf("Invalid %s in %s\n", plural, p.File.Path())
} }
@ -864,7 +865,7 @@ func (s *Site) assembleTaxonomies() {
func (s *Site) assembleSections() { func (s *Site) assembleSections() {
for i, p := range s.Pages { for i, p := range s.Pages {
s.Sections.Add(p.Section(), WeightedPage{s.Pages[i].Weight, s.Pages[i]}) s.Sections.Add(p.Section(), WeightedPage{s.Pages[i].Weight, s.Pages[i]}, s.Info.preserveTaxonomyNames)
} }
for k := range s.Sections { for k := range s.Sections {
@ -1058,9 +1059,16 @@ func (s *Site) RenderTaxonomiesLists() error {
} }
func (s *Site) newTaxonomyNode(t taxRenderInfo) (*Node, string) { func (s *Site) newTaxonomyNode(t taxRenderInfo) (*Node, string) {
base := t.plural + "/" + t.key key := t.key
n := s.NewNode() n := s.NewNode()
n.Title = strings.Replace(strings.Title(t.key), "-", " ", -1) if s.Info.preserveTaxonomyNames {
key = helpers.MakePathToLower(key)
// keep as is, just make sure the first char is upper
n.Title = helpers.FirstUpper(t.key)
} else {
n.Title = strings.Replace(strings.Title(t.key), "-", " ", -1)
}
base := t.plural + "/" + key
s.setURLs(n, base) s.setURLs(n, base)
if len(t.pages) > 0 { if len(t.pages) > 0 {
n.Date = t.pages[0].Page.Date n.Date = t.pages[0].Page.Date
@ -1179,16 +1187,19 @@ func (s *Site) newSectionListNode(sectionName, section string, data WeightedPage
// RenderSectionLists renders a page for each section // RenderSectionLists renders a page for each section
func (s *Site) RenderSectionLists() error { func (s *Site) RenderSectionLists() error {
for section, data := range s.Sections { for section, data := range s.Sections {
// section keys can be lower case (depending on site.pathifyTaxonomyKeys)
// section keys are lower case
// extract the original casing from the first page to get sensible titles. // extract the original casing from the first page to get sensible titles.
sectionName := section sectionName := section
if len(data) > 0 { if !s.Info.preserveTaxonomyNames && len(data) > 0 {
sectionName = data[0].Page.Section() sectionName = data[0].Page.Section()
} }
layouts := s.appendThemeTemplates( layouts := s.appendThemeTemplates(
[]string{"section/" + section + ".html", "_default/section.html", "_default/list.html", "indexes/" + section + ".html", "_default/indexes.html"}) []string{"section/" + section + ".html", "_default/section.html", "_default/list.html", "indexes/" + section + ".html", "_default/indexes.html"})
if s.Info.preserveTaxonomyNames {
section = helpers.MakePathToLower(section)
}
n := s.newSectionListNode(sectionName, section, data) n := s.newSectionListNode(sectionName, section, data)
if err := s.renderAndWritePage(fmt.Sprintf("section %s", section), section, n, s.appendThemeTemplates(layouts)...); err != nil { if err := s.renderAndWritePage(fmt.Sprintf("section %s", section), section, n, s.appendThemeTemplates(layouts)...); err != nil {
return err return err

View file

@ -65,8 +65,10 @@ func kp(in string) string {
func (i Taxonomy) Get(key string) WeightedPages { return i[kp(key)] } func (i Taxonomy) Get(key string) WeightedPages { return i[kp(key)] }
func (i Taxonomy) Count(key string) int { return len(i[kp(key)]) } func (i Taxonomy) Count(key string) int { return len(i[kp(key)]) }
func (i Taxonomy) Add(key string, w WeightedPage) { func (i Taxonomy) Add(key string, w WeightedPage, pretty bool) {
key = kp(key) if !pretty {
key = kp(key)
}
i[key] = append(i[key], w) i[key] = append(i[key], w)
} }