1: Pepper.html
2:
3: ?<html lang="ja" >
4: <head>
5: <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
6: <title>Gadgets Pepper</title>
7: <link href="HotStyle.css" rel="stylesheet" type="text/css" />
8: <script src="http://maps.google.com/maps?file=api&v=2&key=(API KEY)" type="text/javascript" charset="utf-8"></script>
9: <script type="text/javascript" src="HotScript.js"></script>
10: <script type="text/javascript">
11: var urlGourmetSearch = "http://www.tkrb.jp/cgi-bin/pepper/GourmetSearch.cgi";
12: var urlGenreMaster = "http://www.tkrb.jp/cgi-bin/pepper/Genre.cgi";
13: var googleMaps = null;
14: var shopNodeList = null;
15: var curShopNode = 0;
16: var geocoder = null;
17: var lastSearchPoint = null;
18: var lastSearchGenre = null;
19: var initCenter = new GLatLng( 35.681074, 139.767079 );
20: var initZoom = 13;
21: var curSkin = 1;
22: var idIntervalTimer = null;
23:
24: // お店検索、ジャンル一覧を初期化する
25: // HTTP Requestを実行し、onGenreLoadで処理
26: //
27: function initializeGenre(){
28: try{
29: var oReq = createHttpRequest();
30: oReq.onreadystatechange = function(){
31: if( oReq.readyState==4 ){
32: onGenreLoad( oReq );
33: }
34: }
35: oReq.open( "GET", urlGenreMaster );
36: oReq.send( null );
37: }
38: catch( e ){window.alert( "initializeGenre" );}
39: }
40:
41: // HTML bodyのロード時
42: // 各種初期化処理
43: //
44: function load() {
45: try{
46: // Google Mapsの作成
47: initCenter = new GLatLng( 35.681074, 139.767079 );
48: initZoom = 13;
49: loadState();
50: if( GBrowserIsCompatible() ){
51: googleMaps = new GMap2( document.getElementById( "map" ) );
52: googleMaps.addControl( new GSmallMapControl() );
53: googleMaps.enableScrollWheelZoom();
54: geocoder = new GClientGeocoder();
55: }
56: initializeGenre(); // ジャンル一覧の初期化
57: setDockState();
58: // 最後の状態を復元
59: if( lastSearchPoint != null ){
60: googleMaps.setCenter( lastSearchPoint, initZoom, G_NORMAL_MAP );
61: findAtPoint( lastSearchPoint, lastSearchGenre );
62: }
63: else{
64: googleMaps.setCenter( initCenter, initZoom, G_NORMAL_MAP );
65: }
66: idIntervalTimer = setInterval( "showCurrentTime()", 1000 );
67: }
68: catch( e ){}
69: }
70:
71: // HTML bodyのアンロード時
72: //
73: function unload(){
74: saveState(); // 状態の保存
75: GUnload(); // Google Mapsの終了処理
76: }
77:
78: // クッキーの設定
79: //
80: function setCookie(fieldId,value){
81: var expires = new Date()
82: expires.setTime(expires.getTime() + (1*24*60*60*1000))
83: document.cookie=fieldId+"="+escape(value)+"; expires="+expires.toGMTString()
84: }
85:
86: // クッキーの取得
87: //
88: function getCookie(fieldId){
89: var tmp=(document.cookie+";").match(fieldId+"=([^;]*);")
90: if(tmp!=null){
91: return unescape(tmp[1])
92: }else{
93: return null
94: }
95: }
96:
97: // 状態の保存
98: //
99: function saveState(){
100: try{
101: var zl = googleMaps.getZoom();
102: setCookie( "zoom_level", zl );
103: if( lastSearchPoint != null ){
104: setCookie( "search_latitude", lastSearchPoint.y );
105: setCookie( "search_longitude", lastSearchPoint.x );
106: }
107: if(lastSearchGenre != null ){
108: setCookie( "search_genre", lastSearchGenre );
109: }
110: setCookie( "skin_number", curSkin );
111: }
112: catch( e ){}
113: }
114:
115: // 保存した状態の読み込み
116: //
117: function loadState(){
118: try{
119: var skin_number = getCookie( "skin_number" );
120: if( ! isNullOrEmpty( skin_number ) )
121: curSkin = parseInt( skin_number, 10 );
122: var zoom_level = getCookie( "zoom_level" );
123: if( ! isNullOrEmpty( zoom_level ) )
124: initZoom = parseInt( zoom_level, 10 );
125: var search_latitude = getCookie( "search_latitude" );
126: var search_longitude = getCookie( "search_longitude" );
127: lastSearchGenre = getCookie( "search_genre" );
128: if( ! isNullOrEmpty( search_latitude ) && ! isNullOrEmpty( search_longitude ) )
129: lastSearchPoint = new GLatLng( parseFloat( search_latitude ), parseFloat( search_longitude ) );
130: }
131: catch( e ){}
132: }
133:
134: // ジャンル一覧のデータ取得
135: //
136: function onGenreLoad( oReq ){
137: try{
138: var elmSel = document.getElementById( "genreSelect" );
139: var oXMLDocument = oReq.responseXML;
140: genreNodeList = oXMLDocument.getElementsByTagName( "Genre" );
141: if( genreNodeList == null )
142: return;
143: for( var i = 0 ; i < genreNodeList.length ; i++ ){
144: var node = genreNodeList.item( i );
145: var ndName = node.getElementsByTagName( "GenreName" );
146: var ndCD = node.getElementsByTagName( "GenreCD" );
147: if( ndName.length > 0 && ndCD.length > 0 ){
148: var opt = document.createElement( "OPTION" );
149: opt.text = ndName.item(0).firstChild.nodeValue;
150: opt.value = ndCD.item(0).firstChild.nodeValue;
151: elmSel.options.add( opt );
152: if( opt.value == lastSearchGenre )
153: opt.selected = true;
154: }
155: }
156: }
157: catch( e ){}
158: }
159:
160: // 時刻表示のための書式規格化
161: //
162: function format(Num, Format){
163: var s = new String(Num);
164: var z = "";
165: for(c = 0 ; c < Format - s.length ; c++){
166: z = z + "0";
167: }
168: return (z + s);
169: }
170:
171: // 現在時刻の表示
172: //
173: function showCurrentTime(){
174: var date = new Date();
175: var y = date.getFullYear();
176: var mo = date.getMonth();
177: var d = date.getDate();
178: var h = date.getHours();
179: var m = date.getMinutes();
180: var s = date.getSeconds();
181: document.getElementById( "timeView" ).innerHTML = format(y,4) + "." + format(mo+1,2) + "." + format(d,2) + " " + format(h,2) + ":" + format(m,2);
182: }
183:
184: // 緯度経度による、お店の検索
185: //
186: function findAtPoint( pt, genre ){
187: try{
188: if( document.getElementById("shop").style.visibility == "visible" )
189: return;
190: var oReq = createHttpRequest();
191: oReq.onreadystatechange = function(){
192: if( oReq.readyState==4 ){
193: onXmlLoad( oReq );
194: }
195: }
196: var url = urlGourmetSearch + "?Latitude=" + pt.y + "&Longitude=" + pt.x;
197: if( ! isNullOrEmpty( genre ) )
198: url = url + "&GenreCD=" + genre;
199: oReq.open( "GET", url, true );
200: oReq.send( null );
201: }
202: catch( e ){}
203: }
204:
205: // お店検索の実行
206: //
207: function onFindShops(){
208: try{
209: lastSearchPoint = googleMaps.getCenter();
210: lastSearchGenre = document.getElementById( "genreSelect" ).value;
211: findAtPoint( lastSearchPoint, lastSearchGenre );
212: }
213: catch( e ){}
214: }
215:
216: // 住所検索のためのキーダウン処理
217: //
218: function onKeydown(){
219: if(event.keyCode == 13){findAddress();}
220: }
221:
222: // 住所検索
223: //
224: function findAddress(){
225: try{
226: if( document.getElementById("shop").style.visibility == "visible" )
227: return;
228: var address = document.getElementById( "address" ).value;
229: if( isNullOrEmpty( address ) )
230: return;
231: if (geocoder) {
232: geocoder.getLatLng(address,function(point) {
233: if (!point) {
234: alert(address + " not found");
235: } else {
236: googleMaps.setCenter(point);
237: }
238: });
239: }
240: }
241: catch( e ){document.writeln( e );}
242: }
243:
244: // 地図上へのマーカーの追加
245: //
246: function addMarker( pt, idx ){
247: var marker = new GMarker( pt );
248:
249: GEvent.addListener( marker, "click", function(){
250: setShopInfo( idx );
251: });
252: googleMaps.addOverlay( marker );
253: }
254:
255: // お店一覧のXMLデータ、読み込み処理
256: //
257: function onXmlLoad( oReq ){
258: try{
259: var oXMLDocument = oReq.responseXML;
260: shopNodeList = oXMLDocument.getElementsByTagName( "Shop" );
261: if( shopNodeList == null )
262: return;
263: googleMaps.clearOverlays();
264: for( var i = 0 ; i < shopNodeList.length ; i++ ){
265: var node = shopNodeList.item(i);
266: var ndLatitude = node.getElementsByTagName( "Latitude" );
267: var ndLongitude = node.getElementsByTagName( "Longitude" );
268: if( ndLatitude.length > 0 && ndLongitude.length > 0 ){
269: var latitude = parseFloat( ndLatitude.item(0).firstChild.nodeValue );
270: var longitude = parseFloat( ndLongitude.item(0).firstChild.nodeValue );
271: addMarker( new GPoint( longitude, latitude ), i );
272: }
273: }
274: }
275: catch( e ){}
276: }
277:
278: // お店情報を表示設定する
279: //
280: function setShopInfo( idx )
281: {
282: if( shopNodeList == null || idx < 0 || shopNodeList.length <= idx )
283: return;
284: curShopNode = idx;
285: document.getElementById("shop").style.visibility = "visible";
286: node = shopNodeList.item( idx );
287: var ndShopName = node.getElementsByTagName( "ShopName" );
288: var ndShopURL = node.getElementsByTagName( "ShopUrl" );
289: var ndGenreCatch = node.getElementsByTagName( "GenreCatch" );
290: var ndPictureURL = ndPictureURL = node.getElementsByTagName( "PcLargeImg" );
291: if( ndShopName.length > 0 )
292: document.getElementById( "shopName" ).innerHTML = ndShopName.item(0).firstChild.nodeValue;
293: if( ndShopURL.length > 0 )
294: document.getElementById( "shopName" ).setAttribute( "href", ndShopURL.item(0).firstChild.nodeValue );
295: if( ndGenreCatch.length > 0 )
296: document.getElementById( "genreCatch" ).innerHTML = ndGenreCatch.item(0).firstChild.nodeValue;
297: if( ndPictureURL.length > 0 )
298: document.getElementById( "shopPicture" ).setAttribute( "src", ndPictureURL.item(0).firstChild.nodeValue );
299: if( ( curShopNode + 1 ) < shopNodeList.length )
300: document.getElementById("btnNext").style.visibility = "inherit";
301: else
302: document.getElementById("btnNext").style.visibility = "hidden";
303: if( curShopNode > 0 )
304: document.getElementById("btnPrev").style.visibility = "inherit";
305: else
306: document.getElementById("btnPrev").style.visibility = "hidden";
307: }
308:
309: // 前のお店情報に移動する
310: //
311: function prevShop(){
312: if( curShopNode > 0 ){
313: setShopInfo( curShopNode -1 );
314: }
315: }
316:
317: // 次のお店情報に移動する
318: //
319: function nextShop(){
320: if( ( curShopNode + 1 ) < shopNodeList.length ){
321: setShopInfo( curShopNode + 1 );
322: }
323: }
324:
325: // お店情報表示を閉じる
326: //
327: function closeShopInfo(){
328: document.getElementById("shop").style.visibility = "hidden";
329: }
330:
331: // 背景の状態を設定する
332: //
333: function setDockState(){
334: switch( curSkin ){
335: case 2:
336: document.getElementById( "base").style.background = "url(images/b2.png)";
337: document.getElementById( "timeView" ).style.color = "#0f0f0f";
338: break;
339: case 3:
340: document.getElementById( "base").style.background = "url(images/b3.png)";
341: document.getElementById( "timeView" ).style.color = "#ffff80";
342: break;
343: case 4:
344: document.getElementById( "base").style.background = "url(images/b4.png)";
345: document.getElementById( "timeView" ).style.color = "#0f0f0f";
346: break;
347: case 5:
348: document.getElementById( "base").style.background = "url(images/b5.png)";
349: document.getElementById( "timeView" ).style.color = "#0f0f0f";
350: break;
351: default:
352: document.getElementById( "base").style.background = "url(images/b1.png)";
353: document.getElementById( "timeView" ).style.color = "#0f0f0f";
354: break;
355: }
356: }
357:
358: // 背景設定画面を表示する
359: //
360: function showSettings(){
361: document.getElementById( "settings" ).style.visibility = "visible";
362: document.getElementById("genreSelect").style.visibility = "hidden";
363: switch( curSkin ){
364: case 2:
365: document.getElementById( "skin2" ).checked = true;
366: break;
367: case 3:
368: document.getElementById( "skin3" ).checked = true;
369: break;
370: case 4:
371: document.getElementById( "skin4" ).checked = true;
372: break;
373: case 5:
374: document.getElementById( "skin5" ).checked = true;
375: break;
376: default:
377: document.getElementById( "skin1" ).checked = true;
378: break;
379: }
380: }
381:
382: // 背景設定画面を閉じる
383: //
384: function closeSettings( bSave ){
385: if( bSave ){
386: if( document.getElementById( "skin1" ).checked )
387: curSkin = 1;
388: else if( document.getElementById( "skin2" ).checked )
389: curSkin = 2;
390: else if( document.getElementById( "skin3" ).checked )
391: curSkin = 3;
392: else if( document.getElementById( "skin4" ).checked )
393: curSkin = 4;
394: else if( document.getElementById( "skin5" ).checked )
395: curSkin = 5;
396: setDockState();
397: }
398: document.getElementById( "settings" ).style.visibility = "hidden";
399: document.getElementById("genreSelect").style.visibility = "visible";
400: }
401: </script>
402:
403: </head>
404: <body onload="load()" onunload="unload()">
405: <div id="base">
406: <table width="312px" style="height: 34px;">
407: <tr>
408: <td style="width: 132;">
409: </td>
410: <td align="right">
411: <b><span id="timeView"></span></b>
412: </td>
413: <td align="right">
414: <img src="images/settings.png" alt="設定" style="cursor:hand;" onclick="showSettings()" />
415: </td>
416: </tr>
417: </table>
418: <table cellpadding="0" cellspacing="0" width="312px">
419: <tr valign="baseline">
420: <td align="left">
421: <input id="address" type="text" style="width:190px;" onKeyDown="onKeydown()"/>
422: </td>
423: <td align="right">
424: <img src="images/button1.png" alt="住所やスポットで検索" style="cursor:hand;" onclick="findAddress()" id="findShop" />
425: </td>
426: </tr>
427: </table>
428: <div id="map" onmousedown=""></div>
429: <table cellpadding="0" cellspacing="0" width="312px">
430: <tr valign="baseline">
431: <td align="left">
432: <select id="genreSelect" style="width:190px;">
433: <option value="" >全てのジャンル</option>
434: </select>
435: </td>
436: <td align="right">
437: <img src="images/button2.png" alt="お店情報読込" style="cursor:hand;" onclick="onFindShops()" />
438: </td>
439: </tr>
440: <tr>
441: <td align="right" colspan="2">
442: <div id="poweredby" style="color:#363636;font-size: 9px; text-align:right;" >Powered by ホットペッパー.jp</div>
443: </td>
444: </tr>
445: </table>
446: </div>
447: <div id="shop" style="width:290px; height:200px;">
448: <table width="290px" cellpadding="0" cellspacing="0" >
449: <tr valign="top">
450: <td align="right">
451: <img align="top" src="images/close.png" alt="閉じる" style="cursor: hand;" onclick="closeShopInfo()" /></td>
452: </tr>
453: <tr valign="top">
454: <td style="font-size: 13px;">
455: <a id="shopName" target="_blank"></a>
456: </td>
457: </tr>
458: </table>
459: <table id="shopTable" width="290px" cellpadding="0" cellspacing="4">
460: <tr valign="top">
461: <td width="10px">
462: <img id="shopPicture" src="" alt="写真" width="120px" height="120px" /></td>
463: <td align="center" style="font-size: 13px;">
464: <span id="genreCatch"></span>
465: </td>
466: </tr>
467: </table>
468: <table width="290px" border="0" cellpadding="0" cellspacing="0">
469: <tr valign="bottom">
470: <td align="left">
471: <img id="btnPrev" src="images/prev.png" style="cursor: hand;" onclick="prevShop()"
472: alt="戻る" />
473: </td>
474: <td align="right">
475: <img id="btnNext" src="images/next.png" style="cursor: hand;" onclick="nextShop()"
476: alt="次へ" />
477: </td>
478: </tr>
479: </table>
480: </div>
481: <div id="settings">
482: <table id="settingsTable" >
483: <tr><td colspan="4">
484: <h3>
485: 背景の選択</h3>
486: </td></tr>
487: <tr style="height:8px"><td></td><td></td><td></td><td></td></tr>
488: <tr valign="top">
489: <td>
490: <input id="skin1" name="skinSelect" type="radio" value="1" /></td>
491: <td onclick="skin1.checked=true;">
492: <img src="images/b1.png" alt="背景1" width="64px" height="64" />
493: </td>
494: <td>
495: <input id="skin4" name="skinSelect" type="radio" value="4" /></td>
496: <td onclick="skin4.checked=true;">
497: <img src="images/b4.png" alt="背景4" width="64px" height="64" />
498: </td>
499: </tr>
500: <tr valign="top">
501: <td>
502: <input id="skin2" name="skinSelect" type="radio" value="2" /></td>
503: <td onclick="skin2.checked=true;">
504: <img src="images/b2.png" alt="背景2" width="64px" height="64" />
505: </td>
506: <td>
507: <input id="skin5" name="skinSelect" type="radio" value="5" /></td>
508: <td onclick="skin5.checked=true;">
509: <img src="images/b5.png" alt="背景5" width="64px" height="64" />
510: </td>
511: </tr>
512: <tr valign="top">
513: <td>
514: <input id="skin3" name="skinSelect" type="radio" value="3" /></td>
515: <td onclick="skin3.checked=true;">
516: <img src="images/b3.png" alt="背景3" width="64px" height="64" />
517: </td>
518: <td></td><td></td>
519: </tr>
520: <tr style="height:8px"><td></td><td></td><td></td><td></td></tr>
521: <tr><td colspan="4" align="center">
522: <input type="button" onclick="closeSettings( true )" value="OK" style="width:96px" />
523:
524: <input type="button" onclick="closeSettings( false )" value="キャンセル" style="width:96px" />
525: </td></tr>
526: </table>
527: </div>
528: </body>
529: </html>
料理ジャンルの一覧を初期化します。ジャンルマスターAPIを呼び出すHTTP Requestを実行し、取得したXMLデータをonGenreLoad()内で処理します。
HTML bodyがロードされた際に、各種初期化処理を行います。GMap2オブジェクトの生成および地図の初期表示、GClientGeocoderオブジェクトの生成、料理ジャンルの一覧の初期化、背景画像の設定、時計表示のためのインターバルタイマーの設定。ガジェットが前回終了した時の状態を復帰する処理も行います。
HTML bodyがアンロードされた時に、アプリケーションの状態を保存します。
最後に検索された場所の緯度経度、料理ジャンルをCookieに保存します。
最後に検索された場所の緯度経度、料理ジャンルをCookieから取得します。
アプリケーションの状態を保存します。保存されるのは、最後に検索された検索の条件(緯度経度、料理ジャンル)と背景画像の番号です。
保存したアプリケーションの状態を読み込みます。
ジャンルマスターを含むXMLデータを処理します。GenreName(ジャンル名)ノード、GenreCD(ジャンルコード)ノードの値をHTMLのOPTION要素に設定し、プルダウンメニューを設定します。
現在時刻の表示を更新します。
緯度経度、料理ジャンルを指定して、グルメサーチAPIを呼び出します(お店を検索します)。HTTP Requestで取得したデータはonXmlLoad()で処理します。
「読込」ボタンが押されたときに呼び出されます。地図中心の緯度経度、選択されている料理ジャンルを取得し、findAtPoint()を実行します。
住所検索時のリターンキーを処理します。キーコードが13であれば、findAddress()を実行します。
ジオコーダーGClientGeocorderを用い住所を緯度経度に変換します。変換できればその位置に地図中心点を移動、変換できなかった場合はエラーメッセージを表示します。
地図にマーカーを追加します。addListenerメソッドで、マーカーがクリックされた時にsetShopInfo()が呼ばれるようにします。
グルメ検索APIの結果データを処理します。Shop(グルメ店)ノードを詳細画面表示用に保存します。また、Latitude(緯度)ノードとLongitude(経度)ノードを使い、地図にグルメ店マーカーを追加します。
onXmlLoad()内で保存したShop(グルメ店)ノードのリストから、idx番目のお店の情報を表示します。ShopName(店名)、ShopUrl(店URL)、GenreCatch(店キャッチコピー)、PcLargeImg(店画像URL)の各ノードの値を取得し、該当するHTML要素にセット。グルメ店詳細情報の表示は、div要素のvisibilityスタイルをhiddenからvisibleに変えることで行います。
idxの値により「前へ」「次へ」ボタンの表示、非表示を制御します。
表示されているグルメ店詳細情報を閉じます。グルメ店詳細情報のdiv要素をhiddenにします。
背景画像を設定します。
背景画像の設定画面を表示します。設定画面の表示は、グルメ店詳細情報の表示と同様、div要素のvisibilityスタイルをhiddenからvisibleに変えることで行います。
背景画像の設定画面を閉じます。設定画面のdiv要素をhiddenにします。
|