2010年8月29日

ほしい物リストを作る 4

前回からのつづき。今回は具体的なサンプルを作ってみました。関数名、id名は任意でどうぞ。
XMLHttpRequestで送受信する部分は、いろいろなページで解説がされています。中身は、それらとほとんど変わりません。ただ、配列を使うバージョンはなかったように思いますので、その分だけ若干複雑になっています。

1.商品詳細ページの任意の場所に設置
<a href="#" onClick="JavaScript:set_wish_cookie(1);return false">ほしい物リストに追加する</a>

2.JavaScript-wish.js
//XMLHttpRequestオブジェクト生成
function createHttpRequest(num) {
  if(window.XMLHttpRequest) {
    //IE7 IE8 Firefox Opera Safari
    httpObj[num] = new XMLHttpRequest();
  }
  else if(window.ActiveXObject) {
    try {
        //MSXML2以降所
        httpObj[num] = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
      try {
          //旧MSXML
          httpObj[num] = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (e2) {
          httpObj[num] = null;
      }
    }
  }
  else {
    httpObj[num] = null;
  }
}
//タイムアウト処理
function timeout(n) {
  httpObj[n].abort();
  document.getElementById("wish"+n).innerHTML = strPid[n] + " (Timeout)";
}
//ファイルにアクセスし受信内容を確認
function wish_requestFile(num,method,async,pid) {
  createHttpRequest(num);
  if(httpObj[num]) {
    timerID[num] = setTimeout('timeout("' + num + '")',30000);//タイムアウト30秒
    fileName[num] = "http://www.hogehoge.com/?pid="+pid;
    httpObj[num].open(method,fileName[num],async); 
    httpObj[num].onreadystatechange = function() {
      if(httpObj[num].readyState==4) {//受信完了後の処理
        clearTimeout(timerID[num]);//タイムアウト解除
        if(httpObj[num].status == 200) {//正常
          strRes[num] = httpObj[num].responseText;         
          //ほしい物リスト表示
          if(strRes[num].match(/現在、この商品は扱っておりません。/igm) == null) {
            //在庫ありの場合の処理
           document.getElementById("wish"+num).innerHTML ='' + '<a href="#" onClick="JavaScript:del_wish_cookie(' + pid + ');location.reload();return false">リストから削除</a>';
          }
          else {
            //在庫なしの場合の処理
            document.getElementById("wish"+num).innerHTML ="現在、商品ID "+ pid +" は扱っておりません。次回表示時にリストから自動的に削除されます。";
            del_wish_cookie(pid);
          }
        }
        else if(httpObj[num].status == 404) {//404エラー処理
          document.getElementById("wish"+num).style.display = "none";
        }
        else {//それ以外
          document.getElementById("wish"+num).innerHTML = "server status " + httpObj[num].status;
        }
      }
    }
    httpObj[num].send(null);
  }
}


//Cookie部分削除
function del_wish_cookie(strNum) {
  strCookie=$.cookie('wish');
  strNum="!"+strNum+"!";
  re = new RegExp(strNum);
  if(strCookie.search(re)!=-1) {
    if(strCookie.indexOf(strNum)==0) {
      strCookie=strCookie.slice(strNum.length);
    }
    else {
      strCookie=strCookie.slice(0,strCookie.indexOf(strNum)) +       strCookie.slice(strCookie.indexOf(strNum)+strNum.length);
    }
    $.cookie('wish', strCookie ,{expires:365});
  }
}

//Cookieセット
function set_wish_cookie(i) {
  if(i==1) {//追加
    strURL=location.href;
    strCookie=$.cookie('wish');
    if(strCookie==null) {
      strCookie="";
    }
    else {
      loop=strCookie.match(/!/g)
      if(loop!=null && loop.length/2 >= 20) {
        window.alert("これ以上追加することはできません(最大20点まで)");
        return;
      }
    }
    if(strURL.indexOf("?pid=")!=-1) {
      strURL=strURL.slice(strURL.indexOf("?pid=")+5);
      strURL="!"+strURL+"!";
      re = new RegExp(strURL);
      if(strCookie==null || strCookie=="") {
        strCookie=strURL;
        $.cookie('wish', strCookie,{expires:365});
        window.alert("ほしい物リストに追加しました");
      }
      else if(strCookie.search(re)==-1) {
        strCookie=strCookie+strURL;
        $.cookie('wish', strCookie,{expires:365});
        window.alert("ほしい物リストに追加しました");
      }
      else {
        window.alert("この商品はすでに追加されています");
      }
    }
  }
  else {//削除
    $.cookie('wish','',{expires:-1});
  }
}


//ほしい物リスト表示
function load_wishlist() {
  //Cookie読み込み
  httpObj = new Array();
  strRes = new Array();
  timerID = new Array();
  fileName = new Array();
  strPid = new Array();

  strCookie=$.cookie('wish');
  if(strCookie==null)  {
    strCookie="";
  }
  loop=strCookie.match(/!/g);
  if(loop!=null) {
    if(loop.length/2>20) {//最大20点まで
      N=20;
    }
   else {
      N=loop.length/2;
    }
  }
  else {
    N=0;
  }
  for(i=1;i<=N;i++) {    strPid[i]=strCookie.substring(strCookie.indexOf("!")+1,strCookie.indexOf("!",strCookie.indexOf("!")+1));
    wish_requestFile(N+1-i,'GET',true,strPid[i]);
    strCookie=strCookie.slice(strCookie.indexOf("!",strCookie.indexOf("!")+1)+1);
  }
}

3.フリーページ
<div id="wish1"></div>
<div id="wish2"></div>
<div id="wish3"></div>
<div id="wish4"></div>
<div id="wish5"></div>
<div id="wish6"></div>
<div id="wish7"></div>
<div id="wish8"></div>
<div id="wish9"></div>
<div id="wish10"></div>
<div id="wish11"></div>
<div id="wish12"></div>
<div id="wish13"></div>
<div id="wish14"></div>
<div id="wish15"></div>
<div id="wish16"></div>
<div id="wish17"></div>
<div id="wish18"></div>
<div id="wish19"></div>
<div id="wish20"></div>
<script type="text/javascript">
<!--
  load_wishlist();
//-->
</script>
補足
・strRes[]に商品詳細ページまるまる格納されています。
・切り出す部分と表示は各自で作成してください(根気のいる作業です)。
・「現在、この商品は扱っておりません。」はテンプレートによっては異なるかもしれません。在庫の有無によって、処理・表示を分岐させます。在庫表示管理の設定や商材の種類によって、内容を見直す必要があります。
・~部分に表示させる情報を。その上の行に、切り出す処理を追加してください。
・最大登録数を20点にしています。サーバーへの負荷がかかりますので、無茶しない数で。
・Cookieに書き込む商品IDは、!で囲む形式にしています。!は区切り文字として使用。ex. !12345678!

XMLHttpRequestを使用せずに、もっと楽にシンプルに作れるとよいのですが。
使用時はサーバーに過度の負担をかけない程度に。

これに追加して、「カートに入れるボタンを商品詳細ページ以外に設置する」 を使えば、ほしい物リストページにカートに入れるボタンを設置することも可能(多分)。試したあとで、ご紹介したいと思います。


【関連記事】
カラーミーにできること、できないこと

2010年8月28日

ほしい物リストを作る 3

前回からの引き続きで、「ほしい物リストを作る」。

XMLHttpRequestを説明するまえに、今後よく見かけるであろうAjaxという用語について。
All About-Ajaxの基本」にわかりやすい説明がありましたので、まずはご一読を。
XMLHttpRequestによる送受信の流れもわかりやすく書いてあります。

Ajaxとは、Asynchronous JavaScript + XML(非同期なJavaScriptとXML)の略。
XMLHttpRequestはAjaxの中心となる技術で、ページ遷移なしで、非同期にサーバーとデータのやりとりをすることができます。ひどく目新しい技術、ということではなく、従来のJavaScriptの延長線上にあるものと考えて差し支えありません。ただ、はじめてこれを目にすると、かなり衝撃をうけます。
(jQueryのライブラリを使用する方法もありますが、このサイトでは使用していません)

Ajaxの特徴
情報を取ってくるのにページ遷移不要ですので、現在表示中のページに影響をおよぼしません。
非同期なので、ブラウザがロックしません(読み込み完了しなくても、別の操作ができます)。
上記のような理由もあり気づきにくいですが、gmailやGoogleマップなどでも使用されています。

ほしい物リストを作るための、もうすこし具体的な話
1.フリーページ
・ほしい物リスト表示ページの枠を作成→HTML、CSS
・Cookieを読んで、商品IDを取得→jQuery、JavaScript
・Ajaxで商品詳細ページのデータ取得→XMLHttpRequest
・取得後、必要情報を切り出し→JavaScript(indexOf、substring)
・ほしい物リスト表示ページをの枠に入れていく→JavaScript(document.getElementById(id).innerHTML)
2.商品詳細ページ
・ほしい物リストに追加するボタンを設置。クリック時にCookieに商品IDを書き込み→jQuery

XMLHttpRequestは、おいおい解説記事を書く予定ではありますが、まずは各自自習でよろしくお願いします。
簡単なサンプルを使用して(コピペするだけでも良いので)、動くところを実際にみて確認しておくと、このあとの作業でイメージがしやすいと思います。

次回「ほしい物リストを作る 4」 では、サンプルを作ってみます。

2010年8月24日

ほしい物リストを作る 2

前回のつづき。
どうやって必要な情報を取得するかより先に、ほしい物リストに必要な情報はなにか、という点について考えなければいけません。
商品名、販売価格、画像URL、説明文、+α。こんなところでしょうか。

前回も書きましたが、ほしい物リストを実現するためには二通りの方法が考えられます。
・Cookieに必要な情報すべてを書き込む方法
・商品IDだけ書き込んで随時商品ページから必要な情報を読み出す方法

作成するにあたり、Cookieの知識は重要ですので、まず先にその点について。

[引用] OPEN SPACE-Cookieファイルについて
■Cookieファイルの制限
cookieファイルは1行単位で処理され、ファイルの最大サイズは4KB (4096文字)、エントリーの合計は300、サーバーまたはドメインで最大20となっています。この制限を越えた場合使用されていないものから削除されていきます。
まず文字数制限があること。
ほしい物リストの必要情報すべてをCookieに書き込むとしたら、一商品あたりどれくらいの文字数が必要でしょうか。登録する商品点数は? ファイルサイズは足りますか? Cookieが二個以上必要になりますか?
いくつか制限はあるものの、なんとか切り抜けられそうなことが想像できます。

それでもここでは、もう一方の商品IDだけを書き込む方法を採用しています。かんたんな仕様は前回書いたとおりですが、あらためて以下に示します。
・「ほしい物リストに追加する」ボタンをクリックすると、Cookieに商品IDを書き込む
・ほしい物リスト一覧ページをフリーページで作成し、ページデザインをする
・商品ID以外にも表示に必要な情報を取得
・「ほしい物リストから削除する」ボタンをつくる

なぜ手間のかかる方を採用したか。
私がほしい物リスト機能を設置したショップの取り扱い商品は、基本的に一点もの(売れると表示されない)、という事情がありました。ほしい物リストに追加したはいいが、見たさいに在庫がないという状況は容易に想像できます。
ということで、「ほしい物リストページを表示したさいに、在庫のないものは消す」と設計をしました(お客様に手動で消してもらうのは手間で、申し訳なかったから)。
在庫の有無をCookieに書き込むことは無理ですし(情報が反映されない)、soldout_flgのような在庫の独自タグを参照できればよいのですが、フリーページからではそれもままなりません。
ほしい物リストの表示のたびに商品詳細ページに在庫の有無を確認しに行く必要があった訳です。
ということで、結局このような手間のかかる方法を採用することになりました。

そのほかにも細かい点で気になることがあります。
必要な情報内容が変更されたら? たとえば、価格改定が行われたら?
一度Cookieに書き込んでしまうと、修正するタイミングがありません。
ほしい物リストページに必要な情報を追加したくなったら?
Cookieに必要情報をすべて書き込む方法は柔軟性の面で、少し弱点がありました。

次回「ほしい物リストを作る 3」は、どうやって必要情報を取ってくるのか(XMLHttpRequestという機能を使用します)についてと、そのほか機能実現のための手段について。


【参照リンク】
OPEN SPACE-Ajaxを勉強しよう

2010年8月22日

ほしい物リストを作る 1

【追記】2013年10月以降は、カラーミーAPIでデータを引っ張ってくるのが素直。

カラーミーショップ!プロのカートシステムは機能面で少々物足りなく感じることがあります。
大手通販サイトでは、「ほしい物リスト(お気に入り、ウィッシュリストと呼ばれたりもします)」がついていることがよくあります。サーバー側で機能を持たせることが普通ですが、これは私たちからはいじることができません。私たち側からやれることで、実現できないのでしょうか。

方法としては。
・Cookieに必要な情報すべてを書き込む方法→「最近チェックした商品リストを作る」を参照
・商品IDだけ書き込んで随時商品ページから必要な情報を読み出す→ここではこちらを採用

仕様は以下のとおり。
・「ほしい物リストに追加する」ボタンをクリックすると、Cookieに商品IDを書き込む
・ほしい物リスト一覧ページをフリーページで作成し、ページデザインをする
・商品ID以外にも表示に必要な情報を取得してくる
・「ほしい物リストから削除する」ボタンをつくる

問題は、必要な情報をどうやって取得するかです。

ほしい物リストを作る 2」につづく。


【関連記事】
最近チェックした商品リストを作る

【追記】
各ページの内容を見直しました。

2010年8月21日

カートに入れるボタンを商品詳細ページ以外に設置する

以前、「Color Me Shop! pro - 助け合い掲示板」 に興味深い記事がありましたので、ちょこっと修正してサンプルのご紹介を。橙色部分は各自修正。
内容は表題どおり、「カートに入れるボタンを商品詳細ページ以外に設置する」。
<form name="product_form" method="post" action="http://secure.shop-pro.jp/?mode=cart_inn">
  購入数:<input type="text" name="product_num" value="1" />
  <input type="submit" value="カートに入れる" />
  <input type="hidden" name="product_id" value="12345678" />
  <input type="hidden" name="user_hash" value="<{$smarty.request.PHPSESSID}>" />
  <input type="hidden" name="members_hash" value="<{$smarty.request.PHPSESSID}>" />
  <input type="hidden" name="shop_id" value="PA01234567" />
  <input type="hidden" name="members_id" value="<{$smarty.session.PA01234567.MembersInfo.customer_id}>" />
  <input type="hidden" name="back_url" value="/" />
</form>
・product_numは、購入数。valueは初期購入数。商品詳細ページ内では独自タグ<{$product.init_num}>が使用可能ですが、他のページでは使用できませんので、直接数字を入れます。
・product_idは、商品詳細ページURLに表示されているとおり、「pid=」以下の数字。
・user_hash、members_hashは、そのままでOK。サーバーがユーザーを認識するための一連のやりとり、というくらいのイメージで。
・shop_idは、カラーミーショップ!プロのメニュー「オーナー情報」内にある「アカウントID」。

実際に試してみると、たしかに機能してそうです。
商品一覧ページに「カートに入れる」ボタンがあると便利よさそうと、思っていたので、これはつかえるかもしれません。それにしても、こんなことができるとは……勉強になりました。


【追記】 input type="hidden"としてサーバに送っているパラメータは、formタグ内の <{$product.info}> を展開したもの。 それゆえに、この独自タグがないと、カートが動かないのです。
【追記】オプションがある場合について、匿名さんが下にコメントを残してくれています。商品詳細ページに飛ばすという方法がシンプルでよいと思います。
カラーミー以外では、モーダルウィンドウで入力させる画面を表示している、カートもあります。

【関連記事】
カラーミーにできること、できないこと

2010年8月14日

Twitterでつぶやく

ありとあらゆる方面で流行中のTwitterですが、カラーミーショップ!プロを使っているクライアント様から、つぶやきボタンをつけてほしいと依頼がありました。
Twitter機能自体をそれほど詳しくない(そもそもほとんど使ったことがなかった)ので、どんな使われ方がされて、どんなことができるか要調査が必要かもしれません。もうしばらくはオンラインショップでも重要なツールとして使われるかもしれませんので。
ではさっそく、サンプルから。
<a href="http://twitter.com/home?status=http://www.hogehoge.com/?pid=<{$product.id}>" target="_blank"><img src="http://twitter-badges.s3.amazonaws.com/t_mini-b.png" alt="Twitterでつぶやく"></a>
Twitterボタンは、サンプルとして公式から参照しています。

現在閲覧中の商品ページのURLを貼ればOKという依頼でしたので、これで終了。さほど大層なものではありません。product.idの部分は、JavaScriptのlocation.hrefを使用しても良いかもしれません。
ただ、 これにプラスして、商品名もつけてほしいといわれると状況は変わるようです。

Color Me Shop! pro - 助け合い掲示板」をみると、全角文字が文字化けするそうです。
 Escape Codec Library:ecl.jp のライブラリで、EUC-JP→UTF-8変換が必要とのこと。

変換なしで試してみると、「Invalid Unicode value in one or more parameters」とエラーメッセージ。Webページのソースをのぞいてみると、たしかに、TwitterがUTF-8で、カラーミーショップ!プロがEUC-JPでした。
設置方法の詳細は上記リンクにありますので、そちらをご参照下さい。


【参照リンク】
「かぐや東京」さまのWebサイト(Twitterボタンが搭載されている家具屋さん)

【追記】
古い記事になりましたので、「ツイートする 2」 で情報更新しました。