2008/09/11

はてな
ちょっと訳あって、WScriptからjQueryを呼び出す必要があり(嘘です)作ってみました。

これを使うと
$.each([1,2,3], function(index, item) {
    print("foo" + item);
});
$.ajax({
    type: "GET",
    url: "http://www.google.co.jp/",
    async: false,
    success: function(data) {
        print(data);
    }
});
こんなソースが実行出来ます。
$.eachなんかは目茶目茶便利なので、使わない手はありません。とりあえず、$.ajaxでgoogle.co.jpのソースが取得出来るくらいは動きます。
以下全体ソース。
// vim:fdm=marker fdl=0 fdc=0 fdo+=jump,search:
// vim:fdt=substitute(getline(v\:foldstart),'\\(.\*\\){\\{3}','\\1',''):
// {{{
(function(target) {
    target.window = {
        document : {
            defaultView : {}
        },
        navigator : {
            userAgent : "Windows Scripting Host"
        },
        location : {},
        XMLHttpRequest : function() {
            // copied from http://la.ma.la/misc/js/ie_xmlhttp.js
            var self = this;
            var props = "readyState,responseText,responseXML,status,statusText".split(",");
            this.readyState  = 0;
            this.__request__ = new ActiveXObject("Microsoft.XMLHTTP");
            this.__request__.onreadystatechange = function(){
                for(var i=0;i<props.length;i++){
                    try{
                        self[props[i]] = self.__request__[props[i]]
                    }catch(e){
                    }
                }
                self.onreadystatechange()
                if(self.readyState == 4) self.onload();
            }
            this.onreadystatechange = function(){};
        },
        setInterval : function(func, interval) {
            func(); // quickly f*ckin hack
        },
        clearInterval : function(timer) {
        },
        setTimeout : function(func, interval) {
            func(); // quickly f*ckin hack
        },
        clearTimeout : function(timer) {
        }
    };
    var methods = "open','abort','send','setRequestHeader','getResponseHeader','getAllResponseHeaders".split("','");
    var make_method = function(name){
        window.XMLHttpRequest.prototype[name] = function(){
            var params = new Array(arguments.length);
            for(var i=0;i<params.length;i++) params[i] = "_"+i;
            return Function(
                params.join(","),
                ["return this.__request__.",name,"(",params.join(","),")"].join("")
            ).apply(this,arguments);
        }
    };
    for (var i=0;i<methods.length;i++) make_method(methods[i]);
    for (var n in window) target[n] = window[n];
})(this);

function print(msg) {
    WScript.StdOut.WriteLine(String(msg));
}

function require(source, target) {
    target = target||this;
    var fso = new ActiveXObject('Scripting.FileSystemObject');
    var stm = fso.OpenTextFile(source, 1, false, -2);
    var text = stm.ReadAll();
    stm.Close();
    eval(text, target);
    for (var n in windowif (typeof target[n] === 'undefined') target[n] = window[n];
}
// }}}

require("jquery-latest.js");

$.each([1,2,3], function(index, item) {
    print("foo" + item);
});

$.ajax({
    type: "GET",
    url: "http://www.google.co.jp/",
    async: false,
    success: function(data) {
        print(data);
    }
});
setTimeoutとかsetIntervalはf*ckingはhackなので$.get(非同期)は動きません。直す余地ありです。
あと、XMLHttpRequestのbindはmalaさんのをパクってます。

2008/07/28

はてな
不具合報告を頂きまた。自分でも動かなくなってたのに気付いてませんでした。
Big Sky :: XSLとjQuery/HTMLだけで作る、amazon最速検索
http://mattn.kaoriya.net/software/lang/javascript/20080605165643.htm
どうやら、jQueryがcacheを無効にする時に使用する特殊パラメータ"_"がAmazonで蹴られる様になったのが原因です。
結構ハマった(30分)割には、直し方は簡単。
$.ajaxSettings.cache = true;
まぁ、Amazon検索にはリアルタイムなキャッシュ無効は必要なさそうなので、これで良しとします。
一応、直ったのでこの記事にも実行例置いときます。コードは↑のリンク先を参照下さい。

続きを読む...


2008/06/17

はてな
元ネタ
M.C.P.C.: はてなお気に入りAPIを使ってブログパーツ作例

はてなお気に入りAPIを使ってブログパーツ?を作ってみた...

http://blog.dtpwiki.jp/dtp/2007/09/api_60ed.html
ソースは以下
jquery.hatenaFav.js
// --------------------------------------------------------------
// jquery.hatenaFav.js : hatenaお気に入り画像表示ブログパーツ
// based on: http://blog.dtpwiki.jp/dtp/2007/09/api_60ed.html
// (required: jquery.js)
// --------------------------------------------------------------

(function($){
  $.fn.hatenaFav = function(options){
    return this.each(function(index){
      var it = this, $this = $(this);
      it.opts = $.extend({}, $.fn.hatenaFav.defaults, options);
      if (it.opts.loader) $('<img/>').attr('src', it.opts.loader).appendTo($this);
      else $this.html('loading...');
      $.ajaxSetup({cache:true});
      $.getJSON('http://s.hatena.ne.jp/' + it.opts.user + '/favorites.json?callback=?', function(data) {
        $this.html('');
        $.each(data.favorites, function(index, item) {
          if (index > it.opts.max) {
            $('<a/>').attr('href', '#').click(function() {
              options.max = data.favorites.length;
              $this.hatenaFav(options);
              return false;
            }).attr('class', 'hatena-fav-more').css('font-size', '0.8em').text('more...').appendTo($this);
            return false;
          }
          $('<img/>').attr('src', 'http://www.hatena.ne.jp/users/' + item.name.slice(0, 2) + '/' + item.name + '/profile_s.gif')
          .css({
            width: it.opts.size,
            height: it.opts.size,
            border: it.opts.border,
            title: 'id:' + item.name,
            alt: 'id:' + item.name
          }).wrap('<a/>')
            .parent().attr('href', 'http://d.hatena.ne.jp/' + item.name + '/').attr('target', it.opts.target).appendTo($this);
        });
      });
    });
  };
  $.fn.hatenaFav.defaults = {
    user:   'jkondo',
    size:   '16px',
    border: '0px',
    target: '_blank',
    max:    10,
    //loader: 'http://mattn.kaoriya.net/images/ajax-loader.gif'
  };
})(jQuery);
使い方はこんな感じ
<style type="text/css"><!--
.hatena-fav-container {
    font-family: meiryo, osaka;
    font-weight: bold;
    text-align: left;
    width: 200px;
    border: 1px solid gray;
}
.hatena-fav-container a, .hatena-fav-container a:visited {
    color: blue;
}
.hatena-fav-title {
    background-color: #ddd;
    text-align: center;
}
.hatena-fav-icons img {
    margin: 1px;
}
--></style>
<script type="text/javascript" src="jquery-latest.js"></script>
<script type="text/javascript" charset="utf-8" src="jquery.hatenaFav.js"></script>
<script type="text/javascript"><!--
$(function() {
    $('.hatena-fav-icons').hatenaFav({ user: 'mattn', size: 16 });
});
--></script>
<div class="hatena-fav-container">
    <div class="hatena-fav-title">
        <a href="http://mattn.kaoriya.net/">はてなお気に入り</a>
    </div>
    <div class="hatena-fav-icons"></div>
</div>
hatenaFavメソッドの引数に渡すuserとして、はてなのユーザIDを入れるとそのユーザのお気に入りユーザが表示されます。
実行結果は↓

続きを読む...


2008/06/05

はてな
気付いたらAmazon Ecommerce Web Serviceのバージョン3.0が終わっていました
それにともないmalaさんの「Amazon最速検索β」も動かなくなってしまっていました。
残念だったので気分だけでも...と思い作ってみました。
今回のポイントとしてはJSONではなくJSONPであること。malaさんのバージョンでは"end"というマーカーを使い、かつcallbackは指定出来ませんでしたが、以下のサンプルではcallbackパラメータを受け取りJSONPします。
AWS4では、与えられたパラメータがItemSearchResponse/OperationRequest/Arguments/Argumentに格納されるので、この属性Nameが"callback"の物を関数名となる様にしてあります。
まずXSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:aws="http://webservices.amazon.com/AWSECommerceService/2005-10-05"
  exclude-result-prefixes="aws">

  <xsl:output method="text" media-type="text/javascript" encoding="UTF-8"/>
  <xsl:variable name="lcletters">abcdefghijklmnopqrstuvwxyz</xsl:variable>
  <xsl:variable name="ucletters">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>

  <xsl:template match="/aws:ItemSearchResponse">
    <xsl:value-of select="aws:OperationRequest/aws:Arguments/aws:Argument[@Name='callback']/@Value"/>
    <xsl:text>({isvalid:</xsl:text>
    <xsl:value-of select="translate(aws:Items/aws:Request/aws:IsValid/text(),$ucletters,$lcletters)" />
    <xsl:text>,errors:[</xsl:text>
    <xsl:for-each select="aws:Items/aws:Request/aws:Errors/aws:Error">
      <xsl:text>{code:'</xsl:text>
      <xsl:value-of select="aws:Code" />
      <xsl:text>',message:'</xsl:text>
      <xsl:call-template name="sanitize-text">
        <xsl:with-param name="target" select="aws:Message"/>
      </xsl:call-template>
      <xsl:text>'}</xsl:text>
      <xsl:choose>
        <xsl:when test='position() &lt; last()'>
          <xsl:text>,</xsl:text>
        </xsl:when>
      </xsl:choose>
    </xsl:for-each>
    <xsl:text>],result:</xsl:text>
    <xsl:apply-templates select="aws:Items"/>
    <xsl:text>})</xsl:text>
  </xsl:template>

  <xsl:template match="aws:Items">
    <xsl:text>[</xsl:text>
    <xsl:for-each select="aws:Item">
      <xsl:apply-templates select="."/>
      <xsl:choose>
        <xsl:when test='position() &lt; last()'>
          <xsl:text>,</xsl:text>
        </xsl:when>
      </xsl:choose>
    </xsl:for-each>
    <xsl:text>]</xsl:text>
  </xsl:template>

  <xsl:template match="aws:Item">
    <xsl:text>{</xsl:text>

    <xsl:text>asin:'</xsl:text>
    <xsl:value-of select="aws:ASIN"/>
    <xsl:text>'</xsl:text>

    <xsl:text>,url:'</xsl:text>
    <xsl:value-of select="aws:DetailPageURL"/>
    <xsl:text>'</xsl:text>

    <xsl:text>,title:'</xsl:text>
    <xsl:call-template name="sanitize-text">
      <xsl:with-param name="target" select="normalize-space(aws:ItemAttributes/aws:Title)"/>
    </xsl:call-template>
    <xsl:text>'</xsl:text>

    <xsl:text>,publisher:'</xsl:text>
    <xsl:call-template name="sanitize-text">
      <xsl:with-param name="target" select="normalize-space(aws:ItemAttributes/aws:Publisher)"/>
    </xsl:call-template>
    <xsl:text>'</xsl:text>

    <xsl:text>,date:'</xsl:text>
    <xsl:call-template name="sanitize-text">
      <xsl:with-param name="target" select="aws:ItemAttributes/aws:PublicationDate"/>
    </xsl:call-template>
    <xsl:text>'</xsl:text>

    <xsl:text>,authors:[</xsl:text>
    <xsl:for-each select="aws:ItemAttributes/aws:Author">
      <xsl:text>'</xsl:text>
      <xsl:call-template name="sanitize-text">
        <xsl:with-param name="target" select="text()"/>
      </xsl:call-template>
      <xsl:text>'</xsl:text>
      <xsl:choose>
        <xsl:when test='position() &lt; last()'>
          <xsl:text>,</xsl:text>
        </xsl:when>
      </xsl:choose>
    </xsl:for-each>
    <xsl:text>]</xsl:text>

    <xsl:text>,label:'</xsl:text>
    <xsl:call-template name="sanitize-text">
      <xsl:with-param name="target" select="aws:ItemAttributes/aws:Label"/>
    </xsl:call-template>
    <xsl:text>'</xsl:text>

    <xsl:text>,price:'</xsl:text>
    <xsl:call-template name="sanitize-text">
      <xsl:with-param name="target" select="aws:ItemAttributes/aws:ListPrice/aws:FormattedPrice"/>
    </xsl:call-template>
    <xsl:text>'</xsl:text>

    <xsl:text>,availability:'</xsl:text>
    <xsl:call-template name="sanitize-text">
      <xsl:with-param name="target" select="aws:Offers//aws:Availability"/>
    </xsl:call-template>
    <xsl:text>'</xsl:text>

    <xsl:text>,image:{</xsl:text>
    <xsl:for-each select="aws:*[local-name()='SmallImage' or local-name()='MediumImage' or local-name()='LargeImage']">
      <xsl:call-template name="image">
        <xsl:with-param name="type" select="substring-before(local-name(), 'Image')"/>
      </xsl:call-template>
      <xsl:choose>
        <xsl:when test='position() &lt; last()'>
          <xsl:text>,</xsl:text>
        </xsl:when>
      </xsl:choose>
    </xsl:for-each>
    <xsl:text>}</xsl:text>

    <xsl:text>,reviews:[</xsl:text>
    <xsl:for-each select="aws:CustomerReviews/aws:Review">
      <xsl:text>{summary:'</xsl:text>
      <xsl:call-template name="sanitize-text">
        <xsl:with-param name="target" select="normalize-space(aws:Summary)"/>
      </xsl:call-template>
      <xsl:text>',content:'</xsl:text>
      <xsl:call-template name="sanitize-text">
        <xsl:with-param name="target" select="normalize-space(aws:Content)"/>
      </xsl:call-template>
      <xsl:text>'}</xsl:text>
      <xsl:choose>
        <xsl:when test='position() &lt; last()'>
          <xsl:text>,</xsl:text>
        </xsl:when>
      </xsl:choose>
    </xsl:for-each>
    <xsl:text>]</xsl:text>

    <xsl:text>}</xsl:text>
  </xsl:template>

  <xsl:template name="image">
    <xsl:param name="type"/>

    <xsl:value-of select="translate($type,$ucletters,$lcletters)"/>
    <xsl:text>:{</xsl:text>
    <xsl:text>src:'</xsl:text>
    <xsl:value-of select="aws:URL"/>
    <xsl:text>',</xsl:text>

    <xsl:text>width:</xsl:text>
    <xsl:value-of select="aws:Width"/>
    <xsl:text>,</xsl:text>

    <xsl:text>height:</xsl:text>
    <xsl:value-of select="aws:Height"/>
    <xsl:text>}</xsl:text>
  </xsl:template>

  <xsl:template name="sanitize-text">
    <xsl:param name="target"/>
    <xsl:choose>
      <xsl:when test="contains($target, '&quot;')">
        <xsl:value-of select="substring-before($target, '&quot;')"/>
        <xsl:call-template name="sanitize-text">
          <xsl:with-param name="target" select="substring-after($target, '&quot;')"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise><xsl:value-of select="$target"/></xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>
ソース:aws2json.xmsl
ポイントとしては"apply-template"のselectを使うのではなく"xsl:for-each"を使うことで"position()"および"last()"を使った最終要素時のカンマ制御を行っている所。FirefoxではokですがIEだとエラーになっちゃいますからね。
そしてjavascript部分
$(document).ready(function() {
  var unsanitize = function(text) {
    return (text||'').replace(/&amp;/g, '&').replace(/&gt;/g, '>').replace(/&lt;/g, '<');
  }
  $('#aws-word').keydown(function(e) { if (e.keyCode == 13) $('#aws-search').click() });
  $('#aws-search').click(function() {
    if (!$('#aws-word').val()) {
      $('#aws').html('');
      return;
    }
    $('#aws').html('<img src="http://mattn.kaoriya.net/images/ajax-loader.gif"/>');
    $.ajaxSettings.cache = true;
    $.getJSON('http://xml-jp.amznxslt.com/onca/xml?callback=?',
      {
        Service: 'AWSECommerceService',
        SubscriptionId: '1GXPBVS13GJVA58PKVG2',
        AssociateTag: 'bigsky-22',
        Operation: 'ItemSearch',
        SearchIndex: $('#aws-kind').val(),
        ResponseGroup: 'Medium,Offers,Reviews',
        Version: '2005-10-05',
        Keywords: $('#aws-word').val(),
        ContentType: 'text/plain',
        Style: 'http://mattn.kaoriya.net/misc/aws2json.xsl'
      }, function(data) {
        $('#aws').html('');
        $.each(data.result, function(index, item) {
          $('<div>')
            .css('border', '1px dotted black')
            .css('border', '1px dotted black')
            .css('background-color', '#eeeeee')
            .css('padding', '0.5em')
            .css('margin', '0.5em')
            .attr('id', 'aws' + index)
            .hide()
            .appendTo('#aws');
          var c = $('#aws' + index);
      $('<a/>')
        .appendTo(c)
        .attr('href', item.url)
            .text(unsanitize(item.title))
            .appendTo(c);
          var a = $('a', c);
          if (item.image.medium) {
            $('<img>')
              .css('vertical-align', 'top')
              .css('padding', '0.5em')
              .css('border', '0px')
              .css('float', 'left')
              .attr('title', item.title)
              .attr('src', item.image.medium.src)
              .prependTo(a);
          }
          a.after('<br />');

          $.each(item.authors, function(index, item) {
            $('<b>')
              .text(item)
              .appendTo(c)
              .after('<br />');
          });
          $('#aws' + index)
            .append('<span>ASIN: ' + item.asin + '</span>')
            .append('<br />')
            .append('<br />')
            .append(item.publisher + '/' + item.price + ' (' + item.date + ')')
            .append('<br />')
            .append(item.availability);
          $(c).append('<br clear="all" /><br />');
          if (item.reviews.length) {
            $('<a href="#">review comments</a>')
              .css('font-size', 'small')
              .css('color', 'blue')
              .appendTo(c)
              .click(function() { $('.reviews', c).toggle('slow'); return false; });
            $('<div>')
              .attr('class', 'reviews')
              .css('display', 'none')
              .css('font-size', 'small')
              .appendTo(c);
            $.each(item.reviews, function(index, item) {
              $('.reviews', c)
                .append('<span class="name"><strong>' + item.summary + '</strong></span><br />')
                .append('<div class="comment">' + unsanitize(item.content) + '</div>')
                .append('<br />');
              $('.comment', c)
                .css('border', '1px dotted gray')
                .css('background-color', 'white')
                .css('padding', '0.5em')
            });
          }
        });
        $('div', '#aws').fadeIn('slow', function() {
          $('.reviews').hide();
        });
      }
    );
  });
});
amazon web serviceのXSLTプロセッサにcallback付きのXSLを処理させる事でjQueryのcallbackを呼び出させています。
getJSONのデータ部を弄る事である程度動きが変えられるかと思います。ただしOperationのItemSearchを変えると動かなくなりますので要注意です。
今回のサンプルとしてはレビューコメントも表示されるようになっています。"review comments"をクリックすると展開されます。
jQueryとXSLだけで動くのでCGIの動かないサーバでもokです。
あくまでサンプルですが、どなたかの参考になれば...

以下実行例

続きを読む...