bootstrap を使ってリニューアル の変更点

更新


[[FrontPage]]

#contents

* 概要 [#vc3edbd8]

これまでこのサイトでは、pukiwiki の標準に近いスキンを使っていたのですが、
昨今の [[Google:モバイルファースト]] の流れに乗り、
[[Google:Bootstrap]] を使ってリニューアルすることにしまた。

2015-02-19 より、新しいスキンで運用を始めています。

* まずは開発用環境を一式整える [#n21779a4]

* php をインストール [#i6f4a7d3]

一緒に unzip も。

 LANG: console
 $ sudo aptitude install libapache2-mod-php5 unzip

* パーミッションの調整 [#i5f22d0a]

自分が www-data グループに入っていることを確認した上で、
/var/www 以下を www-data グループの人間が自由にいじれるようにする

 LANG: console
 $ groups
  osamu ... www-data ...
 $ cd /var/www
 $ sudo chgrp -R www-data .
 $ sudo chmod -R g+r .
 $ sudo find . -type d -exec chmod g+wx {} \;

* ファイルを展開 [#f948038b]

 LANG: console
 $ cd /var/www/html
 $ unzip ~/pukiwiki-1_5_0_utf8.zip
 $ mv pukiwiki-1_5_0_utf8 pukiwiki
 $ cd pukiwiki
 $ chgrp -R www-data .
 $ chmod -R o-rwx .

ここまでで http://localhost/pukiwiki へアクセス可能

* git を導入 [#b1f3a1e2]

 LANG: console
 $ git init
 $ cat > .gitignore
  *~
  *.BAK
  
  .gitignore
  
  attach
  backup
  cache
  counter
  diff
  image
  trackback
  wiki
  ^D
 $ 

* 古いデータを UTF-8 に変換する [#lda1e9c7]

古い wiki のデータは EUC で保存されていたので、
これを UTF-8 に変換する必要がありました。

古い wiki のディレクトリで以下のスクリプトを走らせることで do.sh 
というファイルを作成して、source コマンドでシェルに食べさせればできました。

convert.php
 LANG:php(linenumber)
 <?php
 
 # 与えられた名前のディレクトリの $pattern にマッチする
 # ファイルのファイル名(hex2bin でエンコード済み)を 
 # EUC-JP から UTF-8 に変換してコールバック関数を呼び出す
 function convert_dir(
     $dir_name, 
     $callback,    # function($src, $dest) { ... }
     $pattern = "/^(?!\.)([0-9A-F][0-9A-F]|_)*(\..*)?$/")
 {
   $file_names = files_in_dir($dir_name, $pattern);
   
   print "mkdir ${dir_name}_utf8\n";
   foreach ($file_names as $index => $file_name) {
     $src = $dir_name . "/" . $file_name;
     $dest = $dir_name . "_utf8/" . convert_filename($file_name);
     $callback($src, $dest);
   }
 }
 
 # 与えられた名前のディレクトリの $pattern にマッチする
 # ファイルを列挙した配列を返す
 function files_in_dir($dir_name, $pattern)
 {
   $file_names = [];
   
   $h_dir = opendir( $dir_name );
   while ( $file_name = readdir( $h_dir ) ) {
     if ( ! preg_match($pattern, $file_name) )
       continue;
   	$file_names[] = $file_name;
   }
   closedir( $h_dir );
   
   return $file_names;
 }
 
 # EUC-JP をエンコードしたファイル名を受け取って
 # UTF-8 をエンコードしたファイル名にして返す
 # ファイル名はエンコードされていない拡張子や "_" を
 # 含んでいる場合があるため、それら以外の部分を変換する
 function convert_filename($file_name)
 {
 	preg_match("/^([^\.]*?)(\..*|)$/", $file_name, $matches); # 必ずマッチする
 	$base_name = $matches[1];
 	$extention = $matches[2];
 	return implode("_", array_map("convert_code", explode("_", $base_name))) . $extention;
 }
 
 # EUC-JP をエンコードした文字列を受け取って
 # UTF-8 をエンコードした文字列にして返す
 function convert_code($s)
 {
   return strtoupper( bin2hex( mb_convert_encoding( hex2bin($s), "UTF-8", "EUC-JP" ) ) );
 }
 
 #
 # 変換処理のバリエーション
 #
 
 function adjust_time_stamp($s, $d) 
 {
   print "touch -r $s $d\n";
 }
 
 function simple_copy($s, $d) 
 {
   print "cp $s $d\n";
   adjust_time_stamp($s, $d);
 }
 
 function simple_convert($s, $d) 
 {
   print "nkf -w $s > $d\n";
   adjust_time_stamp($s, $d);
 }
 
 function gzip_convert($s, $d) 
 {
   print "gunzip -c $s | nkf -w | gzip > $d\n";
   adjust_time_stamp($s, $d);
 }
 
 #
 # 各ディレクトリに対して必要な処理を標準出力に表示する
 #
 
 convert_dir("attach", simple_copy);
 
 convert_dir("backup", gzip_convert);
 
 convert_dir("cache", simple_convert);
 simple_convert("cache/recent.dat", "cache_utf8/recent.dat");
 
 convert_dir("counter", simple_copy);
 
 convert_dir("diff", simple_convert);
 
 convert_dir("wiki", simple_convert);
 
 ?>

 LANG:console
 $ php5 convert.php > do.sh
 $ less do.sh
 $ source do.sh

こうして変換した後、????_utf8/* を新しい wiki の対応するフォルダにコピーしました。

* スキンをいじる [#fc6de793]

 LANG:console
 $ ls skin/
  index.html       pukiwiki.css.php   tdiary.css.php
  keitai.skin.php  pukiwiki.skin.php  tdiary.skin.php
 $ grep \\.skin\\. *
  INSTALL.txt:      ※スキン(外見の骨組み)に関する設定項目は skin/スキン名.skin.php の先頭に
  default.ini.php:        define('SKIN_FILE', DATA_HOME . SKIN_DIR . 'tdiary.skin.php');
  default.ini.php:        define('SKIN_FILE', DATA_HOME . SKIN_DIR . 'pukiwiki.skin.php');
  keitai.ini.php:define('SKIN_FILE', DATA_HOME . SKIN_DIR . 'keitai.skin.php');
  pukiwiki.ini.php:// Skin files (SKIN_DIR/*.skin.php) are needed at
 $ jed default.ini.php
 $ git diff default.ini.php
  diff --git a/default.ini.php b/default.ini.php
  index 2f5259a..3a0b3ac 100644
  --- a/default.ini.php
  +++ b/default.ini.php
  @@ -11,11 +11,7 @@
   /////////////////////////////////////////////////
   // Skin file
  
  -if (defined('TDIARY_THEME')) {
  -       define('SKIN_FILE', DATA_HOME . SKIN_DIR . 'tdiary.skin.php');
  -} else {
  -       define('SKIN_FILE', DATA_HOME . SKIN_DIR . 'pukiwiki.skin.php');
  -}
  +define('SKIN_FILE', DATA_HOME . SKIN_DIR . 'bootstrap.skin.php');
  
   /////////////////////////////////////////////////
   // 雛形とするページの読み込みを可能にする

* bootstrap の theme を落としてくる [#c938c183]

http://www.bootbundle.com/ から良さそうなのを探して・・・

これとかどうかしら?

http://ironsummitmedia.github.io/startbootstrap-sb-admin-2/pages/index.html

 LANG:console  
 $ cd skin/
 $ wget https://github.com/IronSummitMedia/startbootstrap-sb-admin-2/archive/v1.0.5.zip
 $ unzip v1.0.5.zip
 $ mv startbootstrap-sb-admin-2-1.0.5/index.html sb-admin2.html
 $ mv startbootstrap-sb-admin-2-1.0.5/* .
 $ rm -r startbootstrap-sb-admin-2-1.0.5/ v1.0.5.zip
 $ rm LICENSE README.md
 $ cp pukiwiki.skin.php bootstrap.skin.php
 $ cd ..
 $ git add .
 $ git commit -m "sb-admin-2 added"

http://localhost/pukiwiki/skin/sb-admin2.html で sb-admin2 のテーマを表示できるようになりました。

* スキンの変更 [#mfc597c4]

pukiwiki.skin.php の

 LANG:php
 // ------------------------------------------------------------
 // Output
 
以降に sb-admin2.html の内容を移していきます。

** 不必要な設定をごっそり削除 [#cd528615]

Output の前までを

 LANG:php
 <?php
 
 // ------------------------------------------------------------
 // Code start
 
 // Prohibit direct access
 if (! defined('UI_LANG')) die('UI_LANG is not set');
 if (! isset($_LANG)) die('$_LANG is not set');
 if (! defined('PKWK_READONLY')) die('PKWK_READONLY is not set');
 
 $lang  = & $_LANG['skin'];
 $link  = & $_LINK;
 $image = & $_IMAGE['skin'];
 $rw    = ! PKWK_READONLY;

まで削りました。

** ヘッダー部分 [#d469b067]

- DOCTYPE は html5
- 文字セットは UTF-8 固定

とするため、

- http://dqn.sakusakutto.jp/2011/08/content-type-texthtml-charset-utf8.html
- http://coliss.com/articles/build-websites/operation/work/generic-html5-template-by-sixrevisions.html
- skin/pages/index.html

を参考にしながら、以下のようにしました。

 LANG:php
 // ------------------------------------------------------------
 // Output
 
 // HTTP headers
 pkwk_common_headers();
 header('Cache-control: no-cache');
 header('Pragma: no-cache');
 header('Content-Type: text/html; charset=UTF-8');
 ?>
 <!DOCTYPE html>
 <html lang="ja">
 <head>
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <!-- meta name="description" content="" -->
   <meta name="author" content="<?php echo $modifier ?>">
   <meta name="date" content="<?php echo $lastmodified ?>">
   <?php if ($nofollow || ! $is_read)  { ?> <meta name="robots" content="NOINDEX,NOFOLLOW" /><?php } ?>
 
   <title><?php echo $title ?> - <?php echo $page_title ?></title>
 
   <link rel="SHORTCUT ICON" href="<?php echo $image['favicon'] ?>" />
   <link rel="alternate" type="application/rss+xml" title="RSS" href="<?php echo $link['rss'] ?>" /><?php // RSS auto-discovery ?>
 
   <link href="skin/bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
   <link href="skin/bower_components/metisMenu/dist/metisMenu.min.css" rel="stylesheet">
   <link href="skin/dist/css/timeline.css" rel="stylesheet">
   <link href="skin/dist/css/sb-admin-2.css" rel="stylesheet">
   <link href="skin/bower_components/morrisjs/morris.css" rel="stylesheet">
   <link href="skin/bower_components/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css">
   <!--[if lt IE 9]>
       <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
       <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
   <![endif]-->
 
   <?php echo $head_tag ?>
 </head>

これにともない、lib/html.php の pkwk_output_dtd は必要なくなっています。

** $lastmodified について [#b12d8e08]

フォーマットが良くないので、変更したい。

 LANG:console
 $ grep lastmodified lib/*
  ...
  lib/html.php:   $lastmodified = $is_read ?  format_date(get_filetime($_page)) .
 $ less lib/html.php
         $lastmodified = $is_read ?  format_date(get_filetime($_page)) .
                 ' ' . get_pg_passage($_page, FALSE) : '';
 $ less lib/func.php
  function format_date($val, $paren = FALSE)
  {
          global $date_format, $time_format, $weeklabels;
  
          $val += ZONETIME;
  
          $date = date($date_format, $val) .
                  ' (' . $weeklabels[date('w', $val)] . ') ' .
                  date($time_format, $val);
  
          return $paren ? '(' . $date . ')' : $date;
  }
 $ grep date_format *
  pukiwiki.ini.php:$date_format = 'Y-m-d';
  ...

せっかく $date_format と $time_format を指定できるのに $weeklabels が必ず入ってしまう仕様。そして get_pg_passage も入っちゃう。

似たような関数に get_date もあって、こっちも同じ。

できれば出力を <time> タグで括って、datetime="" の属性に iso 8601 フォーマットで正確な日付を出力したい。そうしておけば後から Javascript などでいろいろできるはず(& new プラグインと被るけど・・・)。 [[Google:html5 time]]

 LANG:php
 function format_date_with_tag($val, $paren = FALSE)
 {
   return wrap_with_time_tag(format_date($val, $paren), $val);
 }
 
 function wrap_with_time_tag($display, $time = UTIME)
 {
   $datetime = date('c', $time);
        return "<time datetime=\"$datetime\">$display</time>";
 }

として、

 LANG:php
        $lastmodified = $is_read ? format_date_with_tag(get_filetime($_page)) .
                 ' ' . get_pg_passage($_page, FALSE) : '';

とすれば、上記の meta タグを

 LANG:php
  <meta name="date" content="<?php echo preg_replace('/.*\"(.*)\".*/', '\\1', $lastmodified) ?>">

とすることで ISO 8601 形式の日付を入れられます。

& new プラグインや # comment プラグインなどとも整合性がとれるようにいろいろいじる必要があるけれど・・・

** navbar で囲む [#r1656382]

 LANG:html
 <body>
 <div id="wrapper">
 
     <!-- Navigation -->
     <nav class="navbar navbar-default navbar-static-top" role="navigation" style="margin-bottom: 0">
         <div class="navbar-header">
             <!-- 左上のサイト名部分 -->
         </div>
         <ul class="nav navbar-top-links navbar-right">
             <!-- 上部のバー -->
         </ul>
         <div class="navbar-default sidebar" role="navigation">
             <!-- 左部のバー -->
         </div>
     </nav>
  
     <div id="page-wrapper">
         <!-- 本文 -->
     </div>
 
 </div>
 </body>

という構造なので、本文部分を上記で囲み、

 LANG:php
      <!-- 左部のバー -->
      <?php if (arg_check('read') && exist_plugin_convert('menu')) { ?>
        <div id="menubar"><?php echo do_plugin_convert('menu') ?></div>
      <?php } ?>

として、サイドメニューを左部に読み込むようにしました。

** 編集メニューをトップバーに移す [#x6e0be42]

 LANG:php
    <ul class="nav navbar-top-links navbar-right">
      <!-- 上部のバー -->
      <?php include "navbar-top.php" ?>
    </ul>

として、

 LANG:php
 <li class="dropdown">
     <a class="dropdown-toggle" data-toggle="dropdown" href="#">
       <i class="fa fa-edit fa-fw"></i> <i class="fa fa-caret-down"></i>
     </a>
     <ul class="dropdown-menu">
         <?php
         function _navigator($key, $value = '', $javascript = ''){
         	$lang = & $GLOBALS['_LANG']['skin'];
         	$link = & $GLOBALS['_LINK'];
         	if (! isset($lang[$key])) { echo 'LANG NOT FOUND'; return FALSE; }
         	if (! isset($link[$key])) { echo 'LINK NOT FOUND'; return FALSE; }
         	if (! PKWK_ALLOW_JAVASCRIPT) $javascript = '';
 
         	echo '<a href="' . $link[$key] . '" ' . $javascript . '>' .
         		(($value === '') ? $lang[$key] : $value) .
         		'</a>';
 
         	return TRUE;
         }
         ?>
 
         <?php if ($is_page) { ?>
           <?php if ($rw) { ?>
         	  <li><?php _navigator('edit') ?>
         	  <?php if ($is_read && $function_freeze) { ?>
         		  <li><?php (! $is_freeze) ? _navigator('freeze') : _navigator('unfreeze') ?>
         	  <?php } ?>
           <?php } ?>
           <li><?php _navigator('diff') ?>
           <?php if ($do_backup) { ?>
         	  <li><?php _navigator('backup') ?>
           <?php } ?>
           <?php if ($rw && (bool)ini_get('file_uploads')) { ?>
         	  <li><?php _navigator('upload') ?>
           <?php } ?>
           <li><?php _navigator('reload') ?>
           <li class="divider"></li>
         <?php } ?>
 
         <?php if ($rw) { ?>
           <li><?php _navigator('new') ?>
         <?php } ?>
         <li><?php _navigator('list') ?>
         <?php if (arg_check('list')) { ?>
           <li><?php _navigator('filelist') ?>
         <?php } ?>
         <li><?php _navigator('search') ?>
         <li><?php _navigator('recent') ?>
         <li><?php _navigator('help')   ?>
 
         <?php if ($trackback) { ?>
           <li class="divider"></li>
           <li><?php _navigator('trackback', $lang['trackback'] . '(' . tb_count($_page) . ')',
          	  ($trackback_javascript == 1) ? 'onclick="OpenTrackback(this.href); return false"' : '') ?>
         <?php } ?>
         <?php if ($referer)   { ?> &nbsp;
           <li class="divider"></li>
           <li><?php _navigator('refer') ?>
         <?php } ?>
     </ul>
 </li>

* highlight.js [#zce90f22]
* math.inc.php [#n82749c6]
* mathjax.inc.php [#b5021d3c]
* recaptcha - Google [#r323f860]
* lastmodified [#heff0364]
* breadscrum [#peaf4b89]
* 編集可能・不可能での表示・非表示 [#g80ae2b9]
* heading にナビを追加 [#v7d66ad8]

paraedit.inc.php への対応と合わせて、以下のようにすることで見出しにナビを追加しました。

lib/convert_html.php
 LANG:PHP
 <?php
 function convert_html($lines)
 {
   global $vars, $digest;
   static $contents_id = 0;
 
   // Set digest
   $digest = md5(join('', get_source($vars['page'])));
 
   if (! is_array($lines)) $lines = explode("\n", $lines);
 
   $body = & new Body(++$contents_id);
   $body->parse($lines);
 
   $headings = [];
   foreach($body->elements as $key=>$element) {
     if (is_a($element, 'Heading')) {
       $headings[] = $element;
     }
   }
 
   for($i=0; $i<count($headings); $i+=1){
     if (preg_match('/<a class="anchor_super" id="([^"]*)"/', $headings[$i]->elements[0]->elements[0], $match)){
       $star = 'href="#' . $match[1] . '"';
     }else{
       $star = '';
     }
     if ($i<count($headings)-1) {
       $next = 'href="#' . $headings[$i+1]->id . '"';
     } else {
       $next = '';
     }
     if ($i>0) {
       $prev = 'href="#' . $headings[$i-1]->id . '"';
     } else {
       $prev = '';
     }
     $paraedit = "?plugin=paraedit&amp;parnum=" .($i+1). "&amp;page=" . rawurlencode($vars['page']) . '&amp;refer=' . rawurlencode($vars['page']);
     $navi = "\n" . <<< EOS
       <div class="header-navi btn-group" role="group">
       <a class="btn btn-default btn-sm" $star title="anchor"><i class="fa fa-star-o"></i></a>
       <a class="btn btn-default btn-sm" $next title="next"><i class="fa fa-angle-down"></i></a>
       <a class="btn btn-default btn-sm" $prev title="prev"><i class="fa fa-angle-up"></i></a>
       <a class="btn btn-default btn-sm" href="#navigator" title="top"><i class="fa fa-angle-double-up"></i></a>
       <a class="btn btn-default btn-sm if-rw" href="$paraedit" title="edit" ><i class="fa fa-pencil"></i></a>
       </div>
 EOS;
     array_splice($headings[$i]->elements, 0, 0, [new Inline($navi)]);
   }
 
   return $body->toString();
 }

skin/bootstrap.css.php

 LANG:css
 /* 見出しの上に出すナビゲーション */
 
 .header-navi {
   display: none;
 }
 
 :hover > .header-navi {
   display: block;
 }
 
 .header-navi {
   position: absolute;
   top: 0px;
   opacity: 0.4;
   transition: opacity 0.3s;
 }
 
 .header-navi:hover {
   opacity: 1;
 }
 
 /* 見出しに付けるダガー */
 
 .anchor_super
 {
   vertical-align: super;
   font-size: smaller;
   opacity: 0.4;
 }
 
 @media print {
   .anchor_super { display: none }
 }
 
 /* 書き込み権限があるときのみ表示 */
 
 body.ro .if-rw {
   display: none;
 }

Counter: 8506 (from 2010/06/03), today: 1, yesterday: 0