見出し画像

WSHがお好きでしょ?そしてマークダウンをdocxやPDFにした

こんにちは!なるーらぼです。先日から「WSHがお好きでしょ?」に思いつきの投稿をしてから、合間をぬって久しぶりにコードを書いてみています。思った以上に忘れていることが多くて困ってしまいました。だいたいできたので、そのときに思い出したことや学びがあった(のだろうか…)ことを投稿したいと思います。

HTAの現在

まず最初にざーっと思いつくところを書いてしまって、途中まではChromeで見た目などを調整しながらつくっていきました。そのうえでWSHが動作するコードをつくりはじめたのでInternetExplorerに切り替えて動くものをつくっていきました。

ある程度は動くかな、と思ったところで拡張子を「html」から「hta」に変えたのですが…開いたとたんにエラーになるという事象に遭遇しました。そこそこ面食らいましたが、冷静に考えたら必然でした。
ここで、ご存知の方は当たり前だと思うかもしれませんが、HTAは実体がInternetExplorerではないということがあります。実体は「mshta.exe」というもので、こいつがInternetExplorerの機能を利用しているという仕組みです。この「mshta.exe」は特に指定がなければInternetExplorer9のドキュメントモードで動作します。このため、マークダウンをHTMLに変換するために使用したmarked.jsのエラーを引き起こしたのでした。

実際エラーになったのはdefinePropertyというものが存在しないことだったのですが、それほどHTAの環境は古く、いつ消えてもおかしくない状況です。わたしはmetaタグで久しぶりにIE=edgeなどと書きまして、InternetExplorer11として動作することを期待しました。結果的には意図通りになりましたが、他にもいろいろありました。

たとえばInternetExplorer11などとHTAでピクセルが示すサイズが異なっているということがありました。ここは仕方ないのでスタイルシートであわせることにしました。なんといいますか、敗北感という感じです。

さらに「あー、そうか…」と思わせたのがマークダウンのファイル保存です。エディタ用のtextareaから値を取り出してBlobにして、aタグにデータURLとしてダウンロード!という方法が一般的かと思うのですが、HTAではこれも許してくれませんでした。aタグのクリックが反応しないのです。しかも、例外にもなりません。本当に素晴らしいと思いました。いろいろ考えましたが、UTF-8で保存しておかないとFileReaderをつかったファイルの読み込みで文字化けが発生するため、姑息な手法を採用することにしてしまいました。良い子はマネしないほうがいいでしょう。

これぞ、WSHの醍醐味(なのだろうか)

良い子はマネしないように、と書いたのですが、これはどうにもならないなと思いましてやってみたという感じです。いちおうどうしたかを書いておきます。大きな流れとしては次のとおりです。

1. WSHをつかってテキストファイルをふつうに作成します
2. テキストファイルができたらWSHをつかって別のJScriptファイルを実行します
3. 起動されたJScriptファイルは起動時パラメータに指定されたファイルを読み込んで、UTF-8のファイルとして保存します
4. HTAのほうではJScriptファイルの実行終了を待ち合わせて作成完了まで待機します

もしモダンブラウザでやるとしたら、次のような感じでごくふつうにダウンロードできます。

    function exportMarkdown(val) {
       var file = new Blob([val], { type: 'text/markdown'})
       var a = document.createElement('a')
       a.download = 'my-markdown.md'
       a.href = URL.createObjectURL(file)
       a.click()
   }

たったこれだけです。なのにWSHを使うことになってしまうと、長々と書いていくことになります。さきほどの部分をWSHで書くと次のようになってしまいました。

    function exportMarkdown(val) {
       try {
           var fso = new ActiveXObject('Scripting.FileSystemObject')
           var here = __getHerePath()
           var js = fso.BuildPath(here, 'mysupporter.js')
           var desktop = new ActiveXObject('WScript.Shell').SpecialFolders("Desktop")
           var mdFile = fso.BuildPath(desktop, 'my-markdown.md')
           var tf = fso.CreateTextFile(mdFile, true)
           tf.Write(val)
           tf.Close()
           window.setTimeout(__execScript, 200, mdFile, js)
       } catch(e) {
           alert(e)
       }
   }

まず、なんやそれという「__getHerePath」が登場します。これはいま起動しているHTAファイルのあるフォルダパスを取得するために用意したものです。名前も適当です。HTAはブラウザであるため、HTA自身のファイルパスを知るには「window.location」オブジェクトを利用する必要があります。しかしこれだと「C:\~」で始まるようなパスになっていません。そこで面倒なのですが元のパスに戻るようにしてある、ということです。以下のような感じです。

    function __getHerePath() {
       var fso = new ActiveXObject('Scripting.FileSystemObject')
       var thisfile = unescape(window.location.pathname).substring(1)
       thisfile = window.location.host ? ["\\\\", window.location.host, thisfile] : thisfile
       return fso.GetParentFolderName(thisfile)
   }

1点だけ、妥協したところが保存先を利用者に選択させないというところです。ファイル保存ダイアログを表示させようと思うと、Officeに何かをさせることになるからです。しかもOfficeが提供するFileDialogは保存のときにフィルタを変更することができません。意図しない形式で保存されることが考えられるのでデスクトップのみにしてしまいました。このあたりは自由に選択できたほうがいいような気がしなくはありませんし、直そうかどうしようか悩むところです。もちろん使い勝手は自由に選択できたほうがいいですよね…

ここでひと段落

ふだん投稿している文字数くらいにおさめておこうと思ったのですが、あまりにレガシーな感じで、まだファイルを保存する手続きのうちの1までしかご紹介できませんでした。
書いている途中あたりから「なぜわたしはElectronを使っていないのか」とか「Wordにするなら、PDFにするならもっと他に方法があるだろう」と思い始めてしまいました。しかしもう数回にわけて投稿して「WSHがまだギリギリできることがあるぞ」ということをお話するとともに、変わりゆく時代を味わっていただければと思います。

最後に、この投稿もつくったツールで下書きしていることをお伝えして終わりにしたいと思います。次回の投稿もお楽しみに(?)

コメント 2020-06-29 230112


この記事が気に入ったらサポートをしてみませんか?