« eoblogをMarkdown記法で書く2(SyntaxHighlighter導入) | メイン | プロファイル再構築&firefox3.6→8&その他色々でサクサク »

2011年12月18日 (日)

eoblogをMarkdown記法で書く3(プレビュー)

の続きです。

Markdown(+kramdown拡張)記法で書くといってもやっぱりHTML表示もしたいですよね。
まあ昨日のHTMLでも一応表示は出来るのは出来る(IEやchromeでは文字化けするからエンコードをUTF-8にしないと駄目だけど)んですが、極力ブログ上の見た目と同じになるようにするのが目的です。

準備

まずローカルの適当なフォルダを基準フォルダに決めて、その下にSyntax Highlighterからダウンロードしたファイルを解凍したファイル群をコピーします(最低限stylesとscriptsフォルダは必要)。フォルダはどこでも良いですが、後であまりスクリプトソース修正したくない人はlocal/syntaxに入れといて下さい。

フォルダイメージ

次にスタイルシートファイルをサーバーよりゲットします。HTMLソース表示して、それっぽいスタイルシートファイル(.css)を保存します(eoblogの場合はstyles.css)。保存する場所はどこでもいいですが、後であまりスクリプトソース修正したくない人はlocal/css1にstyles.cssという名前で保存しといて下さい。

スタイルシートファイルを参照して、画像ファイルとか他にインポートしてるスタイルシートファイルがあるなら、それもローカルに保存します。

補足

eoblogのstyles.cssは

@import url(/.shared-asp26/themes/common/base-weblog.css);

のようなcssファイルをインポートしてます。(テーマを使用してる場合はテーマ用のcssファイルもある。)

これの場所は http://xxx.blog.eonet.jp/.shared-asp26/themes/common/base-weblog.css から保存します。まあ当然といえば当然なんですが・・・。
あと保存したstyles.cssの上インポートするスタイルシートの場所を書き換えるのをお忘れなく(styles.cssとbase-weblog.cssを同じフォルダに置く場合@import(base-weblog.css)でOK)

テーマ用も同様です。テーマ用の場合使用してる画像ファイル(.png)を保存しておくと見た目がだいぶ近づきます。

スクリプトソース

# -*- coding: utf-8 -*-
require 'rubygems'
require 'kramdown'
require 'optparse'
require 'date'

@option_hash = {
  :tabwidth => 4,
  :blogmode => true,
  :date_fmt => "%Y/%m/%d (%a)",
  :title => "ブログタイトル",
  :subtitle => "ブログ副題",
  }

#markdown記法をHTML(body)に変換する
#返り値:body文字列
def mkd2htmlbody(text)
  text.encode!("UTF-8")
  #text = text.lines.to_a[1..-1].join # Just ignore the first line
  body = Kramdown::Document.new(text).to_html
  if ( @option_hash[:blogmode] )
    if (false)
      # <pre class="brush~><code>~</code></pre>
      # の場合、<code>、</code>が邪魔なので取り除く
      # こちらを使う場合、SyntaxHighlighter.config.tagName = "code"を消すこと
      body = body.gsub(\
          %r!<pre[\s\t]+([^<>]*?)class[\s\t]*="brush(.*?)>[\s\t\r\n]*<code>(.+?)</code>[\s\t\r\n]*</pre>!mi,\
          '<pre \1class="brush\2>\3</pre>')
    else
      # <pre class="brush~><code>~</code></pre>を
      # <pre><code class="brush~>~</code></pre>に変更
      body = body.gsub(%r!<pre[\s\t]+([^<>]*?)class[\s\t]*="brush(.+?)>[\s\t\r\n]*<code>(.+?)</code>[\s\t\r\n]*</pre>!mi){|match|
        strg = "<pre><code #{$1}class=\"brush#{$2}>#{$3}</code></pre>"
        match = strg
      }
    end
  end
  #<pre>~</pre>内のTABを取り除く。タブ幅はtabwidthで与える
  body = body.split(/\n/).map {|line|
    if (/<pre/ === line) .. (/<\/pre>/ === line) 
      line.gsub(/\t/, "\s"*@option_hash[:tabwidth])
    else
      line
    end
  }.join "\n"
  str_h1 = nil
  # H1→消去 H2→H4 H3→H5 H4→H6に変更する
  if ( @option_hash[:blogmode] )
    #H1消去
    body = body.gsub(%r!<h1.*?>(.+?)</h1>!i, "")
    str_h1 = $1
    #
    for i in [4,3,2]
      body = body.gsub(/<h#{i}(.+?)<\/h#{i}>/,"<h#{i+2}\\1<\/h#{i+2}>")
    end
  end
  return body, str_h1
end

def mkd2htmlbodyfile(inputname, outputname)
  sbody = nil
  File.open(inputname, "r") { |file_in|
    sbody  = mkd2htmlbody(file_in.read)
  }
  #outputname = 1 if (outputname == nil)
  File.open(outputname, "w") { |file_ou|
    file_ou.puts sbody
  }
end

def mkd2bloghtmlfile(inputname, outputname)
  sbody, h1_str = nil
  
  File.open(inputname, "r") { |file_in|
    sbody, h1_str = mkd2htmlbody(file_in.read)
  }
  #outputname = 1 if (outputname == nil)
  File.open(outputname, "w") { |file_ou|
    #inputnameから日付を取得する
    date_match = nil
    date_match = $1 if (File.basename(inputname) =~ /(^[0-9]+)/)
    dt = nil
    dt_today = Date.today()
    if (date_match == nil)
      dt = dt_today
    elsif (date_match.length == 2)    #日付を表すとする
      dt = Date.new(dt_today.year, dt_today.month, date_match.to_i)
    elsif (date_match.length == 4)    #月日を表すとする
      dt = Date.new(dt_today.year, date_match[0,2].to_i, date_match[2,2].to_i)
    elsif (date_match.length == 6)    #年月日を表すとする
      year = dt_today.year/100*100
      year += date_match[0,2].to_i
      dt = Date.new(year, date_match[2,2].to_i, date_match[4,2].to_i)
    elsif (date_match.length == 8)    #年月日を表すとする
      dt = Date.new(date_match[0,4].to_i, date_match[4,2].to_i, date_match[6,2].to_i)
    end
    str_dt = @option_hash[:date_fmt].to_s.gsub(/\#\{(.+?)\}/){|match|
      match = eval($1)
    }
    str_dt = dt.strftime(str_dt)
    file_ou.puts <<-EOF.gsub(/^[\s\t]+\|/, '') 
    |<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"  
    |     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    |<html>
    |<head>
    |<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    |<title>#{@option_hash[:title]}(preview)</title>
    |<!-- Style Sheet -->
    |<link rel="stylesheet" href="./local/css1/styles.css" type="text/css" media="screen" />
    |</head>
    |<body class="layout-two-column-right">
    |<div id="container">
    |  <div id="container-inner" class="pkg">
    |    <div id="banner">
    |     <div id="banner-inner" class="pkg">
    |       <h1 id="banner-header">#{@option_hash[:title]}</h1>
    |       <h2 id="banner-description">#{@option_hash[:subtitle]}</h2>
    |     </div>
    |  </div>
    |   <div id="pagebody">
    |    <div id="pagebody-inner" class="pkg">
    |      <div id="alpha">
    |        <div id="alpha-inner" class="pkg">    
    |         <h2 class="date-header">#{str_dt}</h2>
    |         <div class="entry" id="entry-43937939">
    |           <h3 class="entry-header">#{h1_str}</h3>
    |           <div class="entry-content">
    |             <div class="entry-body">
    EOF
    file_ou.puts sbody
    file_ou.puts <<-EOF.gsub(/^[\s\t]+\|/, '') 
    |             </div>
    |           </div>
    |         </div>
    |       </div>
    |     </div>
    |   </div>
    | </div>
    |</div>
    |</body>
    |<!-- head内だと動作しないみたい。公式だとこの位置に書いてあるのでここに記述 -->
    |<!-- Syntax Highlighter -->
    |<script type="text/javascript" src="./local/syntax/scripts/shCore.js"></script>
    |<script type="text/javascript" src="./local/syntax/scripts/shAutoloader.js"></script>
    |<link type="text/css" rel="stylesheet" href="./local/syntax/styles/shCore.css"/>
    |<link type="text/css" rel="stylesheet" href="./local/syntax/styles/shThemeFadeToGrey.css"/>
    |<script type="text/javascript">
    |<!-- configulation Autoloadの前でないと駄目? -->
    |SyntaxHighlighter.defaults['toolbar'] = false;     <!--お好みで-->
    |SyntaxHighlighter.defaults['auto-links'] = false;  <!--お好みで-->
    |SyntaxHighlighter.config.tagName = "code";
    |
    |function path()
    |{
    |  var args = arguments,
    |      result = []
    |      ;
    |       
    |  for(var i = 0; i < args.length; i++)
    |      result.push(args[i].replace('@', './local/syntax/scripts/'));
    |       
    |  return result
    |};
    |SyntaxHighlighter.autoloader.apply(null, path(
    |  'applescript            @shBrushAppleScript.js',
    |  'actionscript3 as3      @shBrushAS3.js',
    |  'bash shell             @shBrushBash.js',
    |  'coldfusion cf          @shBrushColdFusion.js',
    |  'cpp c                  @shBrushCpp.js',
    |  'c# c-sharp csharp      @shBrushCSharp.js',
    |  'css                    @shBrushCss.js',
    |  'delphi pascal          @shBrushDelphi.js',
    |  'diff patch pas         @shBrushDiff.js',
    |  'erl erlang             @shBrushErlang.js',
    |  'groovy                 @shBrushGroovy.js',
    |  'java                   @shBrushJava.js',
    |  'jfx javafx             @shBrushJavaFX.js',
    |  'js jscript javascript  @shBrushJScript.js',
    |  'perl pl                @shBrushPerl.js',
    |  'php                    @shBrushPhp.js',
    |  'text plain             @shBrushPlain.js',
    |  'py python              @shBrushPython.js',
    |  'ruby rails ror rb      @shBrushRuby.js',
    |  'sass scss              @shBrushSass.js',
    |  'scala                  @shBrushScala.js',
    |  'sql                    @shBrushSql.js',
    |  'vb vbnet               @shBrushVb.js',
    |  'xml xhtml xslt html    @shBrushXml.js'
    |));
    |SyntaxHighlighter.all();
    |</script>
    |</html>
    EOF
  }
end

def mkd2htmlfile(inputname, outputname)
  sbody = nil
  
  File.open(inputname, "r") { |file_in|
    sbody = mkd2htmlbody(file_in.read)
  }
  #output!
  #outputname = 1 if (outputname == nil)
  File.open(outputname, "w") { |file_ou|
    file_ou.puts <<-EOF.gsub(/^[\s\t]+\|/, '') 
    |<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"  
    |     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    |<html>
    |<head>
    |<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    |<title>#{@option_hash[:title]}(preview)</title>
    |</head>
    |<body>
    EOF
    file_ou.puts sbody
    file_ou.puts <<-EOF.gsub(/^[\s\t]+\|/, '') 
    |</body>
    |</html>
    EOF
  }
end

##### main ######
OptionParser.new{|opt|
  opt.on('-f','--full', "make full html file") {|v| @option_hash[:full] = v}
  opt.on('-w VAL', '--tabwidth VAL', /[0-9]+/, "<pre>tag expand tabwidth(default:4)"){|v| @option_hash[:tabwidth] = v}
  opt.on('-d VAL', '--date_fmt VAL', "Date.strftime Format String"){|v| 
    @option_hash[:date_fmt] = v
    @option_hash[:date_fmt].encode!("UTF-8")
    }
  opt.on('--[no-]blog', "blog mode(default:true)"){|v| @option_hash[:blogmode] = v}
  opt.on('-t VAL', '--title VAL', "HTML&blog's title"){|v| 
    @option_hash[:title] = v
    @option_hash[:title].encode!("UTF-8")
    }
  opt.on('-s VAL', '--sub-title VAL', "blog's sub-title"){|v| 
    @option_hash[:subtitle] = v
    @option_hash[:subtitle].encode!("UTF-8")
    }
  opt.parse!(ARGV)
}
#p @option_hash

if (@option_hash[:full])
  if (@option_hash[:blogmode])
    mkd2bloghtmlfile(ARGV[0],ARGV[1])
  else
    mkd2htmlfile(ARGV[0],ARGV[1])
  end  
else
  mkd2htmlbodyfile(ARGV[0], ARGV[1])
end

通常、107~128行目辺りを自分の環境に合うように調整すればOKだと思う。
必要なら132~192行目辺りも修正して下さい(特にSyntax Highlighterの相対パスが違う場合)。

自己満足の世界なんでどこまでやるかはご自由に。ブログのウィジェットとかまでは埋め込んでません。

$ ruby mkd2html -f -t "nukinoの日記" -s "パソコン関係の備忘録" 111218.mkd 111218.html

みたいな感じで実行してやると以下のようなプレビュー画面になります

プレビュー画面1

テーマ:Morgan Noirの場合のスタイルシートファイルと必要な画像ファイルをローカルに入れておくと以下のような感じ

プレビュー画面2

スクリプトの説明

ファイル名から日付の取得(80~100行目)

渡されたMarkdownファイルのファイル名によって日付を取得します。

現在は見出しにしか使われてませんが、イメージのパス書くの面倒くさくなってきたので、スクリプト内で置換する機能をつくる際に使用予定です。

先頭から何文字が数字かによって意味が異なります。

現在の日付が2011/12/18だとすると、以下のようなルールになります

  1. 入力ファイル名の先頭2文字が数字(13_hoge.mkdなど)
    年=現在、月=現在、日=13と評価(2011/12/13)
  2. 入力ファイル名の先頭4文字が数字(1113_hoge.mkdなど)
    年=現在、月=11、日=13と評価(2011/11/13)
  3. 入力ファイル名の先頭6文字が数字(121113_hoge.mkdなど)
    年(下2桁)=12、月=11、日=13と評価(2012/11/13)
  4. 入力ファイル名の先頭8文字が数字(20121113_hoge.mkdなど)
    年=2012、月=11、日=13と評価(2012/11/13)
5.それ以外
年=現在、月=現在、日=現在と評価(2011/12/18)
Syntax Highlighter用のJavaScript定義について

<head>内に記述すると動かなかったので、</body>の後にまとめて書いてあります。(Syntax Highlightr公式のページソースがそうなってたので)

<script type="text/javascript" src="~">みたいにソースコード埋め込みの部分は<head>内に書くのが流儀なのかもしれませんが、その辺専門じゃないんでよく分からなかったりします(^^ゞ

あと昨日の導入例の際には言及しませんでしたが、configurationはAutoloadの前でないと動きませんでした(Syntax Highlighter 3.0.83)。仕様かバグかは分かりません。

スクリプトの使い方

基本的には昨日のと同じ

$ ruby mkd2html [option] input_mkd_file output_html_file

こんな感じで実行します。
入力ファイルは規定の外部エンコーディングEncoding.default_externalのファイルを指定します。Windows XPなら’Windows-31J’(cp932、Shift-JIS)で書いたファイルを渡します。出力のHTMLファイルはUTF-8エンコーディングで出力されます。

オプションの説明
-f、–full
<HTML><HEAD><BODY>タグなどを付加した本当のHTMLファイルを作ります。
-w VAL、–tabwidth VAL
<pre>タグ内のタブをスペースに変換する際のタブ幅を指定します。
例:-w 4
-d VAL、–date_fmt VAL
ファイル名から日付取得した日付を見出し文字列にする際のフォーマット文字列を指定します。rubyドキュメントのDate#strftime参照。
‘#{xxx}`と書くと式展開される(多分)。規定の外部エンコーディング文字列で指定する
例:-d “%Y年%m月%d日(#{%w(日 月 火 水 木 金 土)[dt.wday]})”
–[no-]blog
option  
–blog -fが指定されてるとき、ブログ表示に近づける完全なHTMLファイルを作成します
  -fが指定されてないとき、ブログアップ用表記(見出しシフトなど)で作成します
–no-blog kramdown変換だけ行います(<pre>タグ内のタブ→スペース変換は行う)
-t VAL、–title VAL
ブログタイトルを指定する。規定の外部エンコーディング文字列で指定する 例:-t “Archive of nukino”
-s VAL、–sub-title VAL
ブログサブタイトルを指定する。規定の外部エンコーディング文字列で指定する 例:-s “パソコン関係の備忘録”
使い方のヒント

私は今のところこんなバッチファイルを作って運用してます

ruby mkd2html.rb -t "Archive of  nukino" -s "パソコン、プログラム関係の備忘録"  %1 %2 %3
if %ERRORLEVEL%==0 goto SUCCESS
PAUSE
EXIT
:SUCCESS
if "%1"=="-f" GOTO FULL
notepad "%2"
EXIT
:FULL

1.作業中プレビューしたいとき

$ mkd2html.bat -f 111218.mkd 111218.html

とするとfirefoxでプレビュー出来ます。

2.ブログにアップするときは

$ mkd2html.bat 111218.mkd 111218.html

とすると、notepad が起動するのでコピペします。ちなみに一番最後に記事タイトル(除去されたH1見出し)がくっついてるので、これを記事タイトルの方へコピペします。

vim使いの場合、Markdownファイルがカレントバッファの状態で

:!start mkd2html.bat % %:t:r.html
:!start mkd2html.bat -f % %:t:r.html

とかするとファイル名打たなくて済むんで便利です。

quickrun.vimとか導入するともっと便利になるのかもしれません。

Internet Explorer使用時の注意

Internet ExplorerでHTMLファイルを閲覧しようとすると

フォルダイメージ

みたいな表示が出て鬱陶しい!という人は

  • Internet Explorer以外のブラウザを使う(ぉぃ

または

  • [ツール インターネットオプション]の詳細設定ページの
    • セキュリティ → マイコンピュータでのCDのアクティブ コンテンツの実行を許可する(不要かも)
    • セキュリティ → マイコンピュータのファイルでのアクティブコンテンツの実行を許可する

    の2つにチェックを入れる
    フォルダイメージ

のどれかで対策して下さい。


今日はここまで。あとはイメージ(画像)系をもう少しだけ便利にする予定。

トラックバック

このページのトラックバックURL:
http://app.blog.eonet.jp/t/trackback/558347/27620895

eoblogをMarkdown記法で書く3(プレビュー)を参照しているブログ:

コメント

コメントを投稿

最近のコメント