Search code examples
jquerytruncation

Truncate list of breadcrumbs - and keep the markup


I have this script which truncates long lists which is really useful for long breadcrumbs. However, the result is rendered as a list of atags only.

How can the script be changed to output li list items - like the original markup?

<ul class="breadcrumbs">
  <li>You are here: </li>
  <li><a href="#">Item</a></li>
  <li><a href="#">Long item</a></li>
  <li><a href="#">Long item</a></li>
  <li><a href="#">Really long item</a></li>
  <li><a href="#">Really, really long item</a></li>
  <li><a href="#">Long item</a></li>
  <li class="active">Active page</li>
</ul>

Script:

 /* Truncate breadcrumbs when over a certain number of levels, and remove link from current page.
     *
     * Options:
     *      intro           {String}    Introductory text, may include markup
     *      separator       {String}    Separating character(s)
     *      maxLevels       {Number}    Integer of maximum levels to show without truncation
     *      startCrumbs     {Number}    Integer of levels to show before the truncated levels
     *      endCrumbs       {Number}    Integer of levels to show after the truncated levels
     *      crumbMaxLength  {Number}    Maximum character length for breadcrumb titles to show without truncation
     */

    $.fn.breadcrumbs = function(options) {
      var el = $(this);

      // truncate individual titles if over set length
      $('a', el).each(function() {
        var crumbTitle = $(this).text();
        if (crumbTitle.length > options.crumbMaxLength) {
          $(this).text(
            $.trim(crumbTitle).substring(0, 40).split(" ").slice(0, -1).join(" ") + "…"
          );
        }
      });

      // remove the link from the current page crumb
      $('.active', el).replaceWith(
        $('<span/>').text($('.active', el).text())
      );

      var crumbs = $.map($('a, span', el).toArray(), function(x) {
        return x.outerHTML;
      });

      // if truncation needed
      if (crumbs.length > options.maxLevels) {
        var firstCrumbs = crumbs.slice(0, options.startCrumbs);
        var hideCrumbs = '<a href="#" title="Show all">…</a>';
        var lastCrumbs = crumbs.slice(crumbs.length - options.endCrumbs);
        var newCrumbs = firstCrumbs.concat([hideCrumbs]).concat(lastCrumbs);
        el.html(options.intro + newCrumbs.join(options.separator));
      } else {
        el.html(options.intro + crumbs.join(options.separator));
      }

      // show the hidden breadcrumbs when ellipsis is clicked
      $('[title]', el).click(function() {
        el.html(options.intro + crumbs.join(options.separator));
      });
    };

    // breadcrumb truncation settings
    $('.breadcrumbs').breadcrumbs({
      intro: '<li>Your are here: </li>',
      separator: ' > ',
      maxLevels: 5,
      startCrumbs: 1,
      endCrumbs: 2,
      crumbMaxLength: 40
    });

Fiddle here.


Solution

  • I have updated your breadcrumb function to have another option called wrapWithLi. If passed in option and is true, it will wrap your breadcrumb with li otherwise with a.

    /* Truncate breadcrumbs when over a certain number of levels, and remove link from current page.
         *
         * Options:
         *      intro           {String}    Introductory text, may include markup
         *      separator       {String}    Separating character(s)
         *      maxLevels       {Number}    Integer of maximum levels to show without truncation
         *      startCrumbs     {Number}    Integer of levels to show before the truncated levels
         *      wrapWithLi      {boolean}    wrap element with li. if false or not passed defaults to 'a'
         *      endCrumbs       {Number}    Integer of levels to show after the truncated levels
         *      crumbMaxLength  {Number}    Maximum character length for breadcrumb titles to show without truncation
         */
    
    $.fn.breadcrumbs = function(options) {
      var el = $(this);
    
      var wrap = options.wrapWithLi === true ? 'li' : 'a';
    
      // truncate individual titles if over set length
      $(wrap, el).each(function() {
        var crumbTitle = $(this).text();
        if (crumbTitle.length > options.crumbMaxLength) {
          $(this).text(
            $.trim(crumbTitle).substring(0, 40).split(" ").slice(0, -1).join(" ") + "…"
          );
        }
      });
    
      // remove the link from the current page crumb
      $('.active', el).replaceWith(
        $('<span/>').text($('.active', el).text())
      );
    
      var crumbs = $.map($(wrap + ', span', el).toArray(), function(x) {
        return x.outerHTML;
      });
    
      // if truncation needed
      if (crumbs.length > options.maxLevels) {
        var firstCrumbs = crumbs.slice(0, options.startCrumbs);
        var hideCrumbs = '<a href="#" title="Show all">…</a>';
    
        if (wrap === 'li') {
            hideCrumbs = '<li>'+ hideCrumbs +'</li>';
        }
    
        var lastCrumbs = crumbs.slice(crumbs.length - options.endCrumbs);
        var newCrumbs = firstCrumbs.concat([hideCrumbs]).concat(lastCrumbs);
        el.html(options.intro + newCrumbs.join(options.separator));
      } else {
        el.html(options.intro + crumbs.join(options.separator));
      }
    
      // show the hidden breadcrumbs when ellipsis is clicked
      $('[title]', el).click(function() {
        el.html(options.intro + crumbs.join(options.separator));
      });
    };
    
    // breadcrumb truncation settings
    $('.breadcrumbs').breadcrumbs({
      intro: '<li>Your are here: </li>',
      separator: ' > ',
      maxLevels: 5,
      startCrumbs: 1,
      wrapWithLi: true,
      endCrumbs: 2,
      crumbMaxLength: 40
    });
    

    Here is working jsfiddle