Cigazine - ソースコード
説明
「Cigazine」は、「Web AI」を使ったWebアプリです。このページでは、この「Cigazine」を作るために書いたプログラムを掲載します。
「Web AI」は、クロノス・クラウンの柳井政和が開発しているJavaScirptのライブラリです。「Web AI」を使うと、Web上からデータを取得して構築するWebページを、とても簡単に構築することができます。
「Web AI」は、Webからの検索結果やフィードの取得、短縮URLへのURLの変換、日本語文章からのキーワードや文章抽出、日本語文章のマルコフ連鎖、クエリーの管理などの機能を備えています。
コアとなる「WebSrch」オブジェクトでは、非同期で行われる通信処理に対して、その結果を待ちながら順番に処理していくプログラムを簡単に書くことができます。また、本ライブラリでは「Google AJAX Search API」を抽象化して、検索データを手軽にプログラムに読み込んで利用できるようにしています。
「Cigazine」は、この「Web AI」のサンプルとして作成しました。このWebアプリを作成したソースコードを見れば、その簡単さがよく分かると思います。それでは以下に、ソースコードを掲載します。
ソースコード
まずは、HTMLのヘッダー部分のソースコードです。
<!-- Google API --> <script src="http://www.google.com/jsapi" type="text/javascript"></script> <!-- Web AI API --> <script src="crocro.webAi.min.js" type="text/javascript" charset="UTF-8"></script> <!-- ScriptThis --> <script src="app.js" type="text/javascript" charset="UTF-8"></script>
次に、Webアプリ本体部分になる「app.js」のソースコードを掲載します。
/** * 【変数の初期化】 */ // Googleからスクリプトをロード google.load("search", "1"); google.load("feeds", "1"); google.load("jquery", "1.4.3"); // Web AIの初期化 var $WA = crocro.webAi; // 短縮表記 var cQ = new $WA.Query(); // クエリー var cWSrch = new $WA.WebSrch(); // Web検索用 var cISrch = new $WA.WebSrch(); // 画像検索用 var cJpKw = new $WA.JpKw(); // キーワード var cJpSntnc = new $WA.JpSntnc(); // センテンス var qKeyQckSrch = "qckSrch"; // 急速検索 var loadAnmArr // ロード中アニメ配列 = [".(^o^).", "(^o^)..", "^o^)..(", "o^)..(^", "^)..(^o", ")..(^o^", "..(^o^)"]; var loadAnmCnt = 0; // ロード中アニメ・カウンター var appNm = "Cigazine(滋賀人)"; /* *-------------------------------------------------- */ /** * 【初期化処理】 */ cWSrch.ready(function(){ // デフォルトの固定URLを作成 $("#fix_url_raw").val(getUrlBs()); $("#fix_url_min").val(getUrlBs()); setSclUrl(getUrlBs()); // ソーシャル系URL設定 setTimeout(loadDelay, 1000); // 遅延読み込み // クエリーの初期化 cQ.prsFrmLocation({useH: true}); // 検索結果出力先の追加 var deco = function(r) { if ("unescapedUrl" in r) return r.unescapedUrl + "\n"; return ""; } cISrch.appndResTgt = "vwSrchRes"; cWSrch.appndResTgt = "vwSrchRes"; cISrch.appndResDeco = deco; cWSrch.appndResDeco = deco; // 画像検索用WebSrchを初期化 cISrch.init({type : "img"}).start(); // Web検索用WebSrchを初期化 cWSrch .brand("gglBrnd") .init({ type : "nws", opt : function(obj) { obj.setResultSetSize(google.search.Search.LARGE_RESULTSET); // 8件 } }) .feed({ // 最新ニュースのキーワードリストを取得 url : "http://www.google.co.jp/trends/hottrends/atom/hourly", res : function(res) { // エラー確認 if (res.error) return; // エラーなので終了 // キーワードの取得 var contentStr = res.feed.entries[0].content; var getArr = contentStr.match(/>[^\w\n]+?</g); if (! getArr instanceof Array) return; // エラーなので終了 getArr = $.map(getArr, function(n, i){ return n.replace(/[<>]/g, ""); }); // HTMLの作成 for (var i = 0; i < getArr.length; i ++) { // URL作成 var urlStr = "" + ($WA.Tools.isLocal() ? "#" : "?") // ローカルの場合は# + qKeyQckSrch + "=" + encodeURIComponent(getArr[i]); // HTML作成 var htmlStr = '<span class="newItm">' + '<a href="' + urlStr + '">' + getArr[i] + '</a>' + '</span>'; getArr[i] = htmlStr } // HTMLの挿入 $("#newLst").html(getArr.join(" ")); } }); if (cQ.get(qKeyQckSrch) != "") { // 急速検索がある場合は、検索処理を追加 cWSrch .add(function() { $("#q").val(cQ.get(qKeyQckSrch)); // キーワードを設定 strtSrch(); // 検索開始 }); } else if (cQ.get("kw") != "" && cQ.get("dt") != "" && cQ.get("ttl") != "" && cQ.get("kws") != "" && cQ.get("bdy") != "" ) { cWSrch .add(function() { // 復帰用のデータがあるので画面を復帰 $("#q").val(cQ.get("kw")); // キーワードを設定 $("#resVw").html(qry2News(cQ)); // クエリーを記事に kw2Img(); // 画像の挿入 setSclUrl(location.href); // ソーシャル系URL設定 }); } cWSrch .setEachCall(function(){ // ステップごとに呼び出される処理を追加 drwLoadAnm(true); // ロードアニメ描画 }) .start(); }); /* *-------------------------------------------------- */ /** * @title 【検索開始】 * @description * * 検索を実行する。ボタンから呼び出す。 */ function strtSrchBtn() { // 実行中回避処理 if (cWSrch.isExec) { alert("現在、検索中です。\n\n少々お待ち下さい。"); return; } // 検索実行 cWSrch.reset(); strtSrch(); cWSrch.start(); } function strtSrch() { // 変数の初期化 var kwStrt = $("#q").val(); // 開始キーワード var kwGetArr = []; // 収集キーワード配列 var cQRes = new $WA.Query(); // 結果クエリー // 開始キーワードのトリム kwStrt = kwStrt.replace(/^[ ]+|[ ]$/g, ""); // オブジェクトの内容のリセット cJpKw.reset(); // 日本語キーワードオブジェクトの内容をリセット cJpSntnc.reset(); // 日本語文章オブジェクトの内容をリセット // 検索処理 cWSrch .srch({ // ニュースを検索して、キーワードと文章を収集 type : "nws", page : 4, key : kwStrt, res : function(res, cursor) { if (! res || res.length <= 0) return; // 結果なし // 結果あり for (var i = 0; i < res.length; i ++) { var r = res[i]; cJpKw.addSrc(r.titleNoFormatting); // キーワード用に文字列を追加 cJpSntnc.addSntnc(r.content); // 文章用に文字列を追加 } } }) .add(function() { // 収集した文章からキーワード配列を取得 kwGetArr = cJpKw.getStrArr(); }) .srch({ // さらにニュースを検索して、キーワードと文章を収集 type : "nws", page : 2, loop : function() { return (kwGetArr.length >= 4) ? 4 : kwGetArr.length; }, key : function() { return kwGetArr[cWSrch.loopCnt]; }, res : function(res, cursor) { if (! res || res.length <= 0) { // 結果なし(通信エラー発生の可能性あり) cWSrch.loopBreak(); } else { // 結果あり for (var i = 0; i < res.length; i ++) { var r = res[i]; cJpKw.addSrc(r.titleNoFormatting); // キーワード用に文字列を追加 cJpSntnc.addSntnc(r.content); // 文章用に文字列を追加 } } } }) .add(function() { // 文章配列を取得 var sArr = cJpSntnc.getSntncArr(); var kwArr = cJpKw.getStrArr(); // 本文用文章配列 var bdySArr = $.grep(sArr, function(n, i){ return n.match("[るただい]$"); // 使えそうな文章か判定 }); // タイトル用文章配列 var ttlSArr = $.map(sArr, function(n, i){ n = n.replace(/[^一-龠ァ-ヶー]+$/, ""); var chk = n.match("[一-龠ァ-ヶー]{2}$"); if (chk) return n return null; }); ttlSArr = cJpSntnc.sortLen(ttlSArr, 40); // 40文字位置でソート // 検索文字が含まれるタイトル候補を検索 var strTtlSrch = null; for (var i = 0; i < ttlSArr.length; i ++) { if (ttlSArr[i].indexOf(kwStrt) >= 0) { strTtlSrch = ttlSArr[i]; break; } } // 記事用データをクエリーへ格納 cQRes.set("kw", kwStrt); cQRes.set("dt", getDateStr(new Date())); cQRes.set("ttl", strTtlSrch || ttlSArr[0]); cQRes.set("kws", kwArr.slice(0, 3).join("\n")); cQRes.set("bdy", bdySArr.slice(0, 6).join("\n")); // 記事を出力 $("#resVw").html(qry2News(cQRes)); // クエリーを記事に cJpKw.avoidStr = kwStrt; // 無視文字列 cJpKw.bsUrl = ($WA.Tools.isLocal() ? "#" : "?") + qKeyQckSrch + "="; cJpKw.outKw("kwLst", { // キーワードリスト挿入 clsNm : "kwItm", wrpFnc : function(s) {return '<nobr>' + s + '</nobr>'} }); kw2Img(); // 画像の挿入 // 固定URLを作成 var urlStr = getUrlBs(); // URL基本部分取得 urlStr += "?" + cQRes.getCmprsQuery(); // 圧縮をかけたクエリーを取得 $("#fix_url_raw").val(urlStr); setSclUrl(urlStr); // ソーシャル系URL設定 // 検索の終了 drwLoadAnm(false); // ロードアニメ描画 }); } /* *-------------------------------------------------- */ /** * @title 【日付文字列取得】 * @description * * 日付オブジェクトを元にして、日付文字列を作成して取得する。 * * @param d 日付オブジェクト * @return 日付文字列 */ function getDateStr(d) { var resStr = d.getFullYear() + "年" + (d.getMonth() + 1) + "月" + d.getDay() + "日" + " " + d.getHours() + "時" + d.getMinutes() + "分" + d.getSeconds() + "秒" return resStr; } /** * @title 【URL基本部分取得】 * @description * * URLの本体を取得。 * * @return URLの本体部分 */ function getUrlBs() { var urlStr = "http://www.google.com/"; // ダミー if (! $WA.Tools.isLocal()) { // ネット上なので、URLをそのまま利用 urlStr = location.href.replace(/\?.*$|#.*$/g, ""); // 本体部分のみ取得 } return urlStr; } /** * @title 【クエリーからニュース作成】 * @description * * クエリーを元にして、ニュース記事のHTMLを作成する。 * * @param q クエリー・オブジェクト * @return HTML文字列 */ function qry2News(q) { // エラー対策 if (q.get("dt") == "") return; if (q.get("ttl") == "") return; if (q.get("kws") == "") return; if (q.get("bdy") == "") return; // 変数の初期化 var resStr = ""; var kwArr = q.get("kws").split("\n"); var bdyArr = q.get("bdy").split("\n"); // HTMLの作成 resStr += wrpDiv(q.get("dt") + " 更新", "itm_date"); resStr += wrpDiv(q.get("ttl"), "itm_hdr"); for (var i = 0; i < 4; i ++) { if (i < kwArr.length) { // 画像 resStr += wrpDiv(wrpDiv(kwArr[i], "imgRep"), "itm_img"); } var bdyStr = ""; if (i * 2 < bdyArr.length) bdyStr += bdyArr[i * 2 ] + "。"; // 本文奇数 if (i * 2 + 1 < bdyArr.length) bdyStr += bdyArr[i * 2 + 1] + "。"; // 本文偶数 if (bdyStr != "") resStr += wrpDiv(bdyStr, "itm_bdy"); } resStr += wrpDiv(q.get("dt") + " in " + kwArr[0], "itm_ftr"); resStr = wrpDiv(resStr, "itm_out"); return resStr; } function wrpDiv(inSTr, cls) { if (! cls) cls= ""; var resStr = ""; resStr += '<div class="' + cls + '">'; resStr += inSTr; resStr += '</div>'; return resStr; } /** * @title 【ロードアニメ描画】 * @description * * ロード中のアニメを描画する。 * * @param loading ロード中か否か * @return なし */ function drwLoadAnm(loading) { var dwStr = "" if (loading) { dwStr = "Now Loading... " + loadAnmArr[loadAnmCnt ++ % loadAnmArr.length]; } $("#loading").text(dwStr); } /** * @title 【ソーシャル系URL設定】 * @description * * ソーシャル系のサービスのウィジットにURLを指定する。 * * @param urlStr URL文字列 * @return なし */ function setSclUrl(urlStr) { // ローカル時は無効 if ($WA.Tools.isLocal()) return; // 引数を解析 var cQSrc = new $WA.Query(); cQSrc.prsFrmUrl({url: urlStr}); var kw = cQSrc.get("kw"); // 変数の初期化 var cQTmp; var urlTmp; // AddClip ブックマーク用URL AddClipsUrl = urlStr; // Twitter用URL cQTmp = new $WA.Query(); // クエリ解析用 cQTmp.prsFrmUrl({url: $(".twitter-share-button").attr("src")}); cQTmp.set("url", urlStr); cQTmp.set("text", appNm + " - 「" + kw + "」についての記事"); $(".twitter-share-button").attr("src", cQTmp.getUrl()); // Facebookシェア用URL cQTmp = new $WA.Query(); // クエリ解析用 cQTmp.prsFrmUrl({url: $("#fcbkShare").attr("href")}); cQTmp.set("u", urlStr); $("#fcbkShare").attr("href", cQTmp.getUrl()); // Facebookいいね用URL cQTmp = new $WA.Query(); // クエリ解析用 cQTmp.prsFrmUrl({url: $("#fcbkLike").attr("src")}); cQTmp.set("href", urlStr); $("#fcbkLike").attr("src", cQTmp.getUrl()); // はてブ用URL var htbEntryAdd = "http://b.hatena.ne.jp/entry/add/" + urlStr; var htbEntryUrl = "http://b.hatena.ne.jp/entry/" + urlStr; var htbEntryImg = "http://b.hatena.ne.jp/entry/image/" + urlStr; $("#htbEntryAdd").attr("href", htbEntryAdd); $("#htbEntryUrl").attr("href", htbEntryUrl); $("#htbEntryImg").attr("src", htbEntryImg); } /* *-------------------------------------------------- */ /** * @title 【キーワードをイメージに置換】 * @description * * 画像置換クラスで囲われたキーワードを画像に置換する。 * * @return なし */ function kw2Img() { // 画像キーワードの取得 var imgRep = []; $(".imgRep").each(function(){ imgRep.push($(this)); }); var imgRepSz = imgRep.length; // 検索処理 cISrch .reset() .srch({ // 画像を検索して、キーワードを置換する type : "img", loop : imgRepSz, key : function(){return imgRep[cISrch.loopCnt].text();}, res : function(res, cursor) { if (res && res.length <= 0) return; // 結果なし // 結果あり var r = res[0]; // HTML文字列の作成 var htmlStr = ""; htmlStr += '<img src="' + r.tbUrl + '"' + ' width=' + (r.tbWidth * 1.5) + ' height=' + (r.tbHeight * 1.5) + ' border=0' + ' title="' + cISrch.srchKw + '"' + ' id="imgInsrtTb' + cISrch.loopCnt + '"' + '>'; htmlStr += '<img src="' + r.unescapedUrl + '"' + ' width=' + (r.tbWidth * 3) + ' height=' + (r.tbHeight * 3) + ' border=0' + ' title="' + cISrch.srchKw + '"' + ' id="imgInsrt' + cISrch.loopCnt + '"' + ' style="display: none;"' + ' onload="chngImg(' + cISrch.loopCnt + ');"' + '>'; htmlStr = '<a href="' + r.unescapedUrl + '"' + ' target="_blank"' + '>' + htmlStr + '</a>'; // HTMLの置換 imgRep[cISrch.loopCnt].html(htmlStr); } }) .start(); } function chngImg(n) { $("#imgInsrtTb" + n).hide(); $("#imgInsrt" + n).show(); } /* *-------------------------------------------------- */ /** * @title 【短縮URL取得】 * @description * * 短縮URLを取得する。 * * @return なし */ function getShrtUrl() { cWSrch .reset() .shrtUrl({ // 固定URLを作成して、短縮URLに変換 url : $("#fix_url_raw").val(), res : function(res) { $("#fix_url_min").val(res); } }) .start(); } /** * @title 【遅延読み込み】 * @description * * HTMLの一部を遅延読み込みする。 * * 以下、遅延領域のサンプル。 * * <span class="delay"> * <noscript>No JavaScript</noscript> * <span class="delayBefore">Now Loading...</span> * <span class="delayAfter"><!-- * hoge hoge * --></span> * </span> * * @return なし */ function loadDelay() { $(".delay").each(function () { // 遅延前の表示を消す $(this).children(".delayBefore").html(""); // 遅延後の表示を出す var repStr = $(this).children(".delayAfter").html(); repStr = repStr.replace(/^<!--|-->$/g, ""); $(this).children(".delayAfter").html(repStr); }); } /* *-------------------------------------------------- */ /** * @title 【テスト用】 * @description * * テスト用コードを記述する。 */ function test() { }