2005年 11月 04日

動的補完 in textarea

textarea で動く劣化コピー xml-mode 続き。

TAB 入力時動的補完リストを表示させてみる。たいして意味がない気がする。xyzzy の dabbrev に相当。

デフォルトの内容で j[TAB] とすると ja, javascript, js が候補にあがる。Down/Up で選択してもう一度 TAB を押すと補完される。

「動的」なので、適当に vfsgergfherkgr とか入力したあと、vfs[TAB] とかやれば補完される。

似非 xml-mode じゃホント意味ないなぁ。っていうかほんとはタグの予測補完をやろうと思ったんだけどめんどくてやめたんです。動的補完のが簡単だけどソレなりの面白さはあるかなと。

関係ないところでは C-x h を入力したときキーバインド一覧をだすようにしてみた。微妙。

直前に動的補完できそうな文字がない場合は、親要素に合わせて開始タグ候補をリストするようにしてみた。

xml.complementList = {
"head" : ['<meta name="" content=""/>', '<link rel="" href=""/>'],
"body" : ['<div class="section"', "<p>", "<address>"],
"div"  : ['<div class="section"', "<p>"],
"p"    : ['<abbr title', "<span class"],
"ul"   : ["<li>"],
"ol"   : ["<li>"],
"dl"   : ["<dt>", "<dd>"]
"pre"  : ["<![CDATA["]
};

似非 xml-mode in textarea

制限つきながら、IE でも動くように。閉じタグ補完とかだけ。

Ajax による Full IME のコードをパクっています。

keypress 時のコードがうまくかければもうちょい使えるだろうけど、いかんせん IE はデバッグしにくいのでやる気起きない。Opera も。

Bloglines sanitize <script>alert("unco");</script>

なんか Bloglines が title を sanitize しない気が。。。

title に &lt;textarea&gt; って書いたやつ (すなわちタグじゃなく実態参照) からバグって表示される。なんですか。いぢめ食らってますか僕。

script じゃダメっぽいな。textarea だけか。

で、いつリダイレクトのほうの URL に書き換わるんだろう。

2005年 11月 03日

キーバインドの実装

textarea で動く劣化コピー xml-mode の入力まわりを整理して分離してみた。C-x i とかいうツーストローク以上のキーバインドも可能に。ただ、やっぱり文字入力をキャンセルさせる方法がわからないため、入力された文字をあとから削除する方法になってる。チラつく。

これである程度自由にキーバインドが変えられるようになった。

function xmlText_initialize() {
var xml = new xmlText(document.getElementById("xmltext"));
var kb = new keyBinding(document.getElementById("xmltext"), {
"C-x i" : function () { xml.indentLine() },
"TAB"   : function () { xml.indentLine() },
"C-q"   : function () { xml.indentBuffer() },
"C-."   : function () { xml.wellClose() },
"/"     : function () { xml.slash() },
"="     : function () { xml.equal() },
"RET"   : function () { xml.newLineAndIndent() }
});
}
window.addEventListener("load", xmlText_initialize, true);

劣化コピー xml-mode と一緒に使うとき、キャレット位置が若干混乱するのが微妙。なんで混乱するのかよくわからないのだけれど。

textarea のスクロール位置をセットしなおす方法が分からん。使えないって!

event.preventDefault() を使えばキャンセルできるみたいだ。書き換えよう。

あー、しかもブラウザのキーバインド横取りできる。

スクロール問題解決?

Ctrl+記号を入力すると文字が誤認される。

2005年 11月 01日

xml-mode in textarea

textarea で動く劣化コピー xml-mode

まだまだバグがあるんだけど、ぶっちゃけ微妙に飽きてきたので公開 (してモチベーションあげる作戦)。Firefox でしか確認してない。IE では絶対動かないだろう。Opera でもたぶん動かないだろう。問題なのは setSelectionRange, selectionStart。綺麗にクロスブラウザ化するスクリプトをどっかで見たけどまぁいいや。

keydown/keyup は shift とかを単体で押しても反応しやがるので困った。keypress はイベント発生時点で、まだ textarea.value に文字が入力されないのが困った。かなりキモイ方法で解決したけど、スマートなのは keypress 単体を使って、文字入力をキャンセルする方法かなぁ。できなかったけど。

キャレット位置がおかしいバグがなおせたらそこそこ実用になるかな。

dump() しまくってるので Fx のコンソール表示させてると楽しいですよ。なにがだよ?

TAB 以外の文字でのインデントは一切考えていません。必要性を感じませんから。

  • 属性に / を書こうとすると空要素タグ補完されてうざい。文字列の中にいるか外にいるか調べられればいいんだけどうまくいかない。タグの中の "[^"]*" をスキャンするとかなんとか。
  • たまに補完後のキャレットの位置がおかしい。原因・再現性不明
  • CDATA を見事に無視してインデントする。そんなに難しくないと思うけど、面倒くさいと思う。大して使わないのでどうでもいいちゃどうでもいい。
  • <empty-tag /></close-tag> みたいなときインデント崩れる。原因は空要素タグを最初から無視しているせいなんだけど、これ修正するのはめんどい。
  • 一通り実装終わり。CDATA のインデント無視も動いてるっぽい。俺的に汚いソースを書くとインデントが崩れる素晴らしい仕様に(わらい
  • 2005年 10月 20日

    site-script.js の整理

    とりあえず似非 require を使うことに。ミニ JSAN みたいな実装にしといた。変数のリストを取得できないからこれ以外方法がなさげ。まぁ必要なオブジェクトを明示できるから悪いとはいえないんだけど。

    function require(__path, __exports) {
    if (!__exports) __exports = [];
    var __code = (require.LOADED_FEATURES[__path]) ? require.LOADED_FEATURES[__path] : HTTP.get(__path);
    (function () {
    with (Global) {
    eval(__code);
    }
    for (var __i = 0, __len = __exports.length; __i < __len; __i++) {
    Global[__exports[__i]] = eval(__exports[__i]);
    }
    })();
    require.LOADED_FEATURES[__path] = __code;
    return true;
    }
    require.LOADED_FEATURES = {};
    require("/ruby.js");
    require("/xb.js",   ["document_addEventListener", "document_removeEventListener"]);
    require("/dom.js",  ["getElementsByAttribute", "getElementsByClassName"]);
    require("/mm.js",   ["MetadataManipulator"]);
    require("/code.js", ["markupCode"]);
    require("/util.js", ["MessageArea", "ProgressBar", "AccessibilityOption"]);
    

    余計なことをしても使わないので、できるだけ短くすることにした。"Obj.prop" みたいなのも渡せるようにしたやつも書いてみたけど思ったより長くなったので却下した。

    HTTP.get とか書いてるけどこれより前にそういうのを書いてある。

    さっき気付いたんだけど IE で表示崩れるよね。なんか直す気力がないから放置するよ。別に読めないわけじゃないし。それにともなって MM のテストをいったん廃止

    2005年 10月 19日

    Javascript で require もどき・eval の実行コンテキスト

    Javascript はファイル間の依存関係を一切書けない。ロードする順番は結局 script 要素の出現順、つまり HTML 依存。どう考えても気持ち悪い。のでどうにかして require もどきを作りたい。

    function createXMLHttpRequest() {
    return this.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
    }
    var __LOADED_FEATURES = {};
    var Global = this; // this == window == Global
    function require(lib) {
    if (__LOADED_FEATURES[lib]) return false;
    var req = createXMLHttpRequest();
    req.open("GET", lib, false); // 同期
    req.send(null);
    if (req.status == 200) {
    // IE ではグローバルコンテキストで実行してくれない。
    Global.eval(req.responseText);
    __LOADED_FEATURES[lib] = true;
    } else {
    throw Error("Load Error");
    }
    return true;
    }
    require("/ruby.js");
    require("/mm.js");
    

    Global という名前のオブジェクトが宣言されてなかったりするので強調をこめて宣言してある。それ以上の意味はないです。window.eval でも問題なし。見たとおり XMLHttpRequest を使って取得し、eval させてみる。

    これは Firefox 1.0.7と Opera 8 ではうまくいくけど、IE 6 ではうまくいかない。

    IE の場合 eval する部分のコンテキストが変わってくれない。つまり mm.js に var MottoMottoMeidosan = function () { .. } とかいう宣言があったとき、require 関数の変数オブジェクトに代入されやがるので、require のあとに new MottoMottoMeidosan() とか書くと「そんな変数宣言されてません」と怒られる。

    解決法なんですが、さっぱりわかりません。誰か助けて。

    なんだったら .php にでもして include() でもいいんだろうけど、これは完全に負けだよね(謎

    卑怯な解決方法1を発見した。

    eval(req.responseText.replace(/^var/g, ""));

    インデント依存っていうか副作用がどれだけあるか不明すぎ。

    JSAN つかえよバーカ。

    JSAN はそもそもグローバルスコープで eval することなんて考えてない。指定したオブジェクトだけグローバルスコープに登録してる。つまり基本的に一個のファイルで一つの固まりしかロードできない。use は必要なのをグローバルスコープに登録するらしい。 DOM 定数とかをグローバルスコープに登録するなら全部 use/export の引数に書けってことなのか?

    なんか素晴らしすぎて使いづらいなぁ。特定ファイルを単純にロードしたい。とくにディレクトリ構造を要求するのがなんともいえない。

    疑問なんだけど JSAN は 291 行ものコードを最初から書いておけっていうだろうか?

    script 要素二つ書けっていうんだったら目的が違うな。モジュールシステムが欲しいんじゃないし。

    続きを書いた。

    2005年 10月 18日

    Ruby's eash on ECMAScript

    ECMAScript でイテレータ なんてのを書いたことがあったけど、これ、each の中で break ができないのでちょっと気持ち悪い。ちまたで時々聞く ruby.js はどうやって解決しているんだろう?って思ってみてみたけど、特に何もしてなかった。つーか ruby.js 見つけるのが割りとめんどかったよ。

    いろいろ考えたけどとりあえず動いたのをメモっとく。

    function Array_each(func) {
    try {
    var context = {
    escape : function () {
    throw "break";
    }
    }
    for (var i = 0, len = this.length; i < len; i++) {
    func.apply(context, [this[i]]);
    }
    } catch (e) {
    if (e != "break") throw e;
    }
    return this;
    }
    Array.prototype.each = Array_each;
    [1, 2, 3].each(function (i) {
    if (i > 1) this.escape();
    Debug.dump(this);
    });
    

    Function.prototype.apply() の第一引数は関数の中での this なのでそれにメソッド設定してみる。ループから抜けるのに try - catch。投げるオブジェクトは "break" という文字列。"break" 以外の場合は例外を投げなおす。

    ほんとはコンテキストの変数オブジェクトに直接関数を突っ込めるのがいいんだけど、ECMAScript では変数オブジェクトにアクセス方法はない (Activation オブジェクトは変数の実体化を目的とした変数オブジェクトとして使用される。Activation オブジェクトは純粋に仕様のメカニズムである。 Activation オブジェクトへのアクセスは ECMAScript プログラムには不可能である。 メンバ (変数) にはもちろんアクセスできるから eval つかえばいいけどスマートとは思えない。) のでこんな感じ。Global (window) は使いたくないし……

    あとは eval(func.toString().replace(/\{/, "\{ var escape = function () { .. };")) とか?

    2005年 10月 08日

    for の括弧の中での演算子

    俺は演算子の前後にスペースを入れない書き方が大嫌いなんだけど、for の括弧の中では例外的にスペースを入れないようにしていた時期があった。なんとなくまとまりのあるほうがいいかなぁって思っていたから。

    でも最近 Javascript で var をちゃんと使うようにしてからはその変則的なルールをやめた。

    for (var i=0; i<100; i++)
    alert("pgr");
    for (var i = 0; i < 100; i++)
    alert("pgr");

    var の後にはスペースがもちろん必須なわけで、そのあとに続く部分でスペースを空けないと var だけが浮いてしまう感じに見える。気持ち悪いのでスペースをあけるようにした。var とかない C でもスペースをあける。ほとんど同じ文法なのにスペースあける場所が違うとかは論外だからね。

    2005年 10月 03日

    CSS をテーマにするのはいいけれど @tDiary

    構造が気持ち悪い。とりあえず tDiary の話。はてなにも言えるけどはてなはソースを変えられない時点で「諦め」があるので論外。

    tDiary には CSS によるテーマ機能があって、(たぶん) それがウリなんだろうけど、そのせいで構造が変えにくい。「変えにくい」ってのはテーマを使いたいからでなく、スキンファイル (構造を決定するファイルってことにしてください。CSS は含みません。) が難読になっていたり、プラグインの吐くソースがキモかったりする。「どうせテーマを使ってもらうんだから構造は決めうち。スキンファイルは開発側が編集できればいいや」みたいな。

    俺が tDiary を使っていたとき、そういう気に入らない構造の部分をざっくり修正して使っていたんだけど、バージョンアップしようと思ったときに死んだ。そしていろいろあって tDiary を使うのをやめた。使うのはやめたけど ML は読んでる。なんとなく。

    少し前に「form 要素直下に input 置くと validator に怒られるので div で囲う」みたいなメールが流れてた。あはははって感じ。

    誰もが納得できる構造にするのが一番いいんだけどそれは難しい。だから、スキンファイルをシンプルに。変なソースがあってもユーザが修正できるように。スキンファイルを編集しても別なところでエラーがでないように。バージョンアップのときにスキンファイルを変えなくてもいいように。

    ちなみに「誰もが納得できる構造」であれば CSS によるテーマってのはすごく素敵なもんなんだよなぁ。というかおかしいんだよ。「誰もが納得できる構造」って何なんだ。

    まぁでも、こんないちいちキモイ構造がどうとかいうのは strict ヲタクぐらいなもんだろう。

    そもそもカテゴリが違うといえど blosxom はよろしいな。構造?なにソレ?ていうかボク HTML なんて知らないよ、みたいな。バージョンアップしねぇじゃんとかは禁句らしい。

    放任したほうが楽ちん。やりたい人は tDiary 互換フレーバーとかあるしなぁ。よくわからんセクションになってるのは俺の頭が悪いうえに今眠いからです。