jquery jQueryで文字数により表示幅を変える

2013年4月17日

コードなどを記述する pre 要素の overflow を auto にしている時、1行の文字数が多い場合マウスオーバーすると幅が自動的に広がるようにする。

このサイト(例)の場合、google-code-prettify を使ってコードの記述部分をシンタックスハイライトするようにしていて、行番号を表示する場合は、番号リスト(ol)で出力され、そうでない場合は、span 要素で出力されている。(「WordPressのショートコードでシンタックスハイライト」)

行番号を表示しない場合は、span 要素だけで出力されているため、各行を検出することができないので、行番号を表示しているものを対象とする。(何かいい方法が思いつかないので、取り合えずは全て行番号を表示するようにする。)

各行の幅は、当初は以下のように各行の文字数から幅を算出しようとしたが、半角や全角、空白やタブなどでの個々の幅を算出が困難なので変更。

$('#contents pre.prettyprint').hover(
     function() {    
       var that = $(this);
       var li$ = that.find('li');  //li 要素のラップ集合
       var maxCount = 0;
       li$.each(function() {  //各行の文字数をカウントし最大数を取得
        maxCount = Math.max(maxCount, $(this).text().length);
            }); 
       var prettyprint_maxwidth = maxCount * 10;  //最大文字数から行の幅を推測(かなりアバウト)
...

行番号を表示する場合は、番号リスト(ol)で出力され、各行(li 要素)はテキストの内容が、複数の span 要素で出力されている。

<div class="prettifydiv">
  <pre class="prettyprint linenums prettyprinted" style="">
    <ol class="linenums">
      <li class="L0">
      <li class="L1">
        <span class="pln">jQuery</span>
        <span class="pun">(</span>
        <span class="pln">document</span>
        <span class="pun">).</span>
        ...
      </li>
      <li class="L2">...</li>
      <li class="L3">...</li>
    </ol>
  </pre>
</div>

そこで、各行の幅はその行に含まれる各 span 要素の幅の合計として算出してその最大値を取得。

幅の最大値が基準の値(*)より大きい場合は、幅をjQuery のアニメーションメソッドを使用して拡大。

(*) pre 要素内の ol 要素などのマージンやパディングを考慮して決定。 pre 要素の幅の値よりは小さくなっている。

この例では、コードを記述してある pre 要素には「prettyprint」というクラスが指定してある。


jQuery(document).ready(function($) {
//シンタックスハイライト部分の幅の調整
var prettyprint_width = $(‘#contents pre.prettyprint’).width(); //シンタックスハイライト部分の幅
var expandWidth = 840; //拡大する際のシンタックスハイライト部分の幅の値
$(‘#contents pre.prettyprint’).hover(
function() {
var prettyprint_comparison_width = 590; //比較の基準とする幅(*)
var that = $(this);
var li$ = that.find(‘li’); //’li’要素のラップ集合
var maxWidth = 0; //各行の幅の最大値を初期化
li$.each(function() { //各行に含まれる’span’要素の幅を合計し、その最大値を取得する
var spanWidth = 0; //各’span’要素の幅の合計値を初期化
$(this).find(‘span’).each(function() {
spanWidth += $(this).width();
});
maxWidth = Math.max(maxWidth, spanWidth);
});
if(prettyprint_comparison_width < maxWidth) { //各行の幅の最大値が比較の基準とする幅の値より大きければexpandWidth(840)まで拡大 that.not(":animated").css({whiteSpace: 'pre-wrap', position: 'relative', zIndex: 10}).animate({width: expandWidth}, 100); }else{ return; } }, function() { if($(this).width() == expandWidth) { //シンタックスハイライト部分の幅が拡大されていれば元に戻す $(this).css({whiteSpace: 'pre'}).animate({width: prettyprint_width}, 100); } }); }); [/code] (追記:2013/7/7) Firefox の最新バージョン(22.0)になってから、マウスアウトする際に、今までは元の幅に自動的に戻っていたのに、戻らなくなった。他のブラウザ(IE, Chrome, Safari)では問題がない。 [code] function() { if($(this).width() == expandWidth) { //シンタックスハイライト部分の幅が拡大されていれば元に戻す $(this).css({whiteSpace: 'pre'}).animate({width: prettyprint_width}, 100); } }); [/code] の部分を以下のように変更(条件を削除)すると元の幅に自動的にもどるようになった。 [code] function() { $(this).css({whiteSpace: 'pre'}).animate({width: prettyprint_width}, 100); }); [/code] 関連情報:「jQuery で作成した機能が Firefox の最新バージョンで機能しない