edama2さんから投稿していただいた、Markdown書類をダイアログ上でプレビューするScriptの第二弾です。
WKWebViewではなくNSAttributedStringを使ってMarkdownを表示しています。 NSAttributedStringでhtmlが表示できるとわかってWKWebViewの代わりになるかな?と思ったんですが、javascriptは使えないので自前で実行し、NSAttributedStringに<hr>に相当するものがないのとWKWebViewとは描画結果が違うので、プレビューとして使うのはイマイチです。作っておいてなんですが…😢
本Scriptの見どころは2点。「Scriptバンドル内にJavaScriptのライブラリを突っ込んで呼び出しているところ」と、「Markdownを(HTML経由で)NSAttributedStringに変換してプレビューしている」ところです。
ひかえめな説明文とは裏腹に、ずいぶんと攻めているというか、野心的な実装です。
JavaScriptのライブラリをローカルに置く案についてはいろいろedama2さんと意見交換をしていたんですが、割とさらっと書いているところにショックを受けます。これだけでも、相当に試行錯誤が必要な内容なんですが、このレベルに追いつくためには相当の苦労が、、、
AppleScript名:アラートダイアログでMarkdownをプレビュー v2 |
use AppleScript use framework "Foundation" use scripting additions on run my main() end run on main() set mes to "Markdownファイルを選択してください。" set chooseItems to choose file of type {"net.daringfireball.markdown"} with prompt mes # set aScreen to current application’s NSScreen’s mainScreen() set screenFrame to aScreen’s frame() set aHeight to current application’s NSHeight(screenFrame) set aWidth to current application’s NSWidth(screenFrame) set aHeight to aHeight * 0.845 set aWidth to aWidth * 0.94 / 2 set paramObj to {} set paramObj to paramObj & {myMessage:"Markdown preview"} set paramObj to paramObj & {mySubMessage:"file : " & chooseItems’s POSIX path} set paramObj to paramObj & {mdFile:chooseItems} set paramObj to paramObj & {viewWidth:aWidth} set paramObj to paramObj & {viewHeight:aHeight} my performSelectorOnMainThread:"displayMarkdownPreview:" withObject:(paramObj) waitUntilDone:true end main # Markdownをダイアログで表示 on displayMarkdownPreview:paramObj set mesText to myMessage of paramObj as text set infoText to mySubMessage of paramObj as text set mdFile to (mdFile of paramObj) as alias set viewWidth to (viewWidth of paramObj) as integer set viewHeight to (viewHeight of paramObj) as integer ## MDを読み込む set mdStr to (read mdFile as «class utf8») as text ## javascriptを読み込む set mePath to path to me set resPath to (mePath & "Contents:Resources:marked.min.js") as text set jsStr to (read (resPath as alias) as «class utf8») as text ## javascriptでMarkdownをhtmlに変換 tell current application’s JSContext’s new() evaluateScript_(jsStr) tell objectForKeyedSubscript_("marked") tell callWithArguments_({mdStr}) set resultStr to toString() end tell end tell end tell ## HTMLを読み込む set mePath to path to me set resPath to (mePath & "Contents:Resources:index.html") as text set htmlStr to (read (resPath as alias) as «class utf8») as text ## html内の文字を置き換え set aString to current application’s NSString’s stringWithFormat_(htmlStr, resultStr) as text log result ## NSAttributedString set aString to current application’s NSString’s stringWithString:aString set stringData to aString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding) set aValue to {current application’s NSHTMLTextDocumentType, current application’s NSUTF8StringEncoding} set aKey to {current application’s NSDocumentTypeDocumentAttribute, current application’s NSCharacterEncodingDocumentAttribute} set aOption to current application’s NSDictionary’s dictionaryWithObjects:aValue forKeys:aKey tell current application’s NSAttributedString’s alloc() tell initWithHTML_options_documentAttributes_(stringData, aOption, missing value) set attributedString to it end tell end tell log result # Create a TextView with Scroll View set frameSize to current application’s NSMakeRect(0, 0, viewWidth, viewHeight) tell current application’s NSTextView’s alloc() tell initWithFrame_(frameSize) setEditable_(false) tell textStorage() appendAttributedString_(attributedString) end tell set aView to it end tell end tell tell current application’s NSScrollView’s alloc() tell initWithFrame_(frameSize) setDocumentView_(aView) set theView to it end tell end tell ## アイコンの指定 set aImage to current application’s NSWorkspace’s sharedWorkspace()’s iconForFileType:"net.daringfireball.markdown" ## set up alert tell current application’s NSAlert’s new() addButtonWithTitle_("Close") setAccessoryView_(theView) setIcon_(aImage) setInformativeText_(infoText) setMessageText_(mesText) tell |window|() setInitialFirstResponder_(theView) end tell ### show alert in modal loop if runModal() is (current application’s NSAlertSecondButtonReturn) then return end tell end displayMarkdownPreview: |
そして、本Scriptをよくよく見回してみると、NSAttributedStringになっているのでPDFに変換するのがとても簡単でした。WkWebView上に表示したWebコンテンツをPDF化しようと試みているものの、うまくできていません。Blocks構文を必要とする機能であるため(なんでこんなものまでBlocks(非同期実行)必要なんだろ?)、AppleScriptからの呼び出しができないためです。Xcode上で他の言語をまじえて組めば不可能ではない気もしますが……
CSSがWeb表示用のものなので、PDF出力時には割とゆったり目で密度の低いレイアウトになってしまうものの、このCSS指定を別のものにできればけっこうMarkdown→PDFの変換を行う部品として使えるレベルになってくるのではないでしょうか。それはそれで、Scriptバンドル内に入れたCSSを指定するとか、Web上のどこかに印刷用のCSSをホスティングしておくなどの方法が必要になることでしょう。