3
\$\begingroup\$

I created a function that rewrites file names according to the available space on screen:

@{
  var index = 0;
  foreach (var item in Model)
  {
  <div class="gallery-item">
    <a href="@item.Uri" title="Click to open file" target="_blank" style="display:block; width: 100%;">          
        var id = "filename_" + ++index;
        @Html.SpanFor(i => item.FileName, new { id = id, title = item.FileName, style = "white-space: nowrap;" })          
    </a>
  </div>
  }
}

@section Scripts
{
  <script type="text/javascript">
    function adaptWidth(span) {
      var span = $(span);
      var origfilename = span.text();
      var ext = origfilename.split('.').pop();
      var filename = origfilename.substr(0, origfilename.length - ext.length - 1);
      var text = origfilename;

      while (span.outerWidth() > span.parent().innerWidth()) {
        span.text(text = (filename = filename.substr(0, filename.length - 4) + '...') + ext);
      }
    }

    $(document).ready(function () {
      $('span[id^=filename_]').each(function (i) { adaptWidth(this) });
    });
  </script>
}

Here are the results before and after running script:

Before:

enter image description here

After:

enter image description here

The function runs quite fast for now, but should I be worried from future impact? Any other suggestion or alternatives? Optimization?

I thought about splitting it to 3 spans, 1 for filename, second for ..., and 3rd for the extension, but I don't really know how to make the overflow of the first be hidden under the other two. Besides, if a truncation isn't required, it's gonna look weird.

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

Here are a couple tweeks for your code. I integrated @eicto's suggestion, which is the first step in applying an interpolated search.

var $spans = $('span'),
    parentWidth = $spans.first().parent().innerWidth();

$spans.each(function () { 
    adaptWidth(this, parentWidth);
});

function adaptWidth(elm, maxW) {

    // make a var `$elm` so know it's a jQuery object
   var $elm = $(elm),
        // use `lastIndexOf()` to split the filename and
        // extension halves instead of splitting into an array
        fullname = $elm.text(),
        idx = $elm.text().lastIndexOf('.'),
        name = fullname.substr(0, idx),
        ext = fullname.substr(idx),
        // factor is the ratio of the space available for
        // the text vs the space it currently takes up
        factor = maxW / $elm.outerWidth(),
        // idx is a first guess at where the cutoff will be
        idx = (fullname.length+4) * factor;

    idx = Math.round(idx);

    while ($elm.outerWidth() > maxW) {
        name = name.substr(0, --idx);
        $elm.text(name + '...' + ext);
    }
}

The jsFiddle i was testing with.

Edit:

A few edits in the text and, per a comment from the OP, updated the code to determine the max-width only once.

As a side-note, apparently this type of search is called an interpolation-sequential search.

\$\endgroup\$
2
  • \$\begingroup\$ Since the tiles are shared width, I will check its size only once. Answer updated. \$\endgroup\$ Dec 27, 2012 at 12:05
  • \$\begingroup\$ @Shimmy Good to know. I don't see your edit so I added the change. \$\endgroup\$
    – tiffon
    Dec 28, 2012 at 7:39
4
\$\begingroup\$

In general case I would to get text_width and container_width, then calculate new_string_length=container_width/text_width*length, than setup increase or decrease text, depending on result_text_width > container_width and do the loop like yours.

This is really needed only if strings have a very big size.

\$\endgroup\$
3
  • \$\begingroup\$ 1) It's for filenames, how long can a filename be? I guess not too long. 2) I'm affraid you missed out the whole point, the reason I needed this function is because the font is not a fixed-width one, the width varies between the various characters in it. \$\endgroup\$ Dec 25, 2012 at 3:20
  • \$\begingroup\$ 2) not i not missed, I just think that change length before loop will decrease interations. \$\endgroup\$
    – zb'
    Dec 25, 2012 at 3:21
  • 1
    \$\begingroup\$ fyi in xfs max filename size is 255 bytes, not sure if it big or not, depend how often you plan call such function \$\endgroup\$
    – zb'
    Dec 25, 2012 at 3:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.