GeSHi - Generic Syntax Highlighter を使うようにした。対応言語が多いことと、シンタックスファイルを増やし易いことがいい感じ。ただし時々 well-formed じゃないエラーがでることがあるっぽい。

  1. トップ
  2. prog
  3. ソースの色づけを復活 2
  1. トップ
  2. js
  3. ソースの色づけを復活 2
  1. トップ
  2. site
  3. ソースの色づけを復活 2
  1. トップ
  2. prog
  3. ソースの色づけを復活 2

toSource とかはじめて知った。

GreaseMonkey で設定値保存するときはこれ使うといいね! わざわざ JSON 云々のコピペなんてしなくてよさげ。

var foo = new Object;
foo.bar = "test";
foo.baz = "pqpq";
foo.toSource(); //=> '({bar:"test", baz:"pqpq"})'
(new Date).toSource(); //=> (new Date(1142625169156))
(function () { return ""}).toSource(); //=> '(function () { return "";})'
alert.toSource(); //=> 'function alert() {[native code]}'

ていうか、forEach とかあるのね! やべ。

var sum = 0;
[1, 2, 3].forEach(function (item, index, array) {
sum += item;
}, this); // 第二引数は callback 中の this
alert(sum);

同じように (Ruby -> JS) select -> filter, all -> every, map -> map, any -> some が使えるみたいだ。どうせ Fx 用の GM しか書かないから使いまくろう。

  1. トップ
  2. js
  3. .toSource(), forEach, etc

pre だけ色付けするようにした。

前に Pure JavaScript で色つけていたことがあったけど、あからさまにブラクラだった。で、なんとなく思いついたのでもっかい別の方法で実装してみた。

なんていうか非常にローテクといいますか他力本願な方法でして、PEAR::Text_Hightlighter に Ajax で丸投げというソリューションでございますです。

<?php
header("content-type: text/xml");
require_once 'Text/Highlighter.php';
require_once 'Text/Highlighter/Renderer/Html.php';
$options = array(
'numbers' => HL_NUMBERS_LI,
'tabsize' => 4,
);
$renderer =& new Text_Highlighter_Renderer_HTML($options);
$hl =& Text_Highlighter::factory($_GET["lang"]);
$hl->setRenderer($renderer);
$ret = $hl->highlight($_GET["source"]);
echo '<div xmlns="http://www.w3.org/1999/xhtml">';
echo $ret;
echo '</div>';
?>

こんなスクリプト書いたら、あとは JSpre 要素列挙して投げてあげる。レスポンスを importNode して、pre と置き換える。みたいな。

でもこんなクソ簡単なスクリプトなのに IE ではちゃんとうごかない。importNode がだめなのか、それとも responseXML から importNode ができないのか……謎。

あーHtml.php の &nbsp; は全部 &#160; に置き換えた。DTD がないからエラーになる。

  1. トップ
  2. js
  3. ソースの色づけを復活
  1. トップ
  2. site
  3. ソースの色づけを復活
  1. トップ
  2. prog
  3. ソースの色づけを復活

JS の XPath なんて書きましたけど、重大なバグがありまして、っていうかなんで気がつかなかったんだろう、えーそれは application/xhtml+xml なページ、すなわち XML として、名前空間をちゃんと扱うページではまともにセレクトできないんですよーははははー、例えばこのサイトとかね。

$X = function (exp, context) {
if (!context) context = document;
var resolver = function (prefix) {
var o = document.createNSResolver(context)(prefix);
return o ? o : (document.contentType == "text/html") ? "" : "http://www.w3.org/1999/xhtml";
}
var exp = document.createExpression(exp, resolver);
var result = exp.evaluate(context, XPathResult.ANY_TYPE, null);
switch (result.resultType) {
case XPathResult.STRING_TYPE : return result.stringValue;
case XPathResult.NUMBER_TYPE : return result.numberValue;
case XPathResult.BOOLEAN_TYPE: return result.booleanValue;
case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: {
result = exp.evaluate(context, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
var ret = [];
for (var i = 0, len = result.snapshotLength; i < len ; i++) {
ret.push(result.snapshotItem(i));
}
return ret;
}
}
return null;
}
alert($X("//x:p")); // Array of p elements
alert($X("count(//node())")); // => node number
alert($X("count(//x:body) = 1")); //=> must be true

かなり強引に修正してみた。

XPath で要素を指定するとき x という prefix (上のコードの場合は別になんでもいいんだけど、普通は x とか xhtml とかいうのをつける) を必ずつけるようにしとく。使い勝手が悪くなったけど、仕方ない。prefix がないときは resolver をよんでくれないみたいだ。

そう、で、resolver なんだけど、実はただの関数だった。evaluate は prefix を見つけると、resolver に prefix を渡し、URI を返すように要求する。resolver は prefix に対応する URI を返す。null の場合はエラー, "" の場合は、名前空間が null のものとして扱われるみたい (要追試)。

つまり、上のコードの resolver がやってることは、とりあえず普通の場合のように NSResolver を作って投げてみて、ダメだったら contentType にあわせて名前空間を返してやるっていう、かなり強引な (二回目) 方法なわけです。誰かもっと美しくして!

使い勝手が悪くなったけど と書いたけど、XSLT で使うような XPath と同じになった。まぁ名前空間を考慮するとこういうことになるっていう名前空間マジックなんだけど、やっぱり面倒くさいよなぁ。

$X("count(//x:body) = 1")$X("count(//*[local-name() = 'body' and namespace-uri() = "http://www.w3.org/1999/xhtml"]) = 1") みたいに書きたくはないし、HTML なページと XHTML ページとで、同じ XPath を使おうとするとこんなもんになってしまうような気もする。

冷静に考えると x より h のほうがいいや。

  1. トップ
  2. xpath
  3. XPath, $X function, NSResolver
  1. トップ
  2. js
  3. XPath, $X function, NSResolver