murklinstest (murklinstest) wrote,
murklinstest
murklinstest

Style Contest: Multi-Level Tags with Abbreviations and Menu Links

This is code for when you have a lot of tag tiers, with long names, and you want to use a lot of abbreviations in the tags themselves, but have the Tags Page and sidebar tags box show the full tier names. This code also includes internal anchors to the first and second level tiers, and prints above the tiered list some menu links that point to those anchors. All top level tiers are in one group, and then you can customize which second level tiers you would like to have menu links for. Each second level tier you select will have its own group of links.

Step 1
First, add this code near the top of your theme layer, just after all your set lines. Here you are setting up the long form tier names and the abbreviations they map to. These will be used both on the Tags Page and in the sidebar box. Replace the example tags and abbreviations with your own. Notice that if you have built spaces into your tags after the delimiter character, you need to include that space here as well.
class TagAliases {
  var string{} tag_aliases;
  function init();
}

#### CONFIGURE THE TAG ALIASES ####

function TagAliases::init() {
    $this.tag_aliases = {
      "[fandom wips]" => "01",
      "[rps wips]" => "02",
      "[other wips]" => "03",
      " smallville" => " sv",
      " cw network" => " cw",
      " character" => " ch",
      " slash" => " sl"
    };
}

###################################

Step 2
Now add to your theme layer the sidebar box code and configure the blue values as desired:
function print_module_tags(string title) {

#####   Config   #####

  # Specify your delimiter.  One char only -- extra chars get truncated.
  var string delimiter = ":";

  # Do you want to show the tag use counts? Set to true or false.
  var bool show_count = false;

  # Specify the text to show just before the use count, if any.
  var string pre_count = "[";

  # Specify the text to show just after the use count, if any.
  var string post_count = "]";

  # Which secondary menus do you want to show? Use long form names, not abbreviations.
  # Separate each one by a comma. Only include spaces if they are used in the tag itself.
  var string secondary_menus = "fanfiction,length";

##### End Config #####

  var Page p = get_page();
  var string list = "";
  var string menuone = "";
  var string{} menutwo = {"" => ""};
  var TagAliases ta = new TagAliases;
  $ta->init();
  var string{} tag_aliases = $ta.tag_aliases;

  if (size $p->visible_tag_list() > 0) { 
    if ($delimiter->length() > 1) {
      $delimiter = $delimiter->substr(0, 1);
    } 

    # mt:20070501
    var string{} tag_aliases_short;
    # Reindex tag alias hash using the values as keys to make lookups easier
    foreach var string k ($tag_aliases) {
      var string new_key = $tag_aliases{$k};
      $tag_aliases_short{$new_key} = $k;
    } 

    # mt:20070502
    # Reindex the tags so that we can quickly look up which tiers are true tags, not just labels
    var TagDetail{} truetags;
    foreach var TagDetail t ($p->visible_tag_list()) {
      $truetags{$t.name} = $t;            
    }

    var string[] closing_html;
    var string[] prev_tags;
    var int tag_list_pos = 0;
    var string tier_code = "";
    $closing_html[0] = "";
    $prev_tags[0] = "";
    foreach var TagDetail t ($p->visible_tag_list()) {
      var string[] tags;
 
      if ($t.name) {  
        # mt:20050623
        # Split tags into array on delimiter. Oh god, my kingdom
        # for a function.  Stolen shamelessly from lj-user rane500.
        var int array_counter = 0;
        var string buffer = "";
        foreach var string char ($t.name) {
          if($char == $delimiter) {
            $tags[$array_counter] = $buffer;
            $array_counter = $array_counter + 1;
            $buffer = "";
          }
          else {
            $buffer = $buffer + $char;
          } 
        }  
        $tags[$array_counter] = $buffer;
  
        var int pos = 0;
        var bool show_all_tiers = false;
        var string menulink = "";
        var string menuheader = "";
        foreach var string tier($tags) {
          if (size $closing_html <= $pos) {
            # mt:20050623
            # $closing_html keeps track of html that is used to close off open
            # lists.  Its length must be kept >= to that of the current tag.
            $closing_html[$pos] = "";
          }   

          if (size $prev_tags <= $pos) {
            # mt:20050625
            # The current tag has more tiers than the previous tag.  To avoid array
            # ref errors when comparing the current tier to the previous one (which
            # is non-existent, of course) add empty string to $prev_tags.
            $prev_tags[$pos] = "";
          }

          # mt:20070503
          # Find out if this tier is an alias for a longer tag name
          var string longname = $tier;
          if ($tag_aliases_short{$tier}) {
            $longname = $tag_aliases_short{$tier};
          }

          # mt:20070503
          # Find out if this tier has a longer form tag later or earlier in the list
          var string parenttiers  = "";
          if ($pos > 0) {
            foreach var int i (0 .. ($pos - 1)) {
              $parenttiers  = $parenttiers + ($parenttiers == "" ? "" : $delimiter) + $tags[$i];
            }
          }
          var string realtagname = $parenttiers + ($parenttiers == "" ? "" : $delimiter) + $longname;
          var TagDetail realtag;
          if ($truetags{$realtagname}) {
            $realtag = $truetags{$realtagname};
          }
          else {
            $realtagname = "";
          }

          # mt:20070509
          # Add anchors to first and second level tiers and generate menu links
          var string anchor = "";
          $menulink = "";
          if (($pos == 0) or ($pos == 1)) {
            $anchor = """<a name="taganchor$delimiter$tags[0]""";
            $anchor =  ($pos == 1) ? $anchor + $delimiter + $tags[1] : $anchor;
            $anchor = $anchor + """"></a>""";

            if ($pos == 0) {
              $menulink = """<a href="#taganchor$delimiter$tags[0]">$longname</a>""";
            }
            elseif ($pos == 1) {
              $menuheader = $tags[0];
              if ($tag_aliases_short{$tags[0]}) {
                $menuheader = $tag_aliases_short{$tags[0]};
              }
              $menulink = """<a href="#taganchor$delimiter$tags[0]$delimiter$tags[1]">$longname</a>""";
            }
          } 

          # mt:20070503
          # If we're on a tag's last tier, or if this tier (plus parent tiers) maps to a longer form real tag 
          # we need to return a link to the tag, otherwise plain text is returned.
          if ((size $tags == ($pos + 1)) or (defined $realtag)) {
            # mt:20070503
            # Find out if this tag is the longer form tag of an alias (in which case we need to hide it, since
            # it will be displayed instead of the alias, and shouldn't be repeated).
            var bool hasalias = false;
            if ($tag_aliases{$tier}) {
              $hasalias = true;
            }
            if ($hasalias and (size $tags == ($pos + 1))) {
              $tier_code = "";              
            }
            elseif (defined $realtag) {
              $tier_code = """$anchor<a href="$realtag.url">$longname</a>""";
            }
            else {
              $tier_code = """$anchor<a href="$t.url">$longname</a>""";
            }

            if ($show_count and ($tier_code != "")) {
              var int c = $t.use_count;
              if (defined $realtag) {
                $c = $realtag.use_count;
              }
              $tier_code = $tier_code + """&nbsp;${pre_count}$c${post_count}""";
            }
          }
          else {
            $tier_code = "$anchor$longname";
          }

          # mt:20070503
          # If we've decided that this tag needs to be skipped, do nothing on this loop
          if ($tier_code != "") {

          # mt:20050625
          # $prev_tags stuffed with dummy empty string when it has fewer tiers than 
          # current tag.
          if ($prev_tags[$pos] == "") {     
            # mt:20050623
            # The current tag has more tiers than the previous tag, so a new
            # list must be opened.  
            if (($tag_list_pos == 0) and ($pos == 0)) {
              # mt:20061216
              # The outermost ul is supplied later so omit it from this stage.
              $list = $list + """<li class="module-list-item">$tier_code""";                  
              $closing_html[$pos] = "</li>";  
            }
            else {
              $list = $list + """<ul><li class="module-list-item">$tier_code""";                  
              $closing_html[$pos] = "</li></ul>";
            }

            # mt:20070509
            # Add this as a menu link at the top of the page
            if ($pos == 0) {
              $menuone = $menuone + (($menuone == "") ? "" : " | ") + $menulink;
            }
            elseif ($pos == 1) {
              $menutwo{$menuheader} = $menutwo{$menuheader} + (($menutwo{$menuheader} == "") ? "" : " | ") +  $menulink;
            }  
          }
          elseif (($tags[$pos] != $prev_tags[$pos]) or ($show_all_tiers)) {  
            if ($tags[$pos] != $prev_tags[$pos]) { 
              # mt:20050623
              # The current tag's tier is not the same as the previous tag's tier of  
              # the same level.  This means we may need to close some lists.
              var int i = size $closing_html;
              foreach var string html ($closing_html) {
                if ($i > $pos) {
                  $list = $list + $closing_html[$i];                                 
                  # mt:20050623: As we append the closing code, pop it off the array.
                  $closing_html[$i] = "";
                }
                $i--;
              }   
              # mt:20070507
              # If we just closed some lists, that means that any lower tiers in this tag need to 
              # be explicitly displayed, even if they match the same-level tier of the previous tag
              $show_all_tiers = true;                 
            } 

            if ($closing_html[$pos] == "") {          
              # mt:20050623
              # This is the first tier at this level, so open list.
              $list = $list + """<ul><li class="module-list-item">$tier_code""";
              $closing_html[$pos] = "</li></ul>";
            }
            else {              
              # mt:20050623
              # There have already been tiers added at this level, so just close the previous
              # list item before adding the new tier.
              $list = $list + """</li><li class="module-list-item">$tier_code""";
            }      
     
            # mt:20070509
            # Add this as a menu link at the top of the page
            if ($pos == 0) {
              $menuone = $menuone + (($menuone == "") ? "" : " | ") + $menulink;
            }
            elseif ($pos == 1) {
              $menutwo{$menuheader} = $menutwo{$menuheader} + (($menutwo{$menuheader} == "") ? "" : " | ") +  $menulink;
            }                   
          }
          else {
            # mt:20050623
            # The current tag's tier is exactly the same as the previous tag's tier at
            # this same level.  It has already been included in the list, so do nothing.
          }  
          }
          # mt:20050623: Moving on to next tier in this tag!
          $pos++;
        }
        $prev_tags = $tags;      
        $show_all_tiers = false;       
      }        
      # mt:20050623: Next tag in the list!
      $tag_list_pos++;
    }  

    # mt:20050623
    # All the tags have been added so close all outstanding lists.
    var int i = 0;
    var string remaining_html = "";
    foreach var string html ($closing_html) { 
      if ($html != "") {
        $remaining_html = $html + $remaining_html;
        $closing_html[$i] = "";
      }
      $i++;
    }
    $list = """<ul class="module-list">""" + $list + $remaining_html + "</ul>";

    # mt:20070510
    # Add bracketing commas to the secondary menu links
    if ($secondary_menus->ends_with(",") == false) { 
      $secondary_menus = $secondary_menus + ",";
    }
    if ($secondary_menus->starts_with(",") == false) {
      $secondary_menus = "," + $secondary_menus;
    }

    open_module("categories", $title, "");

    # mt:20070510
    # Print the primary menu links
    print ($menuone == "") ? "" : """<p class="topmenuone">[ $menuone ]</p>""";

    # mt:20070510
    # Print the secondary menu links
    foreach var string toplevel ($menutwo) {
      if ($toplevel != "") {
        if ($secondary_menus->contains("," + $toplevel + ",")) {
          print ($menutwo{$toplevel} == "") ? "" : """<p class="topmenutwo"><span class="topmenuheader">$toplevel</span> [ $menutwo{$toplevel} ]</p>""";
        }
      }
    }

    println $list;
    close_module();
  }
}

Step 3
Finally, add this function for the Tags Page, again altering the blue configuration variables:
function TagsPage::print_body() {

#####   Config   #####

  # Specify your delimiter.  One char only -- extra chars get truncated.
  var string delimiter = ":";

  # Do you want to show the tag use counts? Set to true or false.
  var bool show_count = true;

  # Specify the page title. Defaults to the core layer's value for
  # the Tags Page title. Change to your text, surrounded by quotes, eg:
  # var string page_title = "My Tags List";
  var string page_title = $*text_tags_page_header;

  # Which secondary menus do you want to show? Use long form names, not abbreviations.
  # Separate each one by a comma. Only include spaces if they are used in the tag itself.
  var string secondary_menus = "fanfiction,length";

##### End Config #####

  var Page p = $this;
  var string list = "";
  var string menuone = "";
  var string{} menutwo = {"" => ""};
  var TagAliases ta = new TagAliases;
  $ta->init();
  var string{} tag_aliases = $ta.tag_aliases;

  if (size $p->visible_tag_list() > 0) { 
    if ($delimiter->length() > 1) {
      $delimiter = $delimiter->substr(0, 1);
    } 

    # mt:20070501
    var string{} tag_aliases_short;
    # Reindex tag alias hash using the values as keys to make lookups easier
    foreach var string k ($tag_aliases) {
      var string new_key = $tag_aliases{$k};
      $tag_aliases_short{$new_key} = $k;
    } 

    # mt:20070502
    # Reindex the tags so that we can quickly look up which tiers are true tags, not just labels
    var TagDetail{} truetags;
    foreach var TagDetail t ($p->visible_tag_list()) {
      $truetags{$t.name} = $t;            
    }

    var string[] closing_html;
    var string[] prev_tags;
    var int tag_list_pos = 0;
    var string tier_code = "";
    $closing_html[0] = "";
    $prev_tags[0] = "";
    foreach var TagDetail t ($p->visible_tag_list()) {
      var string[] tags;
 
      if ($t.name) {  
        # mt:20050623
        # Split tags into array on delimiter. Oh god, my kingdom
        # for a function.  Stolen shamelessly from lj-user rane500.
        var int array_counter = 0;
        var string buffer = "";
        foreach var string char ($t.name) {
          if($char == $delimiter) {
            $tags[$array_counter] = $buffer;
            $array_counter = $array_counter + 1;
            $buffer = "";
          }
          else {
            $buffer = $buffer + $char;
          } 
        }  
        $tags[$array_counter] = $buffer;
  
        var int pos = 0;
        var bool show_all_tiers = false;
        var string menulink = "";
        var string menuheader = "";
        foreach var string tier($tags) {
          if (size $closing_html <= $pos) {
            # mt:20050623
            # $closing_html keeps track of html that is used to close off open
            # lists.  Its length must be kept >= to that of the current tag.
            $closing_html[$pos] = "";
          }   

          if (size $prev_tags <= $pos) {
            # mt:20050625
            # The current tag has more tiers than the previous tag.  To avoid array
            # ref errors when comparing the current tier to the previous one (which
            # is non-existent, of course) add empty string to $prev_tags.
            $prev_tags[$pos] = "";
          }

          # mt:20070503
          # Find out if this tier is an alias for a longer tag name
          var string longname = $tier;
          if ($tag_aliases_short{$tier}) {
            $longname = $tag_aliases_short{$tier};
          }

          # mt:20070503
          # Find out if this tier has a longer form tag later or earlier in the list
          var string parenttiers  = "";
          if ($pos > 0) {
            foreach var int i (0 .. ($pos - 1)) {
              $parenttiers  = $parenttiers + ($parenttiers == "" ? "" : $delimiter) + $tags[$i];
            }
          }
          var string realtagname = $parenttiers + ($parenttiers == "" ? "" : $delimiter) + $longname;
          var TagDetail realtag;
          if ($truetags{$realtagname}) {
            $realtag = $truetags{$realtagname};
          }
          else {
            $realtagname = "";
          }

          # mt:20070509
          # Add anchors to first and second level tiers and generate menu links
          var string anchor = "";
          $menulink = "";
          if (($pos == 0) or ($pos == 1)) {
            $anchor = """<a name="taganchor$delimiter$tags[0]""";
            $anchor =  ($pos == 1) ? $anchor + $delimiter + $tags[1] : $anchor;
            $anchor = $anchor + """"></a>""";

            if ($pos == 0) {
              $menulink = """<a href="#taganchor$delimiter$tags[0]">$longname</a>""";
            }
            elseif ($pos == 1) {
              $menuheader = $tags[0];
              if ($tag_aliases_short{$tags[0]}) {
                $menuheader = $tag_aliases_short{$tags[0]};
              }
              $menulink = """<a href="#taganchor$delimiter$tags[0]$delimiter$tags[1]">$longname</a>""";
            }
          }  

          # mt:20070503
          # If we're on a tag's last tier, or if this tier (plus parent tiers) maps to a longer form real tag 
          # we need to return a link to the tag, otherwise plain text is returned.
          if ((size $tags == ($pos + 1)) or (defined $realtag)) {
            # mt:20070503
            # Find out if this tag is the longer form tag of an alias (in which case we need to hide it, since
            # it will be displayed instead of the alias, and shouldn't be repeated).
            var bool hasalias = false;
            if ($tag_aliases{$tier}) {
              $hasalias = true;
            }
            if ($hasalias and (size $tags == ($pos + 1))) {
              $tier_code = "";              
            }
            elseif (defined $realtag) {
              $tier_code = """$anchor<a href="$realtag.url">$longname</a>""";
            }
            else {
              $tier_code = """$anchor<a href="$t.url">$longname</a>""";
            }

            if ($show_count and ($tier_code != "")) {
              var string uses = get_plural_phrase($t.use_count, "text_tag_uses");
              if (defined $realtag) {                
                $uses = get_plural_phrase($realtag.use_count, "text_tag_uses");
              }
              $tier_code = $tier_code + """ - $uses""";
            }
          }
          else {
            $tier_code = "$anchor$longname";
          }

          # mt:20070503
          # If we've decided that this tag needs to be skipped, do nothing on this loop
          if ($tier_code != "") {

          # mt:20050625
          # $prev_tags stuffed with dummy empty string when it has fewer tiers than 
          # current tag.
          if ($prev_tags[$pos] == "") {     
            # mt:20050623
            # The current tag has more tiers than the previous tag, so a new
            # list must be opened.  
            if (($tag_list_pos == 0) and ($pos == 0)) {
              # mt:20061216
              # The outermost ul is supplied later so omit it from this stage.
              $list = $list + """<li>$tier_code""";                  
              $closing_html[$pos] = "</li>";  
            }
            else {
              $list = $list + """<ul><li>$tier_code""";                  
              $closing_html[$pos] = "</li></ul>";
            }

            # mt:20070509
            # Add this as a menu link at the top of the page
            if ($pos == 0) {
              $menuone = $menuone + (($menuone == "") ? "" : " | ") + $menulink;
            }
            elseif ($pos == 1) {
              $menutwo{$menuheader} = $menutwo{$menuheader} + (($menutwo{$menuheader} == "") ? "" : " | ") +  $menulink;
            }  
          }
          elseif (($tags[$pos] != $prev_tags[$pos]) or ($show_all_tiers)) {   
            if ($tags[$pos] != $prev_tags[$pos]) {
              # mt:20050623
              # The current tag's tier is not the same as the previous tag's tier of  
              # the same level.  This means we may need to close some lists.
              var int i = size $closing_html;
              foreach var string html ($closing_html) {
                if ($i > $pos) {
                  $list = $list + $closing_html[$i];                                 
                  # mt:20050623: As we append the closing code, pop it off the array.
                  $closing_html[$i] = "";
                }
                $i--;
              }   
              # mt:20070507
              # If we just closed some lists, that means that any lower tiers in this tag need to 
              # be explicitly displayed, even if they match the same-level tier of the previous tag
              $show_all_tiers = true;   
            }                  
 
            if ($closing_html[$pos] == "") {          
              # mt:20050623
              # This is the first tier at this level, so open list.
              $list = $list + """<ul><li>$tier_code""";
              $closing_html[$pos] = "</li></ul>";
            }
            else {              
              # mt:20050623
              # There have already been tiers added at this level, so just close the previous
              # list item before adding the new tier.
              $list = $list + """</li><li>$tier_code""";
            }    
     
            # mt:20070509
            # Add this as a menu link at the top of the page
            if ($pos == 0) {
              $menuone = $menuone + (($menuone == "") ? "" : " | ") + $menulink;
            }
            elseif ($pos == 1) {
              $menutwo{$menuheader} = $menutwo{$menuheader} + (($menutwo{$menuheader} == "") ? "" : " | ") +  $menulink;
            }  
          }
          else {
            # mt:20050623
            # The current tag's tier is exactly the same as the previous tag's tier at
            # this same level.  It has already been included in the list, so do nothing.
          }  
          }
          # mt:20050623: Moving on to next tier in this tag!
          $pos++;
        }
        $prev_tags = $tags; 
        $show_all_tiers = false;      
      }        
      # mt:20050623: Next tag in the list!
      $tag_list_pos++;
    }  

    # mt:20050623
    # All the tags have been added so close all outstanding lists.
    var int i = 0;
    var string remaining_html = "";
    foreach var string html ($closing_html) { 
      if ($html != "") {
        $remaining_html = $html + $remaining_html;
        $closing_html[$i] = "";
      }
      $i++;
    }
    $list = $list + $remaining_html;
  }

  print """<div class="entry">""";
  print """<h3 class="entry-header">$page_title</h3><div class="entry-content"><div class="entry-body">""";
  print ($menuone == "") ? "" : """<p class="topmenuone">[ $menuone ]</p>""";

  if ($secondary_menus->ends_with(",") == false) { 
    $secondary_menus = $secondary_menus + ",";
  }
  if ($secondary_menus->starts_with(",") == false) {
    $secondary_menus = "," + $secondary_menus;
  }
  foreach var string toplevel ($menutwo) {
    if ($toplevel != "") {
      if ($secondary_menus->contains("," + $toplevel + ",")) {
        print ($menutwo{$toplevel} == "") ? "" : """<p class="topmenutwo"><span class="topmenuheader">$toplevel</span> [ $menutwo{$toplevel} ]</p>""";
      }
    }
  } 
  
  print """<ul class="ljtaglist">""";
  print $list;
  print "</ul>";
  print "</div></div></div>";
}
Tags: code:tagsbox:multi with abbreviations, layout:style contest
Subscribe

  • Post a new comment

    Error

    default userpic
    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 0 comments