News API利用でBASIC!でニュースを検索（ BASIC プログラミング ）

BASIC!は、Androidで動くBASIC インタープリタです。詳しくは以下をどうぞ。

* [AndroidでBASICを使う](http://qiita.com/basictomonokai/items/25bcb21ec69c00e9ad23)

ニュースのWEBAPIはなかなか良いのがありませんが日本語でも情報量がまぁまぁあって便利なAPIがあったのでBASIC!のHTMLモードでニュース検索するプログラムを作ってみました。

## １．NEWS API

かなり有名なサイトらしいので特に説明は不要だと思います。ドキュメントもちゃんと整備されていてわかりやすいです。

News API
https://newsapi.org/

* 非商用なら無料で利用可能らしい
* 日本語のニュースソースもまぁまぁある
* AND、OR、NOTなど条件検索もできる

## ２．作ったプログラム

複数の検索文字列をtextareaに入力して検索ボタンを押すと検索結果がアコーディオンで表示されます。

![](https://i.imgur.com/1McPyaP.png)

ほとんどHTML、CSS、JavaScriptでBASIC!は画面制御関連のみに使っています。

## ３．コード

さっそくコードです。HTMLファイルとBASファイルが1本づつです。ポイントは以下

（HTML）

* 検索文字列はLocalStorageに保存
* FetchでNEWS APIのエンドポイントを呼出し
* アコーディオンで表示

（BASIC!）

* HTMLのリンクをクリックするとブラウザーでリンク先を表示
* 画面終了ボタンまたはバックキーでプログラムを終了

```html:newsapixx2.html
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>NEWS API-M</title>
  <meta name="viewport" content="initial-scale=1.0, user-scalable=no">


<style>
body { 
   font-family: "Rounded Mplus 1c";
   font-size: 100%;
   color: #ecf0f1;
   background: #27ae60;
}

#kkaf {
   font-size: 1.5em;
   margin: 10px;
}

</style>

<style>

#buttonx {
  width:90px;
  color:#ffffff;
  background:#e67e22;
  font-family: fantasy,sans-serif;
  font-size:24px;
  font-weight:bold;
  text-shadow:0 1px 0px #143352,0 2px 0px #143352;
  text-align:center;
  display:inline-block;
  text-decoration:none;
  border:1px solid #225588;
  padding:5px 0 2px 0;
  border-radius:5px;
  margin-bottom:20px;
  margin-left:10px;
  opacity: 0.7;
}

</style>

<style>

div#footer-fixed
{
    position: fixed;            /* フッターの固定 */
    bottom: 0px;                /* 位置(下0px) */
    left: 0px;                  /* 位置(左0px) */
    width: 100%;                /* 横幅100%　*/
    height: 70px;              /* 縦幅70px */
}
 

div#body-bk{
    padding: 0px 0 80px 0;    /* 下に80pxを余白を取る */
}



.linknews{
     display:block;
     width: 90%;
     height:35px;
     line-height: 30px;
     font-size: 1em;
     color: #FFF;
     text-decoration: none;
     text-align: left;
     background-color: #f39800; /*ボタン色*/
     border-radius: 5px; /*角丸*/
     -webkit-transition: all 0.5s;
     transition: all 0.5s;
     padding: 10px;
     white-space: nowrap;
     overflow: hidden;
     text-overflow: ellipsis;
}

.linknews:active{
     background-color: #f9c500; /*ボタン色*/
}


#srch {
  width: 80%;
  font-size: 1.2em;
}

h3 {
  background-color: #096c47;
  padding: 5px;
}

.hide {
  display: none;
}

</style>

<script type="text/javascript">
    function doDataLink(data) {
        // console.log(JSON.stringify(data));
        Android.dataLink(data);
    }
</script>
  
  
</head>

<body>

     <h1>NEWS API</h1>

<textarea id="srch" rows="6"></textarea>


<div id="body-bk">

<div id="kkaf">

<div id="output"></div>
  

</div>

</div>

<div id="footer-fixed">

<a id="buttonx" onmouseover="this.style.background='#e67e22'" onmouseout="this.style.background='#d35400'" onclick="this.style.background='#e74c3c';getnews()">検索</a>

<a id="buttonx" onmouseover="this.style.background='#e67e22'" onmouseout="this.style.background='#d35400'" onclick="this.style.background='#e74c3c';doDataLink('//x//')">終了</a>

</div>

<script>

var srchs = localStorage.getItem('srchnewsapi20190103');  //Storageから読み込み
if ( srchs == null ) {
  document.getElementById('srch').value = '';
  localStorage.setItem('srchnewsapi20190103','');

} else {
  if ( srchs == '' ) {
    document.getElementById('srch').value = '';
    localStorage.setItem('srchnewsapi20190103','');
  } else {
    document.getElementById('srch').value = srchs;
  }
};


function getnews() {
  var srchnew = document.getElementById('srch').value;
  document.getElementById('output').innerHTML = '';
  localStorage.setItem('srchnewsapi20190103',srchnew);
  var arrsrch = srchnew.split('\n');
  for (var i=0;i<arrsrch.length;i++) {
    if (arrsrch[i] == '' ) {
    } else {
      kenone(encodeURIComponent(arrsrch[i]),arrsrch[i]);
    };
  }; 
};

function kenone(kenx,kend) {

  var url = 'https://newsapi.org/v2/everything?' +
            'q=' + kenx + '&' +
            'pagesize=100&'+
            'apiKey=（NEWS　APIのAPIキー）';
   
  var req = new Request(url);
  var maehensyu = []; 
  var outhtml;
  fetch(req).then(function(response) {
    return response.json();
  }).then(function(json) {
    for (var i=0;i<json.articles.length;i++) {
      outhtml = '';
      outhtml += '【日付:' + json.articles[i].publishedAt + ' ';
      outhtml += '情報元:' + json.articles[i].source.name + '】<br>\n';
      outhtml += '<a class=\"linknews\" href=\"' + json.articles[i].url + '\">';
      outhtml += json.articles[i].title + '</a><BR><BR>\n';
      if (json.articles[i].description == null){
        outhtml += '[説明なし]' + '<BR><BR>\n';
      } else {
        outhtml += json.articles[i].description + '<BR><BR>\n';
      };
      if (json.articles[i].urlToImage == null){
        outhtml += '[写真なし]' + '<BR><BR>\n';
      } else {
        outhtml += '<img width=\"150\" src=\"' + json.articles[i].urlToImage + '\"><BR><BR>\n';
      };
      maehensyu.push(outhtml);    
    };
    maehensyu.sort();
    var atohensyu = '';
    for (var j=0;j<maehensyu.length;j++) {
      atohensyu = maehensyu[j] + atohensyu;
    };
    atohensyu = '<span class=\"hide\">\n'+atohensyu;
    atohensyu = '<h3 class=\"group\">'+'検索結果('+j+'):'+kend+'</h3>\n'+atohensyu;
    atohensyu = atohensyu+'</span>\n';

    document.getElementById('output').innerHTML += atohensyu;

    var menu = document.getElementsByClassName('group');

    function show(){
      console.log('aaa');
      var hideContent = this.nextElementSibling;
      hideContent.classList.toggle('hide');
    };

    for(var i = 0; i < menu.length; i++){
      menu[i].addEventListener('click', show)
    }


  });

};

</script>

</body>

</html>
```

```txt:news.bas
console.title "NEW APIマルチ対応版v2"

nxttest:

HTML.OPEN

HTML.LOAD.URL "newsapixx2.html"

xnextUserAction:

! loop until data$ is not ""

DO
 HTML.GET.DATALINK data$
UNTIL data$ <> ""

type$ = LEFT$(data$, 4)

data$ = MID$(data$,5)

! Act on the data type
! Shown are all the current data types

SW.BEGIN type$

 ! Back Key hit.
 ! if we can go back then do it
 SW.CASE "BAK:"
  PRINT "BACK key: " + data$
  popup "終了します",0,0,0
  pause 2000
  end
  SW.BREAK

 ! A hyperlink was clicked on
 SW.CASE "LNK:"
  PRINT "Hyperlink selected: "+ data$
  popup "リンク先をロード中",0,0,1
  browse data$
  SW.BREAK

 ! An error occured
 SW.CASE "ERR:"
  PRINT "Error: " + data$
  popup "エラーが発生しました 終了します",0,0,0
  pause 2000
  exit
  SW.BREAK

 ! User data returned
 SW.CASE "DAT:"
  PRINT "User data: " + data$
  
  ! Check for Exit
  IF data$ = "//x//" then
   PRINT "User ended demo."
   HTML.CLOSE
   popup "終了します",0,0,0
   pause 5000
   end
  else
   msx$=data$+"←データの内容"
   popup msx$,0,0,0
   pause 1000
   goto xnextUserAction
   goto nxttest
  ENDIF
  SW.BREAK

 ! Form data returned.
 ! Note: Form data returning
 ! always exits the html.

 SW.CASE "FOR:"
  PRINT "Form data: "+data$
  popup "終了します",0,0,0
  pause 2000
  exit
  SW.BREAK

 SW.DEFAULT
  PRINT "Unexpected data type:", type$ + data$
  popup "終了します",0,0,0
  pause 2000
  exit

SW.END

GOTO xnextUserAction


end

```

## ４．テスト結果

テスト結果の動画は以下です。

https://www.youtube.com/watch?v=hBOOf_M6dPI

簡単に使えて便利だと思います。

以　上