アナログ
RSS  

Copy URL Lite+ に Amazon Short URI を組み込んだソース2011/01/18 19:57

Copy URL Lite+A

Copy URL Lite+Amazon Short URI を組み込みました。
オリジナルと区別しやすいよう便宜上 Copy URL Lite+A と呼びます。


これは何?

ブログや Twitter などにリンクを貼り付けやすいよう、現在見ているページの URI やタイトルを HTML やテキスト形式でクリップボードにコピーする Firefox の userChromeJS 用スクリプトです。

ユーザスクリプトの導入方法についてはここでは説明しておりません。

動作環境
Firefox 3.6/4.0β
userChromeJS 1.2
Sub-Script/Overlay Loader v3.0.30mod

解説しないけど、なにやらあったので置いとく。
userChrome.js ~拡張機能の解体再構築~
導入時に参考にしたところとか
userChrome.js - Mozilla Firefox まとめサイト
Firefox の拡張機能、userChrome.js の私の使い方 - 朝顔日記
userChromeJS 1.0 キタ - 朝顔日記


Copy URL Lite+ との相違点

  • www.amazon.co.jp の商品ページで URI が短縮可能な場合、メニューに「Amazon Short URI」が表示され、コピーされる URI は短いものに置き換えられます。
  • メニューに「Amazon Short URI」が表示される場合に、トラッキングID付きの URI にするには下記のようにソースを変更します
  • メニューに「Amazon Short URI」が表示中、「画像リンク」を使用すると
    <a class="azlk" target="_blank" href="短縮URI"><img src="画像URI">画像のalt項目またはページタイトル<br><br></a><br clear="all">
    といった特殊な形式でコピーされるので CSS と組み合わせないと見苦しくなります。
  • リンク上で右クリックした場合、画像リンクを除き URI はリンク先のものに置き換わります。
    (画像リンクは Copy URL Lite+ と同様、表示中のページの URI を使います)

Amazon Short URI の画像リンクの CSS について

サイズが75×75程度の画像を想定した CSS のサンプルです。
大きな画像を貼るならwidth: 200px;を適切なサイズに調整します。

a.azlk {
  display: block;
  float: left;
  width: 200px;
  font-size: x-small;
  background-color: white;
  margin: 3px;
  padding: 1px;
  border: 2px solid #FB970E;
  position: relative;
}
a.azlk:after {
  content: url("http://ecx.images-amazon.com/images/G/09/buttons/buy-from-tan.gif");
  border-width: 0;
  margin: 0;
  position: absolute;
  bottom: 0;
  right: 0;
}
a.azlk img {
  border-width:0;
  margin:2px 2px 2px 0;
  float:left;
}
WesternDigital CaviarGreen 3.5inch 5400rpm 2TB 64MB SATA/3.0Gbs WD20EARS-R

ものしり湯呑 しあわせシリーズ 女の気持ち・男の気持ち K-49


上のように <br clear="all"> を消すことで、横に余裕がある場合は回り込みます。
そのままではどこへのリンクか分からないので、a.azlk:after で「amazon.co.jp で買う」の画像を表示してますが、IE6(IE7 は未確認)では表示されないので IE6 への対応が必要な方は別の手段をご検討ください。

追記:backgroundでひとまとめに書いたら表示されなかったのでafterを使ったのに、ばらしたら表示された。orz
というわけで、下のCSSならIE6でも表示できます。

a.azlk {
  display: block;
  float: left;
  width: 200px;
  font-size: x-small;
  margin: 3px;
  padding: 1px;
  border: 2px solid #FB970E;
  background-color: #FFF;
  background-image: url(http://ecx.images-amazon.com/images/G/09/buttons/buy-from-tan.gif);
  background-repeat: no-repeat;
  background-position: right bottom;
}
a.azlk img {
  border-width: 0;
  margin: 2px 2px 2px 0;
  float:left;
}

ソースについて

人様のコードをちょろ~んといじった程度なのに、全部のっけていいのか(作者の迷惑にならないか)悩んだのですが、迷惑になるようなら消すということで全部載せてみます。

※注意

  • 名前とバージョンを変えていますが、オリジナルと区別するためで他意はありません。
    また派生と呼べるほどの変更でもありません。基本的に次回改造するときの覚書です。
  • Copy URL Lite+A で発生したバグを Shinya様に問い合わせるとご迷惑になりますので、このブログのコメントでお知らせ下さい。
    私に治せるバグは対応したいと思います。
  • 機能追加などは対応しません。その辺は自力でお願いします。
// ==UserScript==
// @name           Copy URL Lite+A
// @version        1.0.0
// @description    Like Copy URL+ extention.
// @author         Shinya
// @homepage       http://www.code-404.net/article/2007/07/15/copy-url-lite
// @namespace      http://www.code-404.net/
// @compatibility  Firefox 3.6 4.0beta
// @include        chrome://browser/content/browser.xul
// @note           
// ==/UserScript==
// Copy URL Lite+A は Copy URL Lite+ 1.4.0 に
// Amazon Short URI http://www.foxking.org/oldsite/?20070222S1 を組み込んだものです。
// 詳細は http://puppet.asablo.jp/blog/2011/01/18/5641069 をご覧ください。

/* Copy URL Lite
 *   nanto_vi (TOYAMA Nao), 2006-12-26
 *
 * Copy URL and extra informations from the context menu.
 *
 * http://nanto.asablo.jp/blog/2006/12/31/1083170
 */

(function(){

  var locale = Components.classes["@mozilla.org/preferences-service;1"].
    getService(Components.interfaces.nsIPrefBranch);
  locale = locale.getCharPref("general.useragent.locale");

  var mMenus = [
    {
      // <a>タイトル
      label: locale.indexOf("ja") == -1 ? "<a>title" : "<a>\u30BF\u30A4\u30C8\u30EB ",
      accesskey: "A",
      text: '<a href="%URL_HTMLIFIED%" target="_blank">%TITLE_HTMLIFIED%</a>',
      condition: "non-select"
    },
    {
      // <a>選択部分
      label: locale.indexOf("ja") == -1 ? "<a>Selection" : "<a>\u9078\u629E\u90E8\u5206 ",
      accesskey: "A",
      text: '<a href="%URL_HTMLIFIED%" target="_blank">%SEL_HTMLIFIED%</a>',
      condition: "select"
    },
    {
      // 選択部分とタイトル
      label: locale.indexOf("ja") == -1 ? "<a>Selection - Title" : "<a>\u9078\u629E\u90E8\u5206 - \u30BF\u30A4\u30C8\u30EB",
      text: '<a href="%URL_HTMLIFIED%" target="_blank">%SEL_HTMLIFIED% - %TITLE_HTMLIFIED%</a>',
      accesskey: "S",
      condition: "select"
    },
    {
      // <a title="タイトル">選択部分
      label: locale.indexOf("ja") == -1 ? "<a title>Selection" : "<a \u30BF\u30A4\u30C8\u30EB>\u9078\u629E\u90E8\u5206 ",
      accesskey: "T",
      text: '<a href="%URL_HTMLIFIED%" title="%TITLE_HTMLIFIED%" target="_blank">%SEL_HTMLIFIED%</a>'
    },
    {
      // 選択時の区切り
      label: "separator",
      condition: "select"
    },
    {
      // アンカー付引用
      label: locale.indexOf("ja") == -1 ? "<a>title<blockquote>Selection" : "<a>\u30BF\u30A4\u30C8\u30EB\u3068\u9078\u629E\u90E8\u5206\u306E\u5F15\u7528 ",
      accesskey: "B",
      text: '<a href="%URL_HTMLIFIED%" target="_blank">%TITLE_HTMLIFIED%</a>%EOL%<blockquote>%EOL%%SEL_HTMLIFIED%%EOL%</blockquote>%EOL%',
      condition: "select"
    },
    {
      // 引用
      label: locale.indexOf("ja") == -1 ? "<blockquote>Selection" : "HTML \u9078\u629E\u90E8\u5206\u306E\u5F15\u7528 ",
      accesskey: "Q",
      text: '<blockquote>%EOL%%SEL_HTMLIFIED%%EOL%</blockquote>%EOL%',
      condition: "select"
    },
    {
      // 区切り
      label: "separator",
    },
    {
      // タイトルと URI
      label: locale.indexOf("ja") == -1 ? "Title, URI" : "\u30BF\u30A4\u30C8\u30EB\u3068 URI ",
      accesskey: "C",
      text: '%TITLE%%EOL%%URL%%EOL%',
      condition: "non-select"
    },
    {
      // タイトルと URI と選択部分
      label: locale.indexOf("ja") == -1 ? "Title, URI, Selection" : "\u30BF\u30A4\u30C8\u30EB\u3068 URI \u3068\u9078\u629E\u90E8\u5206 ",
      text: '%TITLE%%EOL%%URL%%EOL%%SEL%%EOL%',
      condition: "select"
    },
    {
      // タイトル
      label: locale.indexOf("ja") == -1 ? "Title" : "\u30BF\u30A4\u30C8\u30EB",
      text: '%TITLE%'
    },
    {
      // 画像時の区切り
      label: "separator",
      condition: "image"
    },
    {
      // 画像リンク
      label: locale.indexOf("ja") == -1 ? "Image Link" : "\u753B\u50CF\u30EA\u30F3\u30AF",
      text: '<a %A_CLASS%target="_blank" href="%URL_HTMLIFIED%"><img src="%IMAGE_URL_HTMLIFIED%"%IMAGE_ALT_HTMLIFIED%>%IMAGE_TITLE_HTMLIFIED%</a>%EOL%<br clear="all">',
      condition: "image"
    },
    {
      // アマゾン短縮 URIの区切り
      label: "separator",
      condition: "as-uri"
    },
    {
      // アマゾン短縮 URI
      label: "Amazon Short URI",
      text: '%URL%',
      condition: "as-uri"
    }
  ];

  init: {
    var contextMenu = document.getElementById("contentAreaContextMenu");
    var separator = document.getElementById("spell-no-suggestions");

    var menu = document.createElement("menu");
    menu.id = "copyurllite";
    menu.setAttribute("label", "Copy URL Lite+A");
    menu.setAttribute("accesskey", "U");
    menu.className = "menu-iconic";
    menu.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAABGdBTUEAALGPC%2FxhBQAAAAlwSFlzAAAnEAAAJxABlGlRGQAAAAd0SU1FB9QGGAEvLH6QQPAAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCBWMy4wOKSzs%2BUAAALoSURBVDhPjZJLTBNRFIYHiAaMIT4CiogLF0ajcWUwrjXiwrgDhGhMfCFWIyQaDZGIhBhBkTdYRUyDIYIgzzSIiAYQsRRoLa%2FSlvJomRampQItBWbu750xEFlAPJkz58zi%2F%2Bb8516fgoqpxG2Bm%2Fb6b2aC%2Ff19g7YG%2BO3keYQ5XItTIL7R0RE7BpmNorKZqxUEAkIIlngC%2BmCZvpp%2FsCiudfbnfOCPbQjIKzPHspwXYoiAhSVKoFH%2FZRiP89VIyeu2MszNoHUh9591h7X1OhZEmYeK5yjLaOfR0DGD900WlFSPIl1ubGzp8bysapmpK22YvrYWti9zS%2B1Xa6eXB1wegtlFoFmzgF69FyJ0cRmYdQvSZGOsG2VKK1Eo3Q9TW%2BG3AvJ5V28ompolmOQIuHlAZVpGu3YOgiCsWvNSkHNuEU%2BKupD%2BZhh3M1SJjE%2BbjwQpKNPKtKZ5WDhgfEqA2giUNjphc3ilpbrp3%2Be9BM55AV06Fp3aMbyrMwxFXG4LlAApuR0RrT12sC7gdaEN2Vl25FZOw2DxUDG1Rjck2rO7aF2gp0Tn%2Bq51keT83oMSIPb2h3Blm0UoltvBHICUV2VGdPb9BjcHsDPUmhuYpHWC2rQ4ALXejdTC7gsS4MiptEPln0Y5eaZ5FSCL06P8MwurQ4CJFTA6TWC2ExgnBRho9o3weJTz84UEOLpHef9evIqTJ7SvApJi23Envgcl8kmYbAT6CTEFjIgQ%2Bj0wRvD0lVrJHA%2FrvL4y9nq1KN%2BGgXGCX2YCnVlAP%2B21JoJshUb3X4D8XBt0VKTW81AN8ug20H6YILdUw0oWdu1nz4fst8ZEhlQ8WJlCFpyXce5ETfXzDCtUQwJ6zaBCujx6xCr938xWaLHmVp4JVSasAMT%2B7KWCKy1qD9p1Ar5plvCxhUNxlQlZCq2HXqi%2BuKTqhjWAf%2Fch9iejMmIepDcN3EquqYqRKdKibry9GHn1Tfjp2JxQv92R2xnmcMAftGCCCifLktsAAAAASUVORK5CYII%3D");
    contextMenu.insertBefore(menu, separator);

    var menuPopup = document.createElement("menupopup");
    menu.appendChild(menuPopup);

    for(var i = 0, menu; menu = mMenus[i]; i++){
      var menuItem;
      if(menu.label == "separator"){
        menuItem = document.createElement("menuseparator");
      }
      else{
        menuItem = document.createElement("menuitem");
        menuItem.setAttribute("label", menu.label);
        if("accesskey" in menu) menuItem.setAttribute("accesskey", menu.accesskey);
        menuItem.culMenu = menu;
        menuItem.addEventListener("command", copyText, false);
      }
      menuItem.id = "copyurllite-menu-" + i;
      menuPopup.appendChild(menuItem);
    }

    contextMenu.addEventListener("popupshowing", setMenuDisplay, false);
  }

  function copyText(aEvent){
    
    function htmlEscape(text) {
      text = text.replace(/&/g, "&amp;");
      text = text.replace(/>/g, "&gt;");
      text = text.replace(/</g, "&lt;");
      text = text.replace(/"/g, "&quot;");
      text = text.replace(/\r\n/g, "<br>\r\n");
      return text;
    }

    function convertText(text){
      if(gContextMenu.onLink){
        text = text.replace(/%URL_HTMLIFIED%/g, link_html);
        text = text.replace(/%URL%/g, link);
      } else {
        text = text.replace(/%URL_HTMLIFIED%/g, url_html);
        text = text.replace(/%URL%/g, url);
      }
      text = text.replace(/%TITLE_HTMLIFIED%/g, title_html);
      text = text.replace(/%TITLE%/g, title);
      text = text.replace(/%SEL_HTMLIFIED%/g, sel_html);
      text = text.replace(/%SEL%/g, sel);
      if(gContextMenu.onImage){
        text = text.replace(/%IMAGE_URL_HTMLIFIED%/g, imageUriHtml);
        text = text.replace(/%IMAGE_ALT_HTMLIFIED%/g, imageAltHtml);
        text = text.replace(/%IMAGE_TITLE_HTMLIFIED%/g, imageTitleHtml);
        text = text.replace(/%A_CLASS%/g, a_class);
      }
      text = text.replace(/%EOL%/g, eol);
      return text;
    }

    var text = aEvent.target.culMenu.text;
    var title = content.document.title;
    var title_html = htmlEscape(title);
    var url = content.document.location.href;
    var asin = '';
    if(content.document.location.hostname == 'www.amazon.co.jp'){
      try{
        asin = content.document.getElementById('ASIN').value;
      }catch(e){
        asin = false;
      }
      if(asin) {
        url = 'http://amazon.jp/dp/'+asin;
      }
    }
    var url_html = htmlEscape(url);
    var sel = '', sel_html = '';
    if(gContextMenu.isTextSelected){
      sel = content.getSelection().toString();
      sel_html = htmlEscape(sel);
    }
    if(gContextMenu.onLink){
      var link = gContextMenu.getLinkURL().toString();
      var link_html = htmlEscape(link);
    }
    if(gContextMenu.onImage){
      link = url;
      link_html = url_html;
      var imageUri = gContextMenu.imageURL;
      var imageUriHtml = htmlEscape(imageUri);
      var imageAlt = gContextMenu.target.alt;
      var imageAltHtml = htmlEscape(imageAlt);
      var imageTitleHtml = '';
      var a_class = '';
      if(asin) {
        a_class = 'class="azlk" ';
        if(imageAltHtml){
            imageTitleHtml = imageAltHtml;
            imageAltHtml = '';
        } else {
          if(!(imageTitleHtml)){
            imageTitleHtml = title_html;
          }
        }
        imageTitleHtml += '<br><br>';
      } else {
        if(imageAltHtml) {
          imageAltHtml = ' alt="' + imageAltHtml + '"';
        }
        imageTitleHtml = '';
      }
    }
    var eol = "\r\n";

    Cc["@mozilla.org/widget/clipboardhelper;1"]
      .getService(Ci.nsIClipboardHelper).copyString(convertText(text));
  }

  function setMenuDisplay(){
    var fasin = true;
    if(content.document.location.hostname == 'www.amazon.co.jp'){
      try{
        if(content.document.getElementById('ASIN').value) {
          fasin = false;
        }
      }catch(e){}
    }

    for (var i = 0, menu; menu = mMenus[i]; i++)
      document.getElementById("copyurllite-menu-" + i).hidden =
        menu.condition == "non-select" ?
          gContextMenu.isTextSelected :
        menu.condition == "select" ?
          !gContextMenu.isTextSelected :
        menu.condition == "image" ?
          !gContextMenu.onImage :
        menu.condition == "as-uri" ?
          fasin : false;
  }

})();

黄色い背景色のコードは Amazon Short URI に必要な変更点です。
Copy URL Lite+ を既にお使いの方は、黄色の部分を取り込めば同様のことが可能になります。

画像リンクに関して、私は画像リンクを利用してなかったこともあって、Amazon Short URI 用の画像リンクとメニューを分けるべきところを共存させているので、かなりの改悪になっています。
それでも Copy URL Lite+ と似た動作になるようになっていますが、末尾に<br clear="all">が付与されます。
Copy URL Lite+ で画像リンクを活用されている方は分離して書き直した方がスッキリすると思います。

なお、Amazon Short URI をトラッキングID付きの短縮URIにするには
202行目の
        url = 'http://amazon.jp/dp/'+asin;

        url = 'http://amazon.jp/o/ASIN/'+asin+'/トラッキングID/';
に変更して、「トラッキングID」部分をご自分のトラッキングIDに書き換えて下さい。

トラッキングIDを埋め込んだら間違いがないか確認のため、適当な商品ページに移動して Amazon Short URI でリンクをコピーし「リンクの動作確認ツール」でテストしておきましょう。


次に青い背景色のコードですが、リンク上で右クリックした場合に(画像上の場合を除き)表示中のURIをリンク先のURIに変更している部分です。

Copy URL Lite+ では URI と RLINK で分けて扱われ、メニュー項目も分けられていますが、Copy URL Lite+A ではメニュー定義が倍化するのを嫌い、リンク上で右クリックしたら勝手に URI を入れ替えてます。

そもそも GUI は説明がなくても分かるようにするべきなのに、メニューが変化しない不親切な UI に改悪してます。
気に入らない場合は、自力でなんとかしてください。

その他の変更点

a タグはすべて target="_blank" が入ります。メニュー定義に埋め込んでますので不要ならソースから消して下さい。

Amazon Short URI で画像リンク作成時に <br><br> が挿入されるのがいやなら、234行の
        imageTitleHtml += '<br><br>';
を削除します。

他にも細かく変更されてますが、影響を及ぼすような変更ではなかったハズ。
例えば、選択してなくても選択項目を空欄で処理するとか、画像がリンクになってなくても画像リンクが動くとか RLINK は変数から消滅してるとか……

           /)
         ///)
        /,.=゙''"/
 /     i f ,.r='"-‐'つ____   こまけぇこたぁいいんだよ!!
/      /   _,.-‐'~/⌒  ⌒\
  /   ,i   ,二ニ⊃( ●). (●)\
 /    ノ    il゙フ::::::⌒(__人__)⌒::::: \
    ,イ「ト、  ,!,!|     |r┬-|     |
   / iトヾヽ_/ィ"\      `ー'´     /

参考までに以前の変更内容です。
JavaScriptが分からないままいじってますのでろくなもんじゃねえです(今だって大差ないですけど^^;)。

必要ないかと思いますが(私には必要だったw)日本語メニュー項目の変更の参考までUnicode エンコード/デコード

Amazon Short URI でトラッキングIDが有効になるアドレスについて

メニュー周りを操作するのに参考にした資料:Extensions - MDC Doc Center

コメント

コメントをどうぞ

※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。

※投稿には管理者が設定した質問に答える必要があります。

名前:
メールアドレス:
URL:
次の質問に答えてください:
スパムがウザイので合い言葉を入れるようにしました。山と言えば川だろJK


コメント:

トラックバック

このエントリのトラックバックURL: http://puppet.asablo.jp/blog/2011/01/18/5641069/tb

※なお、送られたトラックバックはブログの管理者が確認するまで公開されません。