a要素でのitemprop属性

Posted
on
in

Microdataではitemprop属性を指定された要素からどうやって値を選択するか厳密に決められていて、それに外れた書き方はできない。metatimeimg要素の場合はまぁそうなるよねみたいな感じなんだけど、a要素だけがちょっと。

仕様では、a要素でitemprop属性を使った場合その値はhref属性の値を絶対URLに変換したものとなっている。そのため以下のようには書けない。

<address itemscope
  itemtype="http://schema.org/Person">
  Copyright &copy; 2012
  <a href="http://example.com/about/"
    itemprop="name url">
    John Doe
  </a>
</address>

MicroformatshCardのような感覚では書けないということで、以下のようにspan要素(など)を使って別にしないといけない。

<address itemscope
  itemtype="http://schema.org/Person">
  Copyright &copy; 2012
  <a href="http://example.com/about/"
    itemprop="url">
    <span itemprop="name">
      John Doe
    </span>
  </a>
</address>

ボキャブラリーごとに対応しなくても良いようにHTMLの要素側で値の選択法を決定させているのだと思う。ボキャブラリー側でデータ型を決めてそれによって値の選択法を変えるというのだと、処理系でボキャブラリーをちゃんと処理しなければ正確なデータの抽出が行えない。HTML要素で値の選択法が決定されるMicrodataの実装ではデータの抽出自体はボキャブラリーを処理せずに行えることになる。HTMLがマークアップ言語なこともあって理にかなっている実装なんじゃないか(と今は思う)。


このWebサイトはまだ直してない……けど今から直す。

Vimスクリプト用Google Code Prettifyの言語ハンドラー

Posted
on
in

重い腰を上げてGoogle Code PrettifyVimスクリプトのコードを構文強調できるようにする言語ハンドラーを書いた。あんまり頑張らないので、コメントとクオート文字列、Expression evaluationにあるコマンドをキーワードとして強調くらい。

View Demo: Test page for lang-vim.js

注意としてはendiとかfuとかコマンドの省略形がハイライトされないこと。あんまり追加する気はない。.vimrc向けにsetautocmdmap系あたりは追加しても良いかも。

追記

set等の.vimrcでよく使われる設定向けのキーワードの追加と、コメントと引用符絡みでちょっとおかしかったところを直して、GitHubに作った言語ハンドラーのリポジトリに突っ込んだ。だいたいOKな気がする。

ローカルのJavaScriptファイルをClosure Compiler ServiceのREST APIでコンパイルできるように

Posted
on
in

前に作って愛用しているClosure Compiler ServiceのREST APIを叩くPerlスクリプトにローカルのJavaScriptファイルを読み込んでコンパイルに含められる機能を付けた。Closure CompilerJARファイルを使ってローカルで動かしても良かったんだけど、APIやWeb UIのコメントでオプション設定を書く方法(Greasemonkey的な奴)が気に入っているので@code_pathというパラメーターを追加する形にした。

コンパイルするJavaScriptファイルでは

// ==ClosureCompiler==
// @code_path foo.js
// @code_path bar.js
// @code_url  http://example.com/js/buz.js
// ==/ClosureCompiler==

というように@code_pathで取り込むJavaScriptファイルのパスを指定するだけ。@code_url等の他のオプションとはバッティングしないけど、依存関係によって書く順序には注意する必要がある。これらに続けて普通にJavaScriptコードも書けるとかそこらへんはWeb UIと一緒。

コンパイル方法は前のと同じで標準入力と出力で。

$ gccs.pl <test.js >test.min.js

肝心のgccs.plは以下の通り。Gistに置いてあるのも更新しておいた。

#!/usr/bin/env perl

# gccs.pl - Compile your JavaScript code with Google Closure Compiler Service
# Usage:    gccs.pl < <original file> > <compiled file>
# License:  http://hail2u.mit-license.org/2009
# Modified: 2012-01-04T18:43:15+09:00

use strict;
use warnings;

use JSON;
use LWP::UserAgent;
use Path::Class qw();

my @params = (
  "output_info",   "compiled_code",
  "output_format", "json",
);

&main;
exit;

sub main {
  my @code = <STDIN>;
  push @params, "js_code", join("", @code);
  my $idx = 0;
  my $found_metadata = 0;

  while (my $line = $code[$idx++]) {
    if ($line =~ /^\/\/ ==ClosureCompiler==/) {
      $found_metadata = 1;
      last;
    }
  }

  if ($found_metadata) {
    while (my $line = $code[$idx++]) {
      if ($line =~ /^\/\/ ==\/ClosureCompiler==/) {
        last;
      } elsif ($line =~ /^\/\/ @(\S+)\s*(.*)$/) {
        if ($1 eq "code_path" && -e $2) {
          my $js_code = ";" . Path::Class::File->new($2)->slurp() . ";";
          push @params, "js_code", $js_code;
        } else {
          push @params, $1, $2;
        }
      }
    }
  }

  &compile(@params);
}

sub compile {
  my $ua = LWP::UserAgent->new;
  my $res = $ua->post("http://closure-compiler.appspot.com/compile", \@_);

  if ($res->is_success) {
    my $c = from_json($res->decoded_content);

    if (defined $c->{"serverErrors"}) {
      foreach (@{$c->{"serverErrors"}}) {
        warn "Error(" . $_->{"code"} . "): " . $_->{"error"};
      }

      die "Failed to compile";
    } else {
      binmode STDOUT;
      print $c->{"compiledCode"};
    }
  } else {
    die $res->status_line;
  }
}

一応セミコロンの無いダメなJavaScriptファイルのことも考慮して前後にセミコロンを挟んでやったりはしておいた。ちょっと美しくないけどClosure CompilerをSIMPLE_OPTIMIZATIONS以上で通せば消えるのでまぁ良いかなとか。

普通にバラバラにスクリプトを書いて、Makefile的なJavaScriptファイルで@code_pathを使って参照し、それをコンパイルとかで使ってください。catよりはマシ程度ですけどね!

JavaScriptとYQLでReadabilityの短縮URLを作る

Posted
on
in

Readabilityにはrdd.meという短縮URLサービスがあり、それを使ってReadability化された読みやすい状態の記事を共有することができます。短縮URLの取得はWeb UIやReadability化したページで行える他、ウィジェットもありますが、APIも用意されているのでWebアプリケーションへの統合にはこちらを使った方が自由度が高いでしょう。YQLを使えばJavaScriptだけでも何とかなります。

APIは認証不要の単純なHTTPリクエストで叩きます。

$ curl https://readability.com/api/shortener/v1/urls -d url=http://hail2u.net/documents/diveintohtml5-semantics.html

cURLで短縮URLの作成APIを叩く場合はこのようにリソースにurlパラメータとして任意のURLをPOSTで投げるわけです。レスポンスはJSONで返ってきます。

{
  "meta": {
    "url": "/api/shortener/v1/urls/thu5ivbh", 
    "rdd_url": "http://rdd.me/thu5ivbh",
    "id": "thu5ivbh"
  },
  "messages": ["URL shortened."],
  "success": true
}

クエリが成功すればmeta.rdd_urlから短縮URLを拾うことができます。

JavaScriptで叩く場合はクロスドメインという壁があるのでYQLで逃げ……られると思いきや、POSTなので素のYQLでは叩けません(できるらしいですけどよく知らないです……)。しかし、Community Tableを有効にするとjsonpost(POSTでJSONが返ってくるサービスに使うテーブル)というまさに必要なものがあるのでこれを使います。

View Demo: JavaScript rdd.me Shortener

YQLに投げるYQL文は以下のような形になります。

SELECT * FROM jsonpost WHERE url='https://readability.com/api/shortener/v1/urls' AND postdata='url=http://hail2u.net/documents/diveintohtml5-semantics.html'

postdataでリソースに投げるurlパラメータをセットして使います。クロスドメインの問題はYQLのJSONPラッパーで解決できるので、jQueryなどと組み合わせればデモのように数行のJavaScriptでReadabilityの短縮URLが作成可能になります。


Readabilityのウィジェットはカッコイイと思うんですけど、ちょっと主張が強いというかボタンボタンしすぎてる感じで白背景のクリーンなWebサイト(例えばReadability Blogなど)にしかハマらない気がします。それでAPIを叩いて短縮URLを作ってリンクを叩こうとしました。最初は思わずblosxomのプラグインとして作ったんですが、APIが結構遅いのとやることの割にガッツリ様々なPerlモジュールが必要になるあたりで放棄しました。で、JavaScriptでページのロード後に叩けば良いかなーということでこんな感じになりました。

JavaScriptでロード後に叩く場合でも結局APIが遅いというのがボトルネックになって、ユーザーが読み始めた後で短縮URLが表示される、もしくは短縮URLが表示される前に読むのをやめてタブを閉じそうというなんともアレな感じです……。キャッシュ作ったりとかちゃんとやらないと実用化するのは厳しそうです。フィードの再構築みたいに記事の公開時だけに短縮URLを作ってキャッシュして、それ以外ではそのキャッシュを読むだけのblosxomプラグインでも書こうかなでも面倒くさいな(←今ここ)みたいな。

Query YQLプラグインでhttpsを考慮するようにしてもらった

Posted
on
in

Query YQLプラグインに呼び出し元のプロトコルがhttpsだった場合にはhttpsでクエリを投げるようなPull Requestを貰ったのでマージしました。

このパッチのように読み取り専用で安全なdocument.location.protocolを見て切り替えるのと、スキームを省略する(//で始まるURLを使う)のはどちらが良いんでしょうね?//だとローカル環境で動かすの面倒くさくなるので、こういったライブラリ・レベルでは切り替える方が良いのかも。対してコピペでハイ出来上がり!なJavaScriptウィジェットなんかでは//のがユーザーがハマりにくくなるんでしょうか。


圧縮したバージョンを作成するついでにYUI Compressorを更新して気づいたんですが、保持するコメントの出力がちょっと変わったような気がします。/*!で始めたコメントが保持されるのは変わっていませんが、!が削除されなくなったような。最近はClosure Compilerしか使っていなくてうろ覚えなんですが、READMEには消えることが明記されているので記憶違いではないと思います。バグなのか仕様変更してCHANGELOGに記載するの忘れたのかどっちなんだろう。Javaのコードとか読めないのでどこで変わったのかわかりません……。

mf2md

Posted
on
in

本気のメモです。メモなのでタイトルをわかりづらくしておきました。SEO対策ですね。

hAtom

From:

<article class="hentry">
  <h2 class="entry-title">
    <a rel="bookmark"
      href="http://hail2u.net/blog/webdesign/document-structure.html">
      文書構造を見なおした(ている)
    </a>
  </h2>
  <footer>
    <p>
      Posted on
      <time datetime="2011-11-09T19:31:06+09:00"
        pubdate
        class="published">
        09 Nov, 2011
      </time>
      in
      <a rel="tag"
        href="http://hail2u.net/blog/webdesign/">
        Web Design
      </a>
    </p>
  </footer>
  <div class="entry-content">...</div>
</article>

To:

<div itemscope itemtype="http://microformats.org/profile/hatom">
  <article itemscope itemtype="http://microformats.org/profile/hatom#hentry">
    <h2 itemprop="entry-title">
      <a rel="bookmark"
        href="http://hail2u.net/blog/webdesign/document-structure.html"
        itemprop="url">
        文書構造を見なおした(ている)
      </a>
    </h2>
    <footer>
      <p>
        Posted on
        <time datetime="2011-11-09T19:31:06+09:00"
          pubdate
          itemprop="published">
          09 Nov, 2011
        </time>
        in
        <a rel="tag"
          href="http://hail2u.net/blog/webdesign/"
          itemprop="url">
          Web Design
        </a>
      </p>
    </footer>
    <div itemprop="entry-content">...</div>
  </article>
</div>

hCard

From:

<address class="vcard">
  Made by
  <a href="/about/"
    class="fn url">
    Kyo Nagashima
  </a>
</address>

To:

<address itemscope
  itemtype="http://microformats.org/profile/hcard">
  Made by
  <a href="http://hail2u.net/about/"
    itemprop="fn url">
    Kyo Nagashima
  </a>
</address>

おまけ

<address class="vcard author">
  Made by
  <a rel="me"
    href="http://hail2u.net/about/"
    class="fn url">
    Kyo Nagashima
  </a>
</address>

今のこのブログのaddress要素ではhAtomとhCardそしてrel="me"が組み合わさるのでこんな感じになってます。

Google Code PrettifyのSCSSの言語ハンドラー

Posted
on
in

SCSS (Sassy CSS)Google Code Prettifyでシンタックス・ハイライトできるようにする言語ハンドラーを作ってみました。元々Google Code Prettifyがそれほど強力なシンタックス・ハイライトを提供しているわけではない上、ベースにしたCSSの言語ハンドラーがそもそもしょぼいのでイマイチな感じですが、コメントとat-rule系が見やすくなるのでまぁ及第点じゃないかなと。

View Demo: Test page for lang-scss.js

ダウンロードはデモ・ページのGistへのリンクからどうぞ。テスト用のSCSSコードは@terkelが作ってくれました。パッチーズ・ウエルカム。

使い方はlang-css.jsと同じでGoogle Code Prettifyを読み込んだあとlang-scss.jsを読み込むようにします。このサイトのようにまとめて圧縮したりしても良いでしょう。

<script src="http://example.com/js/prettify.js"></script>
<script src="http://example.com/js/lang-css.js"></script>
<script src="http://example.com/js/lang-scss.js"></script>

自動判別は多分失敗するのでHTMLでSCSSのコードであることを明示してやる必要があるでしょう。

<pre class="prettyprint lang-scss">...</pre>

でももうブログ程度のWebサイトにはシンタックス・ハイライトはいらないかなーとはちょっと思いますね。jsFiddleGitHubのような長めのコードを読むためのWebサイトならともかく、そこらのブログにある数行のコードのフラグメントを読む時にシンタックス・ハイライトが助けになることはまずないでしょう。加えて多数の色を使うということがデザインに与えるデメリットはなかなかのものなので、メリットよりデメリットの方が実は大きいのかな、と。

追記

GitHubに作った言語ハンドラーのリポジトリに突っ込んだ。

はてなスターでrel="canonical"を見るように

Posted
on
in

Googleの+1はデフォルトでrel="canonical"を見るようになってたりします。Facebookのいいね!ボタンはてなブックマークボタンは対応していませんが、明示的に対象のURLを指定できるようになっているのであまり問題はありません。しかし、はてなスターはa要素かwindow.locationdocument.locationという訪問者側がいくらでも細工ができるものしか指定できないため、宗教上の理由で自身のURLへリンクを張るa要素を書くことができない人は詰みます。そんな理由で外してしまったんですが、対応してくれそうもないので重い腰を上げてHatenaStar.jsに処理を追加しました。

ざっと読んだところHatena.Star.EntryLoader.getElementByConfigSelector()でうまいことrel="canonical"link要素を返すようにすれば良さそうです。gEBCS()はCSSセレクタを渡して要素を選択するものだが、内部でquerySelector()のラッパーになってたりとかそういううまい話はないので、link[rel="canonical"]を渡してもそのままではうまく動きません。なのでwindow.location等と同じように特別視する処理を入れてやる必要があります。

} else if (selector == 'link[rel="canonical"]') {
  var z = document.getElementsByTagName("link"),
    y,
    x = z.length,
    w,
    v = document.createElement("a");

  for (y = 0; y < x; y++) {
    w = z[y];

    if (w.rel === "canonical") {
      v.setAttribute("href", w.href);
      result = v.cloneNode(false);
      break;
    }
  }

getElementsByTagName()link要素を全て取得し、rel属性がcanonicalなものをresultにセットするというだけです。変数がはっちゃけているのは気にしない。cloneNode()を使っているのは相対URLでrel="canonical"が書かれていた場合に某ブラウザもどきで絶対URLにならないことへの対策で、元ネタはグループ日記のタイトルを変えすぎる人のエントリです。パッチとして欲しい場合はGistに置いておいたのでそちらからどうぞ。

これでHatena.Star.SiteConfigで特殊なセレクタとしてlink[rel="canonical"]が使えるようになります。


このブログのように、Blosxomで一覧ページとpermalinkで対象とするURLを切り替える場合はinterpolcate_fancyを使って以下のようにすれば良いでしょう。

<script type="text/javascript">
Hatena.Star.SiteConfig = {
  entryNodes: {
    "article": {
<?$path_info like="\.html$">
      uri:       "link[rel=\"canonical\"]",
</?>
<?$path_info unlike="\.html$">
      uri:       "h2 a",
</?>
      title:     "h2",
      container: "footer p"
    }
  }
};
</script>

これでスター通知でニヤニヤする日々が帰ってきますね!

HTML LintのAPIを叩くPerlスクリプト

Posted
on
in

HTML LintにはAPIが用意されているのでVimからいけるようにPerlスクリプトを書いてみましたが、やばそうなHTMLだと「Validじゃない」と言ってすぐ止まってしまうし、妥当な感じで書いたHTMLだと大体Lintもパスしちゃうので、あまり意味ない感じでした……。WebService::Validator::HTML::W3Cも使ってMarkup Validation Serviceにまず通してエラーが出たらそこで終了、通ったらHTML Lintにも投げるとかにすればそこそこ良さそうではありますが、んー。

#!/usr/bin/env perl

use strict;
use warnings;

use JSON;
use LWP::UserAgent;

my $file = shift;

my $ua = LWP::UserAgent->new();
my $res = $ua->post("http://lint.brihten.com/html/lint/",
  Content_type => "form-data", 
  Content      => [
    filesource           => [$file],
    tags_closeoptional   => 1,
    tags_lowercase       => 1,
    tags_closeempty      => 0,
    attrs_quoted         => 1,
    attrs_lowercase      => 1,
    attrs_simplebooleans => 1,
    tags_whitespace      => 0,
    response_format      => "json"
  ]
);

if ($res->is_success) {
  my $result = from_json($res->decoded_content);
  my $errors = $result->{mistakes};

  if (scalar(@$errors) > 0) {
    foreach my $e (@$errors) {
      print join(":", $file, $e->{line}, $e->{message}), "\n";
    }
  }
} else {
  die $res->status_line;
}

exit;

空要素を閉じてない場合の警告をオフっている以外はデフォルトです。

Web UIからでも使ってみるとわかると思いますけど、本当にイマイチです。ソースが公開されたりしてからが本番ということでしょうか。期待している人はすごく多いと思うので頑張って欲しいですね。

JPTemplateのラッパーを書いた

Posted
on
in

JPTemplateのスニペットを補完メニューで選択出来るようになりました

Vimのスニペット系のプラグインとしてJPTemplateを愛用しているんですが、テンプレート名を忘れるとどうしようもないという結構致命的な欠点があります。僕はそれほど数多くのスニペットを使うわけではないのであまり気にしてなかったんですけど、template-vimの補完を見て「やっぱあると良いなー」と思ったので、ラッパー関数を書いてみました。

let g:jpTemplateKey = '<C-S-F12>'

function! s:JPTemplateWrapper()
  let templdir_ft = g:jpTemplateDir.'/'.&ft
  let templdir_general = g:jpTemplateDir.'/general'
  let cword = matchstr(strpart(getline('.'), -1, col('.')), '[-0-9a-zA-Z_]*$')

  if filereadable(templdir_ft.'/'.cword) || filereadable(templdir_general.'/'.cword)
    call jp:InsertTemplate()
  else
    let templates = split(globpath(templdir_ft, '*'), "\n")
    let templates += split(globpath(templdir_general, '*'), "\n") 
    call complete(col('.') - strlen(cword), map(filter(templates, 'v:val =~ "'.cword.'"'), 'fnamemodify(v:val, ":t:r")'))
  endif

  return ''
endfunc

inoremap <C-Tab> <C-R>=<SID>JPTemplateWrapper()<CR>

挿入モードでCtrl+Tab(デフォルトのマッピング)を押すと、カーソル位置のファイル名っぽい文字列([-0-9a-zA-Z_])を拾い、もしその文字列でスニペットがあったらJPTemplateを呼んでやってます。スニペットが見つからなかったら全スニペット候補からその文字列で絞り込んで補完メニューを出すので、選択して確定後もう一回Ctrl+Tabでスニペットが挿入されます。

補完メニューで確定したら即スニペット補完とかは難しくて出来ませんでした!