Powerpoint VBAを使おう!

Powerpoint VBAやExcelのVBAで遊んでいます。JavaScriptやJScript,HTAに最近はまってます。

音声ファイルデータを後につけて実行するメモ

自分用メモ

音声データをBase64でテキスト化して,最後に付け足して使うことが可能だったこと。

<!doctype html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE11=edge" charset="utf-8">
<title>テスト中</title>
<script>
    window.onload=function(){
    mus.play()
    new Vue({
        el:"#app",
        data:{
            myText:"今日はいい天気です。"
        }
    })
    
    }
</script>
    </head>

<body>
<div id="app">
    <textarea v-model="myText"></textarea>
    <p>文章は,「{{ myText }}」</p>
    <p>文字数は{{myText.length}}文字です。</p>
</div>
</body>
</html>

<script>
    var mus=Audio()
    mus.src="data:audio/mp3;base64,//uQZAAAA31jQQZSQAI3LFhAwRQATV1VJBz0AADZgCODhjAA8CRkDJjfFWDi3g  ~音声の長いテキストデータ~ "
</script>
<script>
    /*! * Vue.js v2.5.22   * (c) 2014-2019 Evan You   * Released under the MIT License.   */
    !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof de  ・・・
</script>

音声や画像のSVGデータ,またはJQueryやVue.jsなどのライブラリをHTML内に全部放り込めば,

他ファイル依存がなくなって,作ってかなーり経ったHTAファイルでもファイル依存から解放されるんじゃないかということを試しています。

無知だからいろんなことを試行錯誤するしかない。

音声についてはとりあえずちゃんと動いた。

これであまり長い音声を使わない前提でなら,音声ファイルをどこどこに忘れずに入れておいてとかいうことから解放される。

画像データもAdobeのソフト群にお世話になっている自分としてはSVGでだいたい事足りそう。

データ部分はできれば最後に付け足しておいて,読み返さないといけないコード部分は上に固まってほしい派です。

あと,ライブラリもあまりにも長いものでなければつけてしまえそう。こちらは個人使用の段階ではある程度好き勝手でいいと思うんですが,

他人に紹介しようとしたものができた場合微妙でもあります。

ただ,依存する外部ファイルを極力消したいと思う場合たぶん私は避けないと思う。

テキストで数百キロバイトというのはコードで見るとすごいけど,データサイズとしては小さいですしね。

上記のHTMLの中には音声データとVue.jsを入れてみるということをしました。ライブラリも音声もとても長いのでぶちっと切ってますからもちろん上のコードそのままでは動きませんが,

数十キロバイトのライブラリや画像データなら最後に内部に放り込んでおけば一つのファイルでいいものができそうな気がします。

外部ファイルとする方が使いまわし等で適正なんでしょうけど,

私を含めて,あまり深くその言語を知らない場合,しばらくして忘れてしまうと前提となるファイルとの位置関係が変わってしまったり,絶対参照しているファイルが年度を超えていくうちに

なくなってしまったりということは往々にしてあります。

なので,その方法の是非は抜きにして,一つのファイルで納めてしまいたいという強い希望がいつも頭にあるので,無駄なこととはいえできることを試した。

これでかなりストレスが減るなぁ。

本収集以上にはあまり進んではいませんが,自分がしたいことはSPAと呼ばれるやつのようで,Vue.jsととても相性が良いようです。

JQueryで作られたものもよく出会うため,JQueryの本とかも可能な限りたくさん集めました。

プレーンなJavascriptももちろんたくさん。

本にまみれてますが,なんとなく方向性ができつつあるので,来年度はけっこう楽しみ。

ただコードの中にライブラリを内包する場合,ライブラリによくあるMITライセンスというのとの上手な付き合い方はどうなるのか,調べないとなぁと思っているところです。

mp3ファイルをbase64でテキストにしてjavascriptで活用する

すっかりHTAにはまりこんで,Powerpointに戻る気配がありません(;´∀`)

JavascriptCSS,HTML5でできることの幅広さにおののく毎日で,日々本がたまりにたまって読める気配がない。

でも,気の向くままに,調べものするときに読むことで,少しずつ,少しずつ頭の中に概念みたいなものができつつある気がします。

読みながらやれば大概なんとかなりそうな感じです。

さて,HTAの数少ない不満は 画像や音声ファイルを別ファイルで用意しないといけない,という不満でした。

依存ファイルがあると,作って時間がたつと忘れてしまうし,もし誰かに欲しいといわれたときに提供したとして,前提条件が崩れるとうまく動かなくなるのは容易に予測できる。

jQueryやグラフのライブラリはいくらかあきらめがつきますし,私が使う棒グラフ・円グラフくらいならSVGCanvasでどうにかすればいい話だよなぁとも思う。

Illustratorもあるので,画像データはけっこうSVGにできますし,CSSがやれることも半端ない。

画像面ではほぼ問題は見当たりません。

でも,音源ファイルがどうにかならないのかなーと調べていたら,Base64エンコードすることで解決しそうでした。

こちらの記事のおかげです。

qiita.com

そこで,mp3ファイルをWindowsのcertutilコマンドでエンコードするものをexcelvbaで組んでみました。

フォルダを指定して,その直下のmp3ファイルをエンコードします。

そして,さらにそれにちょっとhtmlを足して,htmファイルにして音を確認する感じに作ってみました。

完全に自分用(ノ´∀`*)

前者がこんな感じ

Sub base64encode()
    Dim strPathName As String
    
    With Application.FileDialog(msoFileDialogFolderPicker)
        If .Show = True Then
            strPathName = .SelectedItems(1)
        End If
    End With
    
    If strPathName = "" Then Exit Sub
    
    Dim strFileName As String
    
    strFileName = Dir(strPathName & "\*.mp3", vbNormal)
    If strFileName = "" Then Exit Sub
    Do While strFileName <> ""
        DoEvents
        Shell "certutil -f -encode " & strPathName & "\" & strFileName & " " & strPathName & "\" & Left(strFileName, InStr(strFileName, ".mp3") - 1) & ".htm"
        strFileName = Dir()
    Loop
End Sub

とても短いです(;´∀`)でもこれでhtmファイルを吐き出します。
ただこのままではどんな音だったか確認もできないので,それにちょっと編集をするのが次のコード

Sub edittext()
    Dim strPathName As String
    
    With Application.FileDialog(msoFileDialogFolderPicker)
        If .Show = True Then
            strPathName = .SelectedItems(1)
        End If
    End With
    
    If strPathName = "" Then Exit Sub
    
    Dim strFileName As String

    strFileName = Dir(strPathName & "\*.htm", vbNormal)
    Dim inputText, outputText, records, lineStr, flg As Boolean
    
    
    Do While strFileName <> ""
        DoEvents
        Set inputText = CreateObject("ADODB.Stream")
        With inputText
            .Charset = "UTF-8"
            .Mode = 3 '読み書き
            .Type = 2 'テキスト
            .Open
            .LoadFromFile strPathName & "\" & strFileName
        End With
        
        Set outputText = CreateObject("ADODB.Stream")
        With outputText
            .Charset = "UTF-8"
            .Mode = 3 '読み書き
            .Type = 2 'テキスト
            .Open
            .writetext "<audio controls='controls' autoplay style='border:3px solid red;'><source src='data:audio/mp3;base64,", 1
            flg = True
            Do Until inputText.eos
                DoEvents
                lineStr = inputText.readtext(-2)
                If flg = True Then
                    flg = False
                Else
                    .writetext Replace(lineStr, vbCrLf, ""), 0 '問題あったら1
                End If
            Loop
            .writetext "", 1
            .writetext "' type='audio/mp3' /></audio>", 0
            .savetofile strPathName & "\" & strFileName, 2
            .Close
        End With
        strFileName = Dir()
    Loop
End Sub

この二つをつなげるとうまくいかなかったので,タイミングを分ける意味で分割しています。
さっきのコードで吐き出したhtmファイルにaudioタグを付け加えることで,

そのhtmを開くと音を鳴らすようにしただけです。

あと,base64で吐き出したものを一行にするように少し細工をしています。

これで一応文字列にはなりました。

今度はjavascriptでうまく使えるように調整をしていこう。

<meta http-equiv="X-UA-Compatible" content="IE=edge" charset="utf-8">

この一文を頭に付け加えるだけで,htaにしてもきちんと動くようです。

htaの制限ってあんまりないのかな・・と最近思います。

このブログの名前の変更を検討するべきなんだろうか・・(;´∀`)

HTA Audioオブジェクト meta記述で使えた

昨日までの成果でHTAを作る場合にmeta記述でEdge互換にするといろいろ使えたってのを書いていました。

以前失敗したAudioオブジェクトのやつがふいに頭によぎり試してみた。

ためしてみた

まず前の失敗例

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script>
  var pu=Audio()
  pu.src="end.mp3"
  pu.play()
</script>
</head>

<body>
</body>
</html>

f:id:chemiphys:20190115100424p:plain
この画面が出て使えない。レガシーブラウザモード? (IE6くらいの時代の互換らしい)

metaだけ変えた 他はいじらず

<!doctype html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" charset="utf-8">
<title></title>
<script>
  var pu=Audio()
  pu.src="end.mp3"
  pu.play()
</script>
</head>

<body>
</body>
</html>

音なりますよ! エラーも出ません!

これは大きい。

夢が広がりますね。

Libralyへの苦手意識が減ったので,JQueryの学習も始めました。JavaScriptへの理解が進んだ後でもありますし,意味もあるかな。

たぶんできました。

Plotly.js
plot.ly
現段階でわたしが選んだのはこれです。奥が深そうであり,かつ,こだわらなければシンプルに書ける。

なんといいもの。

Libralyファイルもたった一つです。大き目ではありますが,そこは機能の魅力に負けました。

HTAのコードだけ載せます。

<!doctype html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" charset="utf-8">  <!--meta文で互換性-->
<title>テストアンケート</title>
<style type="text/css">
  table{border-collapse: collapse;}
  table,tr,td{border: solid 2px black;}
  td.clsmondai{padding-left: 5px;font-weight: bold;background-color: black;color: white;width:400px}
  td.clskaito{padding-left: 20px;background-color: antiquewhite}
</style>
<script src="plotly-latest.min.js"></script>
<script>
  var ForReading = 1;
  var ForWriting = 8;
  var p=[
    [1,'クラス','select',['1A','1F','1L','2A','2F','2L','3A','3F','3L']],
    [2,'番号','select',renban(1,41)],
    [3,'好きな科目は','check',['国語','社会','数学','理科','英語']],
    [4,'この中で一番好きな食べ物はどれか。','radio',['りんご','バナナ','みかん','ごはん','おかし']],
    [5,'好きなペットは何か。(複数えらんでいい)','check',['犬','猫','ハムスター']],
    [6,'自分を動物に例えると。','text',''],
    [7,'この変なアンケートについて感想をどうぞ。','multi','']
  ]
  var thisName=location.pathname
  
  thisName=thisName.slice(thisName.lastIndexOf("\\")+1,thisName.lastIndexOf("."));
  var fso = new ActiveXObject("Scripting.FileSystemObject");
  if (fso.FolderExists(".\\data")==false) fso.CreateFolder(".\\data");
  var DataFile = ".\\data\\"+thisName+"_data.csv";
  if (fso.FileExists(DataFile)==false){
    var data = fso.OpenTextFile(DataFile, ForWriting,true);
    var tmp="user"
    for (var i=0;i<p.length;i++){tmp+=","+p[i][1]}
    tmp+=",Date"
    data.WriteLine(tmp);
    data.Close()
  } 
  var User=new ActiveXObject("WScript.Network").UserName;
  
  //ベタ打ちここまで
  
  function init(){
    resizeTo(500,600);
    makeForm()
  }
  
  function renban(s,e){
    var arr=[]
    for (var i=s;i<=e;i++) arr.push(i)
    return arr
  }
  
  function makeForm(){
    var tmp=[]
    tmp.push("<table>")
    for(var i=0;i<p.length;i++) tmp.push(makeElement(i))
    tmp.push("</table>")
    document.getElementById("table").innerHTML=tmp.join("")
  }
  
  function makeElement(No){
    var mondai=p[No][1]
    var name="No"+(No)
    var type=p[No][2]
    var arr=p[No][3]
    var html=[];
    var tmp;
    switch(type){
      case "select":tmp = makeSelectElement(name,"select",arr);break
      case "radio":tmp = makeSelectElement(name,"radio",arr);break
      case "check":tmp = makeSelectElement(name,"checkbox",arr);break
      case "text":tmp="<input type='text' name='" + name + "' size='45' />";break
      case "multi":tmp="<textarea name='" + name +"' rows='5' cols='46' ></textarea>";break
    }
    
    html.push("<tr><td class='clsmondai'>" + (No+1) + " " + mondai + "</td></tr>")
    html.push("<tr><td class='clskaito'>")
    html.push(tmp+"</td>")
    
    return html.join("")
  }

  function makeSelectElement(name,type,arr){
    switch(type){
      case "select":
        var tmp=[]
        tmp.push("<select name='" + name +"'>")
        for(var i=0;i<arr.length;i++){tmp.push("<option value='" + arr[i]+"'>"+arr[i]+"</option>")}
        tmp.push("</select>")
        element=tmp.join("")
        break
      case "radio":
      case "checkbox": //間違いじゃないよ
        var tmp=[]
        for(var i=0;i<arr.length;i++){
          tmp.push("<input type='"+ type +"' name='" + name + "' value='" + arr[i] +"'>"+arr[i]+"<br>")
        }
        element=tmp.join("")
        break

    }
    return element
  }
  // データ収集部分
  function result(){
    var html=[]
    html.push(User+",")
    for (var i=0;i<p.length;i++){
      html.push(getData("No"+i,p[i][2])+",")
    }
    html.push(Date())
    return html.join("")
  }

  function PostData(str){
    var fso = new ActiveXObject("Scripting.FileSystemObject");
    var data = fso.OpenTextFile(DataFile, ForWriting);
    data.WriteLine(result());
    data.Close();
    makeGraph()
  }
  function getData(name,type){
    switch(type){
      case "radio":
      case "check":
      return getCheck(name);
    break;
      case "text":
      case "multi":
      case "select":
    return document.getElementsByName(name)[0].value.replace(/\r?\n/g,"_");
    break;
    }
  }
    
  function getCheck(name){
      var CHECK=document.getElementsByName(name)
      var tmp=""
      for(var i=0;i<CHECK.length;i++){
        if(CHECK[i].checked) tmp+="_" +CHECK[i].value
      }
      return tmp.substring(1)
  }
  
   function makeGraph(){
    var fso = new ActiveXObject("Scripting.FileSystemObject")
    var data = fso.OpenTextFile(DataFile, ForReading)
    var data= data.ReadAll()
    var rowCount=data.split("\n").length
    var res=[]
    res.push("<table>")
    var graphNo=0
    var graphvalues=[]
    var graphlabels=[]
    var graphtype=[]
    for (var i=0;i<p.length;i++){
    res.push("<tr><td class='clsmondai'>"+p[i][1]+"</td></tr>")
      switch(p[i][2]){
        case "select":
        case "radio":
        case "check":
          var tmpArray = []
          var count={}
          for (var j=1;j<rowCount-1;j++){
            var tmp=data.split("\n")[j].split(",")[i+1]
            if (!tmp==""){
              var tmp2=tmp.split("_")
              for (var k=0;k<tmp2.length;k++) {
                var key=tmp2[k]
                count[key]=(count[key])? count[key]+1 : 1;
              }
            }
          }
          
          for (var key in count){
            tmpArray.push([key,count[key]])
          }

          var tmp3=[]
          var tmp4=[]
          for (var k=0;k<tmpArray.length;k++){
            tmp3.push(tmpArray[k][0])
            tmp4.push(tmpArray[k][1])
          }
          graphlabels[graphNo]=tmp3
          graphvalues[graphNo]=tmp4
          
          graphtype[graphNo]= (p[i][2]=='radio') ? 'pie' : 'bar'
          res.push("<tr><td><div id='graph"+graphNo+"'></div></td></tr>")
          graphNo++
          break
        case "text":
        case "multi":
          res.push("<tr><td>")
          for (var j=1;j<rowCount;j++){
            tmp=data.split("\n")[j].split(",")[i+1]
            if (!tmp=="") res.push(tmp+"<br>")
          }
          res.push("</td></tr>")
          break
      }
      
    }
     res.push("</table>")
     res.push('<input type="button" href="#" value="グラフ更新" onClick="makeGraph()"/>')
     document.body.innerHTML=res.join("")
     
    for (var i=0;i<graphvalues.length;i++) {
      drawGraph(graphvalues[i],graphlabels[i],graphtype[i],'graph'+i)
    }
     
  }
  function drawGraph(gvalues,glabels,gtype,gdiv){
    if (gtype=='pie'){
      var data = [{
        values: gvalues,
        labels: glabels,
        type: 'pie'
      }];
    } else {
      var data = [{
        x: glabels,
        y: gvalues,
        type: 'bar'
      }];
    }

    var layout = { height: 400, width: 388 };

    Plotly.newPlot(gdiv, data, layout);
  }
</script>
</head>
<body onload="init()">
  <form id="formFld">
    <div id="table"></div>
    <input type="button" href="#" value="送信する" onClick="PostData()"/>
    <input type="button" href="#" value="グラフ表示" onClick="makeGraph()"/>
  </form>
</body>
</html>

グラフを書いているところは

  function drawGraph(gvalues,glabels,gtype,gdiv){
    if (gtype=='pie'){
      var data = [{
        values: gvalues,
        labels: glabels,
        type: 'pie'
      }];
    } else {
      var data = [{
        x: glabels,
        y: gvalues,
        type: 'bar'
      }];
    }

    var layout = { height: 400, width: 388 };

    Plotly.newPlot(gdiv, data, layout);
  }

ここだけなんです。gvalues,glabelsは配列を与えています。
驚異的なシンプルさです。

これにより作られるグラフはこんな感じ
f:id:chemiphys:20190114202504p:plain

とても満足しています。canvasjavascriptだけで書く方法もネットで探せばありましたが,

libralyも使えるべきだと思い,使う方向で模索しました。

私も慣れないうちは手間取ったので,今はライブラリのファイルを同じフォルダに入れている,という想定のコードになっています。

職場で使うならフルパスで与えておいて,どこにhtaファイルをコピーしても使えるようにするのがよさそうですね。

ライブラリファイルは
plot.ly
ここで落とせます。

最初はグラフライブラリの殆どが動かずとても困りましたが,最終的には全部動くようになりました。

結局知らないせいで視野や選択肢が狭くなっていただけだったようです。

今までhtaで動かないなぁと思っていたことも,互換設定のmeta記述で動くのかもしれません。

いろんな意味で今回のがんばりは今後につながりそうです。この三連休ひたすらやってたので,時間は費やしたけど

集中的に取り組んで,だいぶ変わりました。

vba vbs Jscript javascript

ここら辺がわかればたぶん本職じゃないので,ずっと戦えるはず。

ほんとにそう思ってるのでしっかりやろう。

HTAのタイマー非常に使いやすくて重宝しているので,いろんなものをHTAに作り直してみたいものです。

あとは,今回JavaScriptの配列の中に配列がある場合について,うまく制御できずにかなり時間を費やしたので,

その辺をいろいろと試したい。

デバッグ環境が欲しい。VBEditor並みとまではいかなくても,なんとかしたいな・・。

Dreamweaverを使いこなせていないだけのようでもありますが・・(;´∀`)

次にやること メモ

アンケートを取ったら,次にやることはグラフ表示。

そこまでできたら本当に授業に生かせる気がする。

単純に記録やアンケートを取るだけならもう対応可能なとこまできたわけですが,グラフはまた別の話ですね。

HTML+JavaScriptという範囲でなら選択肢は非常に多そうでした。

できるだけプラグイン等を少なくしたい,という中で考えた場合で

gionkunz.github.io

apexcharts.com

この二つがとても気に入りました。すごくいい。

でも,HTAで動くか,と試してみたところ,うまくいきません。。むうぅ。

出力にブラウザを使うのはかまわないため,JScriptでローカルデータを吸い上げてブラウザに渡せばいいから

使えないといえません。

でも,できるならHTAの画面だけで勝負はできないか,いろいろと試しています。

そのまま使えるものはあんまりないぽいんですが,

meta文に

<meta http-equiv="X-UA-Compatible" content="IE=edge" charset="utf-8">

とすれば動くものがいくつかありました。

ちょこっとずつ変えたらけっこう動いてくれるっぼい。

これにいろいろ書き出しながら確認,編集をすると次々と動き出しました。ヽ(*´∇`)ノ

やる気がまたデテキタ(゚▽゚*)

簡単にあきらめるものではないね。 きっちり形になったら,また記事にしたいと思います。

Windows7の環境が自宅にはないんですが,電子黒板がWindows7なのが,とても脅威  (((ノ)゜Д゜(ヽ))))

追記
plot.ly

plotly.jsがものすごくいい。職場で使えるか確認した後本格的に扱ってみようと思います。

これがもし使えるなら・・スゴソウダ。

アンケート とりあえずできた

今日一日でかなり進んだ。

久々に一日の大半を使ってやってた気がします。

Excelのブックを貼れないのが残念ですが,まぁやってみます。

Excelには二つのシートを作ります。 アンケートシート と コード と名前をつけます。

アンケートシート はこんな感じ
f:id:chemiphys:20190113014836p:plain

セル b1の値がタイトルに
セル a4から 設問
セル b4から 種別 入力規則で select check radio text multi に制限しています。
セル c4からが選択肢です 連番は 1-41 のように書く,選択肢の場合は,(半角カンマ)区切りで
do loopでa列に空白がでるまで見ているので,けっこうアバウトです。

コード にはつぎのを貼ります。

<!doctype html>
<html>
<head>
<meta charset="utf-8">
【タイトル】
<style type="text/css">
  table{border-collapse: collapse;}
  table,tr,td{border: solid 2px black;}
  td.clsmondai{padding-left: 5px;font-weight: bold;background-color: black;color: white;width:400px}
  td.clskaito{padding-left: 20px;background-color: antiquewhite}
  </style>
<script>
  var ForReading = 1;
  var ForWriting = 8;
  var p=[
【パラメータ配列】
  ]
  var thisName=location.pathname
  
  thisName=thisName.slice(thisName.lastIndexOf("\\")+1,thisName.lastIndexOf("."));
  var fso = new ActiveXObject("Scripting.FileSystemObject");
  if (fso.FolderExists(".\\data")==false) fso.CreateFolder(".\\data");
  var DataFile = ".\\data\\"+thisName+"data.txt";
  if (fso.FileExists(DataFile)==false){
    var data = fso.OpenTextFile(DataFile, ForWriting,true);
    var tmp="user"
    for (var i=0;i<p.length;i++){tmp+="◇"+p[i][1]}
    tmp+="◇Date"
    data.WriteLine(tmp);
    data.Close()
  } 
  var User=new ActiveXObject("WScript.Network").UserName;
  
  //ベタ打ちここまで
  
  function init(){
    resizeTo(500,600);
    makeForm()
  }
  
  function renban(s,e){
    var arr=[]
    for (var i=s;i<=e;i++) arr.push(i)
    return arr
  }
  
  function makeForm(){
    var tmp=[]
    tmp.push("<table>")
    for(var i=0;i<p.length;i++) tmp.push(makeElement(i))
    tmp.push("</table>")
    document.getElementById("table").innerHTML=tmp.join("")
  }
  
  function makeElement(No){
    var mondai=p[No][1]
    var name="No"+(No)
    var type=p[No][2]
    var arr=p[No][3]
    var html=[];
    var tmp;
    switch(type){
      case "select":tmp = makeSelectElement(name,"select",arr);break
      case "radio":tmp = makeSelectElement(name,"radio",arr);break
      case "check":tmp = makeSelectElement(name,"checkbox",arr);break
      case "text":tmp="<input type='text' name='" + name + "' size='45' />";break
      case "multi":tmp="<textarea name='" + name +"' rows='5' cols='46' ></textarea>";break
    }
    
    html.push("<tr><td class='clsmondai'>" + (No+1) + " " + mondai + "</td></tr>")
    html.push("<tr><td class='clskaito'>")
    html.push(tmp+"</td>")
    
    return html.join("")
  }

  function makeSelectElement(name,type,arr){
    switch(type){
      case "select":
        var tmp=[]
        tmp.push("<select name='" + name +"'>")
        for(var i=0;i<arr.length;i++){tmp.push("<option value='" + arr[i]+"'>"+arr[i]+"</option>")}
        tmp.push("</select>")
        element=tmp.join("")
        break
      case "radio":
      case "checkbox": //間違いじゃないよ
        var tmp=[]
        for(var i=0;i<arr.length;i++){
          tmp.push("<input type='"+ type +"' name='" + name + "' value='" + arr[i] +"'>"+arr[i]+"<br>")
        }
        element=tmp.join("")
        break

    }
    return element
  }
  // データ収集部分
  function result(){
    var html=[]
    html.push(User+"◇")
    for (var i=0;i<p.length;i++){
      html.push(getData("No"+i,p[i][2])+"◇")
    }
    html.push(Date())
    return html.join("")
  }

  function PostData(str){
    var fso = new ActiveXObject("Scripting.FileSystemObject");
    var data = fso.OpenTextFile(DataFile, ForWriting);
    data.WriteLine(result());
    data.Close();
    document.forms[0].reset()
  }
  function getData(name,type){
    switch(type){
      case "radio":
      case "check":
      return getCheck(name);
    break;
      case "text":
      case "multi":
      case "select":
    return document.getElementsByName(name)[0].value.replace(/\r?\n/g,"_");
    break;
    }
  }
    
  function getCheck(name){
      var CHECK=document.getElementsByName(name)
      var tmp=""
      for(var i=0;i<CHECK.length;i++){
        if(CHECK[i].checked) tmp+="_" +CHECK[i].value
      }
      return tmp.substring(1)
  }
</script>
</head>
<body onload="init()">
  <form id="formFld">
    <div id="table"></div>
    <input type="button" href="#" value="送信する" onClick="PostData()"/>
  </form>
</body>
</html>

[END]

wordに一度貼ってからexcelに貼るといいかも。 最後の[END]は大事です。
これがないと永久ループに・・ DoEventsは入れてるので止めてあげればいいですが。

HTAを吐き出すコードが次

Sub MakeHTAFile()
    Dim CodeSheet As Worksheet: Set CodeSheet = ThisWorkbook.Worksheets("コード")
    Dim ConfigSheet As Worksheet: Set ConfigSheet = ThisWorkbook.Worksheets("アンケートシート")
    
    Dim ADODBStream As Object
    Set ADODBStream = CreateObject("ADODB.Stream")
    With ADODBStream
        .Charset = "UTF-8"
        .Open
    End With
    
    Dim i, j, k, tmp, tmp2, tmp3
    
    i = 1
    Do
        Select Case CodeSheet.Cells(i, 1)
            Case Is = "【タイトル】"
                ADODBStream.writetext "<title>" & ConfigSheet.Cells(1, 2) & "</title>", 1
            Case Is = "【パラメータ配列】"
                j = 1
                Do While ConfigSheet.Cells(j + 3, 1) <> ""
                    tmp = ConfigSheet.Cells(j + 3, 3)
                    If InStr(tmp, ",") > 0 Then tmp2 = "['" & Replace(tmp, ",", "','") & "']"
                    If InStr(tmp, "-") > 0 Then tmp2 = "renban(" & Split(tmp, "-")(0) & "," & Split(tmp, "-")(1) & ")"  '数式に,が出るから上のコードとの順番注意
                    If tmp = "" Then tmp2 = "''"
                    tmp3 = "    [" & j & ",'" & ConfigSheet.Cells(j + 3, 1) & "','" & ConfigSheet.Cells(j + 3, 2) & "'," & tmp2 & "],"
                    If ConfigSheet.Cells(j + 3 + 1, 1) = "" Then tmp3 = Left(tmp3, Len(tmp3) - 1)
                    ADODBStream.writetext tmp3, 1
                    j = j + 1
                Loop
            Case Else
                ADODBStream.writetext CodeSheet.Cells(i, 1), 1
        End Select
        i = i + 1
        DoEvents
    Loop Until CodeSheet.Cells(i, 1) = "[END]"
    
    Dim FileName As String
    FileName = ThisWorkbook.Path & "\" & ConfigSheet.Cells(1, 2) & ".hta"
    
    ADODBStream.savetofile FileName, 2
    ADODBStream.Close
    
End Sub

こんな感じの画面です。
f:id:chemiphys:20190113073539p:plain
テキストには
f:id:chemiphys:20190113073558p:plain
こういう感じでテキストがたまっていきます。
JScript側でかなり処理をしているので 以前のものよりだいぶすっきりです。

わたしの環境では一応動きました。(゚▽゚*)

アンケートづくり テキスト出力部分も統合

さて,やっとJScript,HTML部分の最後です。たぶん。

けっこう確認はしたんですが・・・どうでしょう。(;´∀`)

Excelとの連携はまだです。

メモ帳などにUTF-8文字コードで出力し,拡張子HTAで保存すればたぶん動きます。たぶん(;´∀`)

dataフォルダを直下につくり,その中に出力データをtextで出力するはずです。

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>無題ドキュメント</title>
<style type="text/css">
  table{border-collapse: collapse;}
  table,tr,td{border: solid 2px black;}
  td.clsmondai{padding-left: 5px;font-weight: bold;background-color: black;color: white;width:400px}
  td.clskaito{padding-left: 20px;background-color: antiquewhite}
  </style>
<script>
  var ForReading = 1;
  var ForWriting = 8;
  var p=[
    [1,"クラス","select",["1A","1B","1C"]],
    [2,"番号","select",renban(1,41)],
    [3,"食べ物をひとつえらべ","radio",["りんご","みかん","バナナ"]],
    [5,"てすとですよ","text"]
  ]
  var thisName=location.pathname
  
  thisName=thisName.slice(thisName.lastIndexOf("\\")+1,thisName.lastIndexOf("."));
  var fso = new ActiveXObject("Scripting.FileSystemObject");	
  if (fso.FolderExists(".\\data")==false) fso.CreateFolder(".\\data");
  var DataFile = ".\\data\\"+thisName+"data.txt";
  if (fso.FileExists(DataFile)==false){
    var data = fso.OpenTextFile(DataFile, ForWriting,true);
    var tmp="user"
    for (var i=0;i<p.length;i++){tmp+="◇"+p[i][1]}
    tmp+="◇Date"
    data.WriteLine(tmp);
    data.Close()
  } 
  var User=new ActiveXObject("WScript.Network").UserName;
  
  //ベタ打ちここまで
  
  function init(){
    resizeTo(500,600);
    makeForm()
  }
  
  function renban(s,e){
    var arr=[]
    for (var i=s;i<=e;i++) arr.push(i)
    return arr
  }
  
  function makeForm(){
    var tmp=[]
    tmp.push("<table>")
    for(var i=0;i<p.length;i++) tmp.push(makeElement(i))
    tmp.push("</table>")
    document.getElementById("table").innerHTML=tmp.join("")
  }
  
  function makeElement(No){
    var mondai=p[No][1]
    var name="No"+(No)
    var type=p[No][2]
    var arr=p[No][3]
    tablepart=document.getElementById("table")
    var html=[];
    var tmp;
    switch(type){
      case "select":tmp = makeSelectElement(name,"select",arr);break
      case "radio":tmp = makeSelectElement(name,"radio",arr);break
      case "check":tmp = makeSelectElement(name,"checkbox",arr);break
      case "text":tmp="<input type='text' name='" + name + "' size='45' />";break
      case "multi":tmp="<textarea name='" + name +"' rows='5' cols='46' ></textarea>";break
    }
    
    html.push("<tr><td class='clsmondai'>" + (No+1) + " " + mondai + "</td></tr>")
    html.push("<tr><td class='clskaito'>")
    html.push(tmp+"</td>")
    
    return html.join("")
  }

  function makeSelectElement(name,type,arr){
    switch(type){
      case "select":
        var tmp=[]
        tmp.push("<select name='" + name +"'>")
        for(var i=0;i<arr.length;i++){tmp.push("<option value='" + arr[i]+"'>"+arr[i]+"</option>")}
        tmp.push("</select>")
        element=tmp.join("")
        break
      case "radio":
      case "checkbox": //間違いじゃないよ
        var tmp=[]
        for(var i=0;i<arr.length;i++){
          tmp.push("<input type='"+ type +"' name='" + name + "' value='" + arr[i] +"'>"+arr[i]+"<br>")
        }
        element=tmp.join("")
        break

    }
    return element
  }
  // データ収集部分
  function result(){
    var html=[]
    html.push(User+"◇")
    for (var i=0;i<p.length;i++){
      html.push(getData("No"+i,p[i][2])+"◇")
    }
    html.push(Date())
    return html.join("")
  }

  function PostData(str){
    var fso = new ActiveXObject("Scripting.FileSystemObject");
    var data = fso.OpenTextFile(DataFile, ForWriting);
    data.WriteLine(result());
    data.Close();
    document.forms[0].reset()
  }
		
		
  function getData(name,type){
    switch(type){
      case "radio":
      case "check":
      return getCheck(name);
    break;
      case "text":
      case "multi":
      case "select":
    return document.getElementsByName(name)[0].value.replace(/\r?\n/g,"_");
    break;
    }
  }
    
  function getCheck(name){
      var CHECK=document.getElementsByName(name)
      var tmp=""
      for(var i=0;i<CHECK.length;i++){
        if(CHECK[i].checked) tmp+="_" +CHECK[i].value
      }
      return tmp.substring(1)
  }
</script>
</head>
<body onload="init()">
  <form id="formFld">
    <div id="table"></div>
    <input type="button" href="#" value="送信する" onClick="PostData()"/>
  </form>
</body>
</html>

だいぶまたいじってます。

 var p=[
    [1,"クラス","select",["1A","1B","1C"]],
    [2,"番号","select",renban(1,41)],
    [3,"食べ物をひとつえらべ","radio",["りんご","みかん","バナナ"]],
    [5,"てすとですよ","text"]
  ]

質問のパラメータを二次配列?に固めました。連番も専用の関数を用意。40人とか相手のときはこのほうがいいかな,と。
この部分とタイトルさえExcelから出力すればいいように作った・・はず。

どうかなー