今日は、nucleusの投稿(ポップアップ)画面のカスタマイズに取り掛かろう。

デフォルトでは、“Bボタン=文字を太字にする(<b>要素を付加)”と“Iボタン=文字をイタリック体にする(<i>要素を付加)”および“リンクボタン=文字にリンクを張る(<a>要素を付加)”の3つのボタンがある。

まず、<b>、<i>の“物理的フォントタグ”。これ嫌い。個人的に。

これらをまず“論理的タグ”である<strong>、<em>に置換する。

ちなみに<em>は強調(emphasis)で、ほとんどのブラウザのデフォルトスタイルシートではfont-style: italic;となっている。さらに強い強調が<strong>で、同じくデフォルトではfont-style: bold;となっている。

■<b>、<i>ボタンのカスタマイズ■

・nucleus\imagesディレクトリに、適当なボタン用画像を作成し、button-strong.gifおよびbutton-emphasis.gifとして保存。

nucleus\javascriptディレクトリのedit.js中の110行目付近に、

function boldThis() { insertAroundCaret('<b>','</b>'); }
function italicThis() { insertAroundCaret('<i>','</i>'); }

とあるので、これらを

function strongThis() { insertAroundCaret('<strong>','</strong>'); }
function emphasisThis() { insertAroundCaret('<em>','</em>'); }

に変更。

nucleus\languageディレクトリのenglish.phpおよびenglish-utf-8.php中の857行目に、

define('_ADD_BOLD_TT',  'Bold');
define('_ADD_ITALIC_TT',  'Italic');

とあるので、これらを

define('_ADD_STRONG_TT',  'Strong');
define('_ADD_EMPHASIS_TT',  'Emphasis');

に変更。

同じくnucleus\languageディレクトリのjapanese-euc.phpおよびjapanese-utf-8.php中の873行目に、

define('_ADD_BOLD_TT',  '太字');
define('_ADD_ITALIC_TT',  '斜体');

とあるので、これらを

define('_ADD_STRONG_TT',  '強い強調');
define('_ADD_EMPHASIS_TT',  '弱い強調');

に変更。

nucleus\libsディレクトリのPAGEFACTORY.php中の425行目の_jsbutton($type, $code ,$tooltip)関数

function _jsbutton($type, $code ,$tooltip) {
?>
  <span class="jsbutton"
    onmouseover="BtnHighlight(this);"
    onmouseout="BtnNormal(this);"
    onclick="<?php echo $code?>" >
    <img src="images/button-<?php echo $type?>.gif" alt="<?php echo $tooltip?>" title="<?php echo $tooltip?>" width="16" height="16"/>
  </span>
<?php	}

の記述があり、_jsbutton関数の第1引数がボタンの画像名の“button-”以降、第2引数がedit.jsの関数名、第3引数がボタン名になっている。

したがって308行目にparse_jsbuttonbar関数が記述されており、320行目付近に

$this->_jsbutton('bold',"boldThis()",_ADD_BOLD_TT ." (Ctrl + Shift + B)");
$this->_jsbutton('italic',"italicThis()",_ADD_ITALIC_TT ." (Ctrl + Shift + I)");

とあるので、これらを

$this->_jsbutton('strong',"strongThis()",_ADD_STRONG_TT ." (Ctrl + Shift + S)");
$this->_jsbutton('emphasis',"emphasisThis()",_ADD_EMPHASIS_TT ." (Ctrl + Shift + E)");

に変更。

同じく350行目付近に

$this->_jsbutton('bold',"boldThis()",_ADD_BOLD_TT);
$this->_jsbutton('italic',"italicThis()",_ADD_ITALIC_TT);

とあるので、これらを

$this->_jsbutton('strong',"strongThis()",_ADD_STRONG_TT);
$this->_jsbutton('emphasis',"emphasisThis()",_ADD_EMPHASIS_TT);

に変更。

・スタイルシートに、

strong {
  font-weight: bold;
}

em {
  background-color: #FFFFCC;
  font-style: normal;
}

と記述。

以上でカスタマイズ完了。

本来<em>はfont-style: oblique;を指定したかったのだが、当サイトで使用している日本語フォント'ヒラギノ角ゴ Pro W3'に斜体が用意されていないため、断念。

代替案として、背景色を変更することにした。

ちなみに、font-style: normal;を指定しておかないと、デフォルトで英字・数字といった半角文字がイタリックになるので注意

次は、引用<blockquote>のボタンを新設することに。
本来は手作業で引用文をまるまる<blockquote>~</blockquote>で括ればよいのだが、
“blockquote”という文字をいちいち入力するのがめんどくさい。
このボタンは選択した文章の前後にタグを追加するというものなので、
基本的にはデフォルトの“Bボタン”や“Iボタン”と同じものを作ればよい。

■<blockquote>ボタンのカスタマイズ■

・nucleus\imagesディレクトリに、適当なボタン用画像を作成し、button-quote.gifとして保存。

nucleus\javascriptディレクトリのedit.js中の110行目付近に、

function quoteThis() { insertAroundCaret('<blockquote>\n','\n</blockquote>'); }

を追加。

nucleus\languageディレクトリのenglish.phpおよびenglish-utf-8.php中の857行目に、

define('_ADD_QUOTE_TT',	'Blockquote');

を追加。

同じくlanguageディレクトリのjapanese-euc.phpおよびjapanese-utf-8.php中の873行目に、

define('_ADD_QUOTE_TT',	'引用');

を追加。

nucleus\libsディレクトリのPAGEFACTORY.php中の320行目付近に

$this->_jsbutton('quote',"quoteThis()",_ADD_QUOTE_TT ." (Ctrl + Shift + Q)");

を追加。

同じく350行目付近に

$this->_jsbutton('quote',"quoteThis()",_ADD_QUOTE_TT);

を追加。

以上でカスタマイズ完了。

ポイントは、'<blockquote>\n','\n</blockquote>'の部分。

しょおもないことだが、インライン要素の<strong>や<em>と異なり<blockquote>はブロック要素なので、開始タグのあとと終了タグの前にそれぞれ改行を入れておいた。

ああ、しょおもない。

最後は、<js>ボタン、<css>ボタン、<php>ボタン、<xhtml>ボタンを新設することに。

昨日、ソースコードビューライブラリ“syntaxhighlighter 3.0.83”を導入した。

ソースコードの前後に<pre class="brush:xxx"></pre>(xxxはphpやcssなどのソースの種類)を付加してやると、自動的に行番号が付加され、行ごとに色分けされるなど、非常にコードが見やすくなるスグレモノだ。

ただ、基本中の基本として、コード中の“&”や“<”などのメタ文字は“&amp;”や“&lt;”などの実体参照に置換する必要がある。

これはさすがにいちいち手作業ではやってられないため、自動変換のボタンを作ることにした。

■<js>ボタン、<css>ボタン、<php>ボタン、<xhtml>ボタンのカスタマイズ■

・nucleus\imagesディレクトリに、適当なボタン用画像を作成し、button-js.gif、button-css.gif、button-php.gif、button-xhtml.gifとして保存。

nucleus\javascriptディレクトリのedit.js中にメタ文字(およびタブ文字)を実体参照に変換するchangeEntity関数を作成。

function changeEntity(strtxt) {
  strtxt = strtxt.replace(/&/g,'&amp;');
  strtxt = strtxt.replace(/"/g,"&quot;");
  strtxt = strtxt.replace(/'/g,"&#039;");
  strtxt = strtxt.replace(/</g,"&lt;");
  strtxt = strtxt.replace(/>/g,"&gt;");
  strtxt = strtxt.replace(/\t/g,"&nbsp;&nbsp;");
  return strtxt;
}

nucleus\javascriptディレクトリのedit.js中の118行目のahrefThis関数

function ahrefThis() {
  if (document.selection)
    strSelection = document.selection.createRange().text;
  else
    strSelection = '';

  strHref = prompt("Create a link to:","http://");
  if (strHref == null) return;

  var textpre = "<a href=\"" + strHref.replace(/&/g,'&amp;') + "\">";
  insertAroundCaret(textpre, "</a>");
}

と、266行目insertAroundCaret関数

function insertAroundCaret (textpre, textpost) {
  var textEl = lastSelected;
	
  if (textEl && textEl.createTextRange && lastCaretPos) {
    var caretPos = lastCaretPos;
    caretPos.text = textpre + caretPos.text + textpost;
  } else if (!document.all && document.getElementById) {
    mozWrap(document.getElementById('input' + nonie_FormType), textpre, textpost);
    if(scrollTop>-1) {
      document.getElementById('input' + nonie_FormType).scrollTop = scrollTop;
    }
  } else {
    document.getElementById('input' + nonie_FormType).value += textpre + textpost;
    if(scrollTop>-1) {
      document.getElementById('input' + nonie_FormType).scrollTop = scrollTop;
    }
  }

  updAllPreviews();
}

と、288行目mozWrap関数

function mozWrap(txtarea, lft, rgt) {
  var selLength = txtarea.textLength;
  var selStart = txtarea.selectionStart;
  var selEnd = txtarea.selectionEnd;
  if (selEnd==1 || selEnd==2) selEnd=selLength;
  var s1 = (txtarea.value).substring(0,selStart);
  var s2 = (txtarea.value).substring(selStart, selEnd)
  var s3 = (txtarea.value).substring(selEnd, selLength);
  txtarea.value = s1 + lft + s2 + rgt + s3;
}

を参考に、

function codeThis(code) {
  if (document.selection)
    selectedText = document.selection.createRange().text;
  else
    selectedText = '';

  strRow = prompt("最初の行番号を入力","1");
  if (strRow == null) return;

  var textpre = "<pre class=\"brush:" + code + "; auto-links:false; first-line:" + strRow + ";\">\n";
  var textpost = "\n</pre>";

  var textEl = lastSelected;
	
  if (textEl && textEl.createTextRange && lastCaretPos) {
    var caretPos = lastCaretPos;
    caretPos.text = textpre + changeEntity(caretPos.text) + textpost;
  } else if (!document.all && document.getElementById) {
    var txtarea = document.getElementById('input' + nonie_FormType);
    var selLength = txtarea.textLength;
    var selStart = txtarea.selectionStart;
    var selEnd = txtarea.selectionEnd;
    if (selEnd==1 || selEnd==2) selEnd=selLength;
    var s1 = (txtarea.value).substring(0,selStart);
    var s2 = (txtarea.value).substring(selStart, selEnd)
    var s3 = (txtarea.value).substring(selEnd, selLength);
    s2 = changeEntity(s2);
    document.getElementById('input' + nonie_FormType).value = s1 + textpre + s2 + textpost + s3;
    if(scrollTop>-1) {
      document.getElementById('input' + nonie_FormType).scrollTop = scrollTop;
    }
  } else {
    var txtarea = document.getElementById('input' + nonie_FormType);
    document.getElementById('input' + nonie_FormType).value = textpre + changeEntity(txtarea.value) + textpost;
    if(scrollTop>-1) {
      document.getElementById('input' + nonie_FormType).scrollTop = scrollTop;
    }
  }

  updAllPreviews();
}

を追加。
同じく115行目付近に、

function jsThis() { codeThis('js'); }
function cssThis() { codeThis('css'); }
function phpThis() { codeThis('php'); }
function xhtmlThis() { codeThis('xhtml'); }

を追加。

nucleus\languageディレクトリのenglish.phpおよびenglish-utf-8.php中の857行目に、

define('_ADD_JS_TT',	  'Js');
define('_ADD_CSS_TT',  'Css');
define('_ADD_PHP_TT',  'Php');
define('_ADD_XHTML_TT',  'Xhtml');

を追加。
同じくlanguageディレクトリのjapanese-euc.phpおよびjapanese-utf-8.php中の873行目に、

define('_ADD_JS_TT',  'JS');
define('_ADD_CSS_TT',  'CSS');
define('_ADD_PHP_TT',  'PHP');
define('_ADD_XHTML_TT',  'XHTML');

を追加。

nucleus\libsディレクトリのPAGEFACTORY.php中の308行目付近にparse_jsbuttonbar関数が記述されているので、
320行目付近に

$this->_jsbutton('js',"jsThis()",_ADD_JS_TT ." (Ctrl + Shift + J)");
$this->_jsbutton('css',"cssThis()",_ADD_CSS_TT ." (Ctrl + Shift + C)");
$this->_jsbutton('php',"phpThis()",_ADD_PHP_TT ." (Ctrl + Shift + P)");
$this->_jsbutton('xhtml',"xhtmlThis()",_ADD_XHTML_TT ." (Ctrl + Shift + X)");

を追加。
同じく355行目付近に

$this->_jsbutton('js',"jsThis()",_ADD_JS_TT);
$this->_jsbutton('css',"cssThis()",_ADD_CSS_TT);
$this->_jsbutton('php',"phpThis()",_ADD_PHP_TT);
$this->_jsbutton('xhtml',"xhtmlThis()",_ADD_XHTML_TT);

を追加。

以上でカスタマイズ完了。

これに関しては、“最初の行番号を入力”できるようにしたのがポイントかいねえ。
コードの種類の振り分けは各ボタンで、ということで。

以上の変更・追加を踏まえて、最後の仕上げでショートカットキーの設定の変更を行う。

まず、nucleus\javascriptディレクトリのedit.js中の88行目のshortCuts関数

function shortCuts() {
  if (!event || (event.ctrlKey != true)) return;

  switch (event.keyCode) {
    case 1:
      ahrefThis(); break; // ctrl-shift-a
    case 2:
      boldThis(); break; // ctrl-shift-b
    case 9:
      italicThis(); break; // ctrl-shift-i
    case 13:
      addMedia(); break; // ctrl-shift-m
    default:
      return;
  }
  return;
}

を以下のように変更。

function shortCuts() {
  if (!event || (event.ctrlKey != true)) return;

  switch (event.keyCode) {
    case 1:
      ahrefThis(); break; // ctrl-shift-a
    case 2:
      blockquoteThis(); break; // ctrl-shift-b
    case 3:
      cssThis(); break; // ctrl-shift-c
    case 5:
      emphasisThis(); break; // ctrl-shift-e
    case 13:
      addMedia(); break; // ctrl-shift-m
    case 18:
      phpThis(); break; // ctrl-shift-r
    case 19:
      strongThis(); break; // ctrl-shift-s
    case 22:
      jsThis(); break; // ctrl-shift-v
    case 24:
      xhtmlThis(); break; // ctrl-shift-x
    default:
      return;
  }
  return;
}

また、nucleus\formsディレクトリのadditemform.template中の27行目の

<span class="shortcuts">[ctrl+shift+A]&nbsp;=&nbsp;Link, [ctrl+shift+B]&nbsp;=&nbsp;Bold, [ctrl+shift+I]&nbsp;=&nbsp;Italic, [ctrl+shift+M]&nbsp;=&nbsp;Insert&nbsp;Media.</span>

を、

<span class="shortcuts">[ctrl+shift+A]&nbsp;=&nbsp;Link, [ctrl+shift+B]&nbsp;=&nbsp;Blockquote, [ctrl+shift+C]&nbsp;=&nbsp;CSS, [ctrl+shift+E]&nbsp;=&nbsp;Emphasis, [ctrl+shift+M]&nbsp;=&nbsp;Insert&nbsp;Media, [ctrl+shift+R]&nbsp;=&nbsp;PHP, [ctrl+shift+S]&nbsp;=&nbsp;Strong, [ctrl+shift+V]&nbsp;=&nbsp;JS, [ctrl+shift+X]&nbsp;=&nbsp;XHTML.</span>

に変更。

これらのショートカットキーはIE環境では他のキーとバッティングしないように設定したが、(javascriptのctrl+shift+Jやphpのctrl+shift+Pはバッティングしていて使えず)他のブラウザ環境ではメンドクサイから調べてない

自分しか使わないし、そもそもショートカットキーも使わないし、まあ、ええか。

いやあ、コードを注意深く見ていけば、ボクにもカスタマイズできるんだねえ。

なんだかちょっと賢くなった気がして、今日は満足。

いい夢見れそう。

気持ちよく、寝よう。