[ カテゴリー » 開発日誌 » JavaScript ]

pettieSyntaxの微調整とか

category-icon

 こんばんは、martinです。JavaScript単体で稼働するソースハイライト表示用のスクリプトpettieSyntax.jsですが、スタイルシートのクラス指定に対応したバージョン(pettieSyntax-class.js)も作成してみました。と、同時に正規表現の微調整をしています。一応、CSSソースのハイライトにも対応していますが、CSS3のセレクタLink とかは何でもありの状態なので、まぁ抜けがあったりするかも知れませんが、そこまで完璧を求めていないので。ちなみに、CSS3のセレクタは、具体例で挙げると以下のような感じです。

a[rel="external"] { /* REL属性がexternalなら外部アイコンの背景を付ける */
  padding-right: 5px;
  background: url(Images/external-icon.png) no-repeat right center;
 }
p[class~="foo"] { /* クラス名にfooが含まれていれば */
  margin: 0;
  padding: 0;
}
a[href$=".pdf"] { /* リンク名が.pdfで終わっていれば */
  background: url(Images/pdf.png) no-repeat right center;
}
a[hreflang|="en"] { /* リンク要素のhreflang属性がenで始まっていれば(enとかen-USとか) */
  background: url(Images/english.png) no-repeat right top;
}
div p:nth-child(2n+1) { /* DIVの子孫P要素で奇数番目のもの */
  background: ivory;
}

 別件ですが、JavaScriptライブラリのoParts.jsは、このCSS3のセレクタにも対応していて、例えば、

o('div:nth-child(2n+1)')

とすれば、奇数番目にあるDIV要素を一気に取得することが出来ます。お遊びですが、

<button onclick="o('ul li:nth-child(2n+1)').css('background:red');">
CLICK ME!
</button>

というコードを記述してみます。期待するのは、「UL要素の子孫のLI要素で奇数番目のやつの背景を赤にする」という動作です。

 syntax.jsの最新版とクラス対応版、およびそのCSSファイルを添付しておきます。ハイライト用のCSSファイルは、テーマのCSSファイルに追加しても良いでしょうし、以下のようにCSSファイルの中で呼び出すことも出来ます。

@import 'syntax.css';

 メンテナンスしやすいのは、上記のように別ファイルで用意しておくインポート方式でしょうか。

添付ファイル: syntax.jsattachedIcon  syntax-class.jsattachedIcon  syntax.cssattachedIcon 

 

— posted by martin at 09:37 pm   commentComment [0]  pingTrackBack [0]

pettieSyntaxがCSSに対応

category-icon

 ソースをJavaScriptでハイライト表示するpettieSyntaxLink ですが、CSSの表記にも対応しました。このせいでファイルサイズが3キロ弱になりましたが、まぁこの辺で落ち着くでしょう。

 色の指定をソースの上の方で、指定できるようにしてます。ソースを見ると、CSSの表記に対応した色指定だけ3色ありますが、これは1.タグ、2.CSSプロパティー(fontなど)、3.その実際の指定値 に対応しています。

var cssprops = ['indigo', 'slategray', 'indianred', /((?:[-#a-z0-9.,_* +:¥r¥n[¥]=]{2,}|[abipq*]))¥s*¥{¥s*[^}=]+?¥}/ig];

 実際のデモとして、このサイトのベーシックテーマに適用しているPREタグのCSS指定をば。

pre {
  font: 500 1em/1.4 "Consolas","Bitstream Vera Sans Mono","Lucida Console","Courier New",Verdana,Meiryo,monospace;
  background: #f6f6f9;
  border: double 4px #808080;
  border-width: 0 0 0 4px;
  margin: 1em auto;
  padding: 20px;
  width: 89%;
  height: 3em;
  color: #333;
  clear: both;
  white-space: pre;
  overflow-x: auto;
  letter-spacing: 0.1px;
}
body[id=weblog] pre { /* IE6以外のモダンなブラウザ用 */
  overflow: auto;
  height: auto;
}

 こんな感じです。仕様上、PHPやJavaScript用キーワードの中途半端な対応と違って、CSSのあらゆるプロパティーに対応してると思います。最新版を添付しておきます。

添付ファイル: syntax.jsattachedIcon 

 


— posted by martin at 05:34 pm   commentComment [6]  pingTrackBack [0]

ソースコード表示用の軽いスクリプト:pettieSyntax

category-icon

 こんにちは。たまにはアップデート以外の記事も書きたいので。

 前々から思っていたのですが、このブログではPHPとかJavaScriptのソースを提示することがままあります。現状、モノクロの味気ないソースコードだったので、PHPマニュアルのユーザーノートLink にあるようなカラフルな色付けにしたいなと思っていたわけです。この手のことを実現するには大きく2通りのアプローチがあって、サーバー側でハイライト表示の処理をして読み込ませる方法と、もうひとつはクライアント側のJavaScriptに解析させてその場でハイライト表示させる方法です。前者の例だと、PHPライブラリではGeSHi - Generic Syntax HighlighterLink などがあり、後者だとグーグルのgoogle-code-prettifyLink が有名でしょうか。

 でも、この手のやつって、これようのCSSファイルも用意しないといけないし、ファイルサイズはでかいし、設置が面倒そうだなと。なので書いてみました。基本的に、自分用なのでPHPとJavaScriptの一部の関数しかサポートしていませんが、まぁ、要は見栄えを良くすることが目的なので、すべてを網羅する必要はないと考えてます。PHPの組み込み関数なんて山ほどありますし。おかげで随分とサイズが小さいスクリプトになりましたが、それっぽく見えます。

 特徴としては、このスクリプト単体で動作可能ということです。他の見栄えのためのCSSファイルとかは必要ないです。記事の中のPREタグを見つけたら、その中身をハイライト表示します。初めは、PREタグに特定のクラス名を付けて、それを認識させようかと思っていましたが、そうすると過去の記事の書き換えをしないといけないし、どうせPREタグに書くのはソースコードぐらいだろうと割り切り、PREタグに絞りました。早速ですが、そのソースコードをこのスクリプトを使って表示してみます。

/*
 Lightweight syntax-analyzing script
 Copyright: modified BSD license 2008 martin
   version: 20080803.204553
*/

function pettieSyntax(){
 var cssprops = ['#c03', '#003366', '#636', /((?:[^{;_<]{2,}|[abipq*]))¥s*?¥{(¥s*[^}=_[¥]?<>]+?)¥}/ig];
 var etcetera = ['#c33', /( > | < )/g];
 var operants = ['green', /(¥/¥/¥-¥->|¥+¥+|¥-¥-|!?===?|<=|>=|=>|¥+=|¥-=|!=|&&|¥|¥|| = )/g];
 var variants = ['#669', /(¥$¥w+?¥b|var¥b¥w+¥b|@)/g];
 var htmltags = ['navy', /(<¥/¥w+?>|<¥w+|<¥?(?:xml|php)|(?:¥?|¥/)>|>)/g];
 var keywords = ['blue', /(¥b(?:alert|[Aa]rray|break|case|catch|class|charset|continue|Date|default|define|delete|do|else|false|FALSE|for|function|global|i[fn]|instanceof|new|null|Object|return|script|src|type|switch|this|throw|document¥S|TRUE|true|echo|try|typeof|var|void|while|window¥S|with|Location|version|encoding)¥b)/g];
 var decimals = ['#c69', /([¥s:¥/¥(,[+;."=>])(¥-?¥d+(?:¥.¥d+)?)(%|px|pt|em)?/g];
 var equipped = ['#036', /([¥.¥s(@>])([^'"¥(¥n=¥s<>¥/]+?)([¥( ])/g];
 var oneliner = ['#906', /('[^'¥r¥n]+?'|"[^"]*?"|<![^¥r¥n]+?¥-¥-.*?>)/g];
 var regulars = ['tomato', /([¥s(])(¥/[^¥r¥n]+?¥/)([igmy¥s¥);.])/g];
 var enoparts = ['indigo', /(¥b(?:o|oParts)¥b|¥.(?:away|moveTo|sizeTo|dimension|target)¥(¥)|¥.(?:loadScript|evt|metrics|start|css|view|each|sib))/g];
 var comments = ['#093', /([^:]|)((?:¥/¥/|#)¥s+[^'¥r¥n]+(?:¥r?¥n?|$)|¥/¥*[¥s¥S]+?¥*¥/)/g];
 var omitspan = function(m){ return m.replace(/<span[^>]*?>/ig, '').replace(/<¥/span>/ig, '');}
 var targets = document.getElementsByTagName('PRE');
 if(targets){
  for(var t, i = 0; t = targets[i++];){
   var c = t.innerHTML.replace(/<(?:span|code)[^>]*?>([^<]+?)<¥/(?:span|code)>/ig, '$1').replace(/¥t/g, '').replace(/'/g, ''').replace(/"/g, '"');
   if(/<(?:a |img )/i.test(c)) continue;
   c = c.replace(cssprops[3], function(A, B, C){ return /:/.test(C) ? '<span style=¥tcolor:'+cssprops[0]+'¥t>'+B+'</span>' + A.replace(B, '').replace(/([^:{]+?):([^;]+?);/g, '<span style=¥tcolor:'+cssprops[1]+'¥t>$1</span>:<span style=¥tcolor:'+cssprops[2]+'¥t>$2</span>;') : A;});
   c = c.replace(etcetera[1], '<span style=¥tcolor:'+etcetera[0]+'¥t>$1</span>');
   c = c.replace(operants[1], '<span style=¥tcolor:'+operants[0]+'¥t>$1</span>');
   c = c.replace(variants[1], '<span style=¥tcolor:'+variants[0]+'¥t>$1</span>');
   c = c.replace(htmltags[1], '<span style=¥tcolor:'+htmltags[0]+'¥t>$1</span>');
   c = c.replace(keywords[1], '<span style=¥tcolor:'+keywords[0]+';font-weight:bold¥t>$1</span>');
   c = c.replace(equipped[1], function (A, B, C, D){return B + '<span style=¥tcolor:'+equipped[0]+'¥t>' + C + '</span>' + D;});
   c = c.replace(enoparts[1], '<span style=¥tcolor:'+enoparts[0]+';font-weight:bold;¥t>$1</span>');
   c = c.replace(decimals[1], '$1<span style=¥tcolor:'+decimals[0]+'¥t>$2$3</span>');
   c = c.replace(regulars[1], function (A, B, C, D){return B + '<span style=¥tcolor:'+regulars[0]+'¥t>' + omitspan(C) + '</span>' + D;});
   c = c.replace(oneliner[1], function (A, B){return '<span style=¥tcolor:'+oneliner[0]+'¥t>' + omitspan(B) + '</span>';});
   c = c.replace(comments[1], function (A, B, C){return B + '<span style="color:'+comments[0]+'">' + omitspan(C) + '</span>';});
   c = c.replace(/¥t/g, '"');
   if(/*@cc_on!@*/false){
    t.outerHTML = '¥n<pre>' + c + '</pre>¥n'; /* IEの改行対策です */
   } else t.innerHTML = c;
  };
 }
};

 ファイルサイズは2キロ前後と小さいです。ppBlogで使うのであれば、とりあえずこのファイルをjsディレクトリにアップロードして、後は、lib.jsの最初の方で、このスクリプトを以下のように呼び出します。

oParts.loadScript('js/syntax.js');

次に同じlib.jsの下の方にある、oParts.start関数内で、このpettieSyntax()を呼び出せばOKです。

if(typeof pettieSyntax != UD) pettieSyntax();

 コードを見れば分かりますが、ハイライトの色はSPANタグ内でスタイルシート指定してますので、この部分を好きな色に変えれば良いです。あと、強調したいキーワードを追加したいときも、ソース内の該当箇所に追加していけばよいです。

 ppBlog使用前提なら、上のような設置になりますが、純粋に単体で動かしたい場合は、外部スクリプトとして、

<script type="text/javascript" src="path/to/syntax.js"></script>

みたく読み込ませて、ページ読み込み完了後にpettieSyntax()を呼べば良いです。

 まだろくに動作検証していないのですが、興味がある方はどうぞ。syntax.jsと、あと、ppBlogの設置例としてlib.jsを添付しておきます。

添付ファイル: syntax.jsattachedIcon  lib.jsattachedIcon 

 


— posted by martin at 01:12 pm   commentComment [1]  pingTrackBack [0]

ppBlogでのgetElementsByClassName

category-icon

こんばんは、martinです。ソーシャルブックマークへのリンクアイコンを各記事に付けるようにしました。近々配布予定の最新版に採用してます。またJavaScript関連の話をば。

 愛用しているタブブラウザFirefoxの現行バージョンは2ですが、バージョン3からはネイティブでdocument.getElementsByClassNameサポートされるLink ようです。現時点でこのメソッドをサポートしている主要なブラウザは存在しないので、document.getElementsByClassNameGでググれば分かるように、皆さん、色んなgetElementsByClassNameを書いています。ppBlogのJavaScriptのライブラリlib.jsでも、この関数(getByClass)は多用しているのですが、この関数は、ページ内のオブジェクトを逐一調べていくループ作業を伴うので、一般的に言って動作に時間がかかります。

 JavaScript使いの間では、常識かと思いますが、この手の操作で一番スピードが速いのは、XPathGを利用するやり方です。jQueryGで有名なJohn Resig氏のブログに、この手の関数のスピード比較記事があります。
 →http://ejohn.org/blog/getelementsbyclassname-speed-comparison/Link

 ネイティブサポートのFirefox3が無茶苦茶速いのは当然として、XPathもDOMを解析していく手法よりはずっと高速なのが分かります。IE6,7を除くモダンなブラウザは、このXPathをサポートしているので、ppBlogでもXPathを使うようにしました。以下のような感じです。

document.getElementsByClassName(className, pElement, tagName){
 var d = document, nodes = [], item;
 try { // XPathをサポートしているならこれを使う
  var xp = d.evaluate(
   './/'+(tagName || '*')+'[contains(concat(" ", @class, " "), " '+className+' ")]',
   (pElement || d), null, XPathResult.ANY_TYPE, null
  );
  for (item = xp.iterateNext(); item; item = xp.iterateNext()){
   nodes.push(item);
  }
 } catch(e){ // そうでなければ地道にDOM解析
  var cls, items = (pElement || d).getElementsByTagName((tagName || '*'));
  for(var i = 0, l = items.length; i < l; i++){
   item = items[i];
   if(item.className){
    cls = item.className.split(/¥s+/);
    for(var j = 0, k = cls.length; j < k; j++){
     if(cls[j]==className){
      nodes[nodes.length] = item; break;
     }
    }
   }
  }
 }
 return nodes.length > 0 ? nodes : null;
}

 John Resig氏のブログにあるのと同じ実験Link をしてみましたが(パクっただけ)、彼のサイトにある、Prototype.jsのXPathを使ったもの(xpath.htmlLink )と同等か少し速いくらいですね。

 当然ながら、XPathをサポートしていないIE6,7は、通常通りDOM解析をするアプローチしかないです。こちらの計測では、XPathを利用するより5倍ほど遅いです。

 ちなみに、1つ前のエントリで紹介したphotoeffect.jsも、この関数を使用しているので更新しました。ついでに添付しておきますね。このphotoeffect.jsは、単体で動くので、ppBlog以外の各種ブログでも外部ファイルとして呼び込むだけで簡単に使えます。要望があれば、詳しいクラス指定などの解説書きますんで、その時はたずねて下さい。

添付ファイル: photoeffect.jsattachedIcon 

 


— posted by martin at 01:22 am   commentComment [19]  pingTrackBack [0]

アップした写真をお洒落に見せるJavaScript

category-icon

 久しぶりのJavaScriptネタです。最近は、マック(MBP)で作業することも多いのですが、アップルの提供する.MacLink というサービスを使うと簡単に見栄えのよいホームページ(HP)を作成することが出来ます。このサービスはマックを使ってこそ活きるものですが。

 で、何種類ものHP向けのテンプレートが予め用意してあるんですが、多くのテンプレには、デジカメで撮った写真を単に貼り付けるだけでなくて、それらをちょこっと斜めにしたり切手風に縁取りしたり出来て、お洒落に演出できるわけです。自分も以前からこういうことをppBlogでしたいなぁとは思っていて、現状、写真っぽく見せたりドロップシャドウを付けたりというのはスタイルシートを使って出来るようにしています。後は、切手風とか写真を少し傾けて貼り付けるとかですが、これらはサーバーサイドのPHPプログラムで画像を加工すれば可能なんだけど、写真をアップする際の手間が増えるのは好ましくないし、何よりプログラムを書かないといけない。

 画像の回転(写真を傾けて貼り付けたいので)なんて、クライアント側のJavaScriptで出来れば楽チンだけど無理だよなぁと思っていたんだけど、実は<canvas>Link を使えば簡単に出来ちゃうんですね。しかも画像同士を合わせることも簡単に出来る。これなら自分がやりたいことはJavaScriptで出来るじゃないか、ということで書いてみました。

WinterLeaves
Vistaに最初から付いてるサンプル写真

 これは通常の、ppBlogでデフォルトで出来ることです。つまり写真のように白枠を付けて、ドロップシャドウを付けて、ということですが、さすがに写真をちょいと傾けるとかは出来ません。ところが、これに、canvasを利用したJavaScriptをかますと以下のようになります。

WinterLeaves
photoeffect.jsを反映させたやつ-写真風

 この写真は上の写真と同じ画像ファイルを指定していますが、見栄えが随分と違ってます。しかもこれをJavaScriptでやっているわけで、canvas恐るべしですね。反対向きの傾きにしたらこんな感じです。

WinterLeaves
photoeffect.jsを反映させたやつ-写真風

 これは写真風のフレーム画像を合わせてますが、切手風のフレームを合わせたのが以下です。

WinterLeaves
photoeffect.jsを反映させたやつ-切手風

 てな感じです。どちらに傾けるかとか(傾けないというのもあります)、写真風か切手風かというフレームの選択は、何れもIMGタグの中でクラス指定をすることで実現します。

 ほかにいくつかデモを並べてみます。

TocoToucan

FrangipaniFlowers

OryxAntelope

Dock

Garden

 ちなみに、IE(インターネットエクスプローラー)はcanvasをサポートしていないので、こちらはVMLGを利用して同様の効果を見せるようにしています。こちらで動作が確認できたブラウザは、ウィンドウズではIE7, Firefox2.0でマックではSafariとFirefoxです。OperaやIE6以下は未確認です。

 一応、このスプリプトは外部読み込み形式で作動するようにしています。ppBlogであれば、各テーマのテンプレートHTMLファイルに、外部スクリプトを呼び込む要領で、

<script type="text/javascript" src="js/photoeffect.js"></script>

と記述して、あとはlib.jsDOM.onloadの最後の行にでも、

if(typeof photoEffect != 'undefined'){
 photoEffect.init();
}

と書いておけば動きます。あ、あと2種類のフレーム用の画像はトップページのImagesディレクトリにアップしておく必要があります。クラス名の指定ですが、IMGタグでのクラス指定で photo-effect が指定されていれば、それを認識して、このスクリプトが発動します。このスクリプトと画像ファイルを添付しておきます。まだ作りたてなので細かいところは見ていませんが興味ある方はどうぞ。

[Update:2007/10/8 17:31:18]

 傾きの角度は、自由に指定出来るようにしました。クラス名で photo-angle3photo-angle-3 みたいに指定します。数字は-360度から360度まで。マイナスの値なら、右肩上がり、正の値なら左肩上がりです。

 あ、ついでにppBlogユーザー向けも。これは、Firefoxに対するマウスオーバーチップ処理を追加しています。


— posted by martin at 04:35 am   commentComment [12]  pingTrackBack [3]

T: Y: ALL: Online:
Created in 0.0095 sec.
prev
2024.4
next
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30