右クリック長押し+ホイールでタブ切り替え

Operaに浮気した理由っていうのはFirefoxのモッサリ加減に突然嫌気がさしたからだったけど、OperaOperaで上辺だけの軽さっていうか、使い始めると結構ヘンな挙動があったりしてやっぱり使えなかったから、Firefoxに戻した。

とは言え、Firefoxのモッサリもなんとかしたいので、必要最低限の物だけ残して拡張機能を削除してみたり。それで気になったのがAll in One Gestures。「これは必須だろう」と思ってたけど、userChrome.jsで事足りるのかも。どんだけこのモッサリの原因になってるかは知らないけど、噂では重いって評価をよく聞くから、必要な機能をuserChrome.jsで書いて、All in One Gesturesは削除することにした。

http://amb.vis.ne.jp/mozilla/?p=72」の動作をロッカージェスチャの「右クリック+ホイール」で出来ると嬉しいなと思ったのですが・・・

ttp://supert.garyr.net/userchrome/gestures.uc.jsも使ってみたのですが、1つ隣のタブに切替えるたびに止まってしまい連続で切替えれないですし、右クリックを離す度にポップアップが開いてしまいます。
自分でも色々やってるのですが、全然上手くいきません。

http://amb.vis.ne.jp/mozilla/?p=76

↑このコメント、物凄い理解る。自分もそれ欲しい!ってことで作ってみた。参考にさせてもらったのはuserChrome.js 用スクリプト: Days on the MoonHistory Scrollerです。

gBrowser.addEventListener("mousedown", prepareForScroller, true);
function prepareForScroller(event) {
  if (event.button != 2 ||
      event.originalTarget.ownerDocument == document)
    return;
  document.addEventListener("DOMMouseScroll", selectTab, true);
  document.addEventListener("mouseup", defaultMouseup, true);
}

function selectTab(event) {
  preventClick(event);

  gBrowser.mTabContainer.advanceSelectedTab(event.detail > 0 ? +1 : -1, true);
  document.removeEventListener("mouseup", defaultMouseup, true);
  document.addEventListener("mouseup", endTabRoll, true);
}

function endTabRoll() {
  document.removeEventListener("DOMMouseScroll", selectTab, true);
  document.removeEventListener("mouseup", endTabRoll, true);
  gBrowser.addEventListener("click", preventClick, true);
  setTimeout(removeClickListener, 0);
  return;
}

function defaultMouseup() {
  document.removeEventListener("DOMMouseScroll", selectTab, true);
  document.removeEventListener("mouseup", defaultMouseup, true);
  return;
}

function preventClick(event) {
  event.stopPropagation();
  event.preventDefault();
}

function removeClickListener() {
  gBrowser.removeEventListener("click", preventClick, true);
}

タブリストをポップアップメニュー?みたいなので出して選ぶやつじゃなくて、マウスホイールで左右のタブをページのようにめくっていくやつです。ホイール回しまくるとめっちゃタブを切り替えまくります。Gomitaさんの「軽量マウスジェスチャ」との併用は試してないけど、とりあえずこんな感じで書けばできますよ、と。

userChrome.jsが面白い

以前、このはてなダイアリーじゃないところで、Firefoxで「コンテンツエリアでミドルクリックしたら今見てるタブを閉じる」とかいう、かなり誰も支持しないような操作法を実現するためのTipsを書いたりしてたけど、エクステンションを作るような知識もなく、browser.js内のcontentAreaClickを直接いじって…という感じでどうにかしていた。けどFirefoxをアップデートしたらそのいじった箇所も上書きされてしまうわけで、また書いて.jarファイルに圧縮して、とかいうのがウザくてやめた。

でも実際、Livedoor Readerとかでピン立て→一気に開く、とかやってると、凄い勢いでタブを閉じまくりたい時がある。「タブ上でミドルクリック」はデフォだけど、タブのところまでマウスを持っていくのが面倒くさい。ミドルクリックでのスクロールやジェスチャなんかを使う人はこの方法は論外だけど、使わない人は「コンテンツエリアでミドルクリックでタブを閉じる」って、いいと思うんだけどなぁ。

とか思っていたら、userChrome.jsなんて物があったのか。Firefoxの挙動自体をかなり自由に決めれる感じだ。早速これで再チャレンジしてみた。

最初は、window.contentAreaClickをオーバーライドして拡張して…なんて思っていて、こちらを参考にしたり、applyとかcallとかやってみたけど、どうもネイティブのwindow.contentAreaClickでの条件分岐を生かす書き方がわからなかった。targetがlinkNodeなのかとか、そういう判定を生かしつつ、“linkNodeとかじゃない場合”の処理を追加する方法がわからない。

なので、window.middleMousePasteを悪用することにした。middleMousePasteは、ミドルクリックをするとクリップボード内の文字列をURLとして開く機能なのだけど、はっきり言ってマジ要らないので普段はOFFにしてある。だけどこれをabout:configでmiddlemouse.contentLoadURL=trueにして、わざわざONにしておき、middleMousePasteをタブ閉じのための処理にごっそり書き換えてみた。

(function MouseEvents(){
window.middleMousePaste = function(event){
  if(event.target.nodeName=="xul:tab" || event.target.localName=="tab"){
    gBrowser.removeTab(event.target);
  }else{
    gBrowser.removeTab(gBrowser.selectedTab);
  }
  event.stopPropagation();
  return false;
}
})();

return falseが要るのかどうかはよくわからないけど、これで理想の動作になった!Tab Mix Plusを愛用しているけど、この拡張はmiddlemouse.contentLoadURL=trueの場合はタブ上での「ミドルクリックで閉じる」の処理を行わない。だからタブ上での動作も自前で書く必要がある。今回はシンプルにと思ってこの程度にしたけど、閉じた後に右のタブに移るのか左のタブに移るのか?みたいなこと書くならまた大変そうだな…。

ZenCartの注文確認メールの文面変更

v1.2.0-l10n-jp-6でのお話。

フッターなど

/includes/languages/japanese/email_extras.php

「ご注文日」に時刻をつけるとか

/includes/languages/japanese.php
定数DATE_FORMAT_LONGをいじる

購入した商品の情報

/includes/modules/checkout_process.php
変数$products_orderedをいじる

新しいバージョンのZenCartではどうなっているかわからないが、/includes/modules/checkout_process.phpはOverRideが効かなかった。直接変更するしかないようだ…。なんか本当ZenCartとかXOOPSとかってウザいな。挙動も構成も何もかもがモッサリしてる。

不必要なnamespace

<xsl:copy-of select="atom:content/xhtml:div/node()"/>

この場合のアウトプットは

<a xmlns="http://www.w3.org/1999/xhtml" href="#">リンクだよ</a>
<strong xmlns="http://www.w3.org/1999/xhtml">強調だよ</strong>

って感じで、XSLT

<xsl:copy-of select="atom:content/xhtml:div"/>

こう書くとアウトプットが

<div xmlns="http://www.w3.org/1999/xhtml">
  <a href="#">リンクだよ</a>
  <strong>強調だよ</strong>
</div>

ってなる。

atom:contentのmode属性

どうやらmt-atom.cgiでエントリーの本文を拾う場合、必ずしも

<content xmlns="http://purl.org/atom/ns#" mode="xml" type="application/xhtml+xml">
  <div xmlns="http://www.w3.org/1999/xhtml">本文</div>
</content>

という形式になるとは限らないみたいだ。こういう場合もある。

<content xmlns="http://purl.org/atom/ns#" mode="escaped" type="application/xhtml+xml">本文(&lt;_&gt;)</content>

本文にHTMLエンティティが含まれる場合にはこうなるみたい。でもHTMLエンティティが含まれていても、HTMLタグも使っている場合は<content mode="xml">となって<div>で囲まれるみたい。ってことでXSLTを修正した。

<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0"
  xmlns:atom="http://purl.org/atom/ns#"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xhtml="http://www.w3.org/1999/xhtml"
  xmlns:dc="http://purl.org/dc/elements/1.1/">
<xsl:output method='html' version='1.0' encoding='UTF-8' indent='no'/>

<xsl:template match="atom:entry">
  <textarea>
    <xsl:if test="not(atom:content/@mode='escaped')">
      <xsl:copy-of select="atom:content/xhtml:div/node()"/>
    </xsl:if>
    <xsl:if test="atom:content/@mode='escaped'">
      <xsl:value-of select="atom:content"/>
    </xsl:if>
  </textarea>
</xsl:template>

</xsl:stylesheet>

atom:contentをXSLTを使って表示する時

XSLT、一日や二日でそう簡単に扱えるような代物ではなかったみたい…。atom:contentでエントリーの本文を拾う時にハマッテしまった。なかなか難しいんだな。

今回は、エントリーの編集画面を作っているので、textareaに本文を入れる必要があった。だけどXSLT

<textarea><xsl:value-of select="atom:content"/></textarea>

と書いてしまうと、mt-atom.cgiでのAtomにはatom:contentとその子のdivの間にホワイトスペースが入っているので、それがtextareaの中にも入ってしまうし、エントリー本文の中で使っているHTMLタグが消えてしまう。

それで悩んでいた時にRe: Atom の XSLTを見つけて、よく読んだらやっと以下のような正解を見つけた。

<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0"
  xmlns:atom="http://purl.org/atom/ns#"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xhtml="http://www.w3.org/1999/xhtml"
  xmlns:dc="http://purl.org/dc/elements/1.1/">
<xsl:output method='html' version='1.0' encoding='UTF-8' indent='no'/>

<xsl:template match="atom:entry">
  <textarea><xsl:copy-of select="atom:content/xhtml:div/node()"/></textarea>
</xsl:template>

</xsl:stylesheet>

上に挙げたnantoさんのページでは

<xsl:copy-of select="atom:content/xhtml:div"/>

と言った感じになっているけど、この場合はdiv要素ごと表示される感じ。更に中身だけ欲しければ今回のようにnode()を指定する。これで一応なんとかなった。あとnamespaceをちゃんと書くのを忘れてしまったのも結構あったな、気をつけないと…。

でも今書いたXSLTだとFirefoxではエントリーの中で使っているHTML要素にも全部いちいちxmlns="http://www.w3.org/1999/xhtml"って属性が入っちゃう。これどうにかならないかなぁ。まだ模索が必要か…

けどXSLTって本当にいいな。もっとちゃんと勉強して自由に書けるようになろっと。

Sarissaが激しく便利

JavaScriptでXSLTを処理を見て驚いた!こんな便利な物があったなんて。今までxmlHttpRequestXMLを受信する場合、データを取り出して表示する時にchildNode.nodeValueやcreateElementの嵐に泣かされて本当に億劫だったけど、XSLTが使えるなら一気にHTMLを適用できて物凄く楽。XSLTの書き方から勉強しなきゃいけなかったけど、なんとか覚えました。

SarissaJavascriptでのXSLTXMLの扱いをクロスブラウザにまとめてくれてるもの。これからかなりお世話になりそうです。prototype.jsと一緒に使っても大丈夫でした。