TinyMCEで”this.getdoc() is undefined”というエラー

TinyMCE 3.3系(jQuery版)を3.5.8に置き換えると、
this.getdoc() is undefined
というスクリプトエラーが出てTinyMCEが死にました。

どうやら、pluginの構成が変わってて “more” を呼び出してはいけない様子。
デモページに従って

plugins : "pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template",

に変更することで解決しました。

CKEditor4とKCFinderでビジュアルエディタを組み込んでマルチユーザーで使う

CMS的なものを作っているとWYSIWYG editorが必要になるシーンは多いかと思います。
いままで、Wordpressでも使い慣れた”TinyMCE“を使っていたのですが、iPadでの入力には非対応でした。(最新のTinyMCE3.5.8を入れてみたら問題なく対応してました。いつの間に……)
で、調べると”CKEditor“はiPad対応(v3.6.2-)とリリースノートにあるので、導入してみようかなと。

CKEditorを入れる

【インストール】

CKEditor“のサイトから、アーカイブをダウンロードしてきます。
(執筆時点で4.1.1が最新でした。)
ファイルを展開して出てくる”ckeditor”フォルダを適当なパスに配置します。
(ここでは、[rootDir]/js/ckeditor に置いたとします。)

使いたいページのHTMLで、スクリプトを読み込ませます。

<script src="/js/ckeditor/ckeditor.js" type="text/javascript"></script>

フォームのビジュアルエディタとしたいtextareaタグに、ckeditorクラスを振ります。

<textarea name="contents" style="width:400px;height:400px;" class="ckeditor" ></textarea>

おしまい。
後はブラウザで表示させるといい感じに表示されているかと思います。

【ツールバーのカスタマイズ】

ckeditor/config.js を編集すると、様々なカスタマイズが行えます。

デフォルトのツールバー設定が

config.toolbarGroups = [
        { name: 'document',    groups: [ 'mode', 'document', 'doctools' ] },
        { name: 'clipboard',   groups: [ 'clipboard', 'undo' ] },
        { name: 'editing',     groups: [ 'find', 'selection', 'spellchecker' ] },
        { name: 'forms' },
        '/',
        { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
        { name: 'paragraph',   groups: [ 'list', 'indent', 'blocks', 'align' ] },
        { name: 'links' },
        { name: 'insert' },
        '/',
        { name: 'styles' },
        { name: 'colors' },
        { name: 'tools' },
        { name: 'others' },
        { name: 'about' }
    ];

らしいのですが、要らない物も多いので編集しようとするのですが…
マニュアルを読んでもどうにもconfig.toolbarGroupsの値の設定がよく分かりません(==;
グループ化することでデフォルト設定を読んで余り弄らなくてもいい感じにしてくれるらしいんですが…細かく書いて好みにしたいんだよ!
ということで、config.toolbarの設定値を触ってカスタマイズしたいと思います。

デフォルトのツールバーは、下記コードで再現できます。

    config.toolbar = [
            ['Source','-','Save','NewPage','Preview','Print','-','Templates']
            ,['Cut','Copy','Paste','PasteText','PasteFromWord','-','Undo','Redo']
            ,['Find','Replace','-','SelectAll','Scayt']
            ,['Form','Checkbox','Radio','TextField','Textarea','Select','Button','ImageButton','HiddenField']
            ,'/'
            ,['Bold','Italic','Underline','Strike','Subscript','Superscript','-','RemoveFormat']
            ,['NumberedList','BulletedList','-','Outdent','Indent','-','Blockquote','CreateDiv','-','JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock']
            ,['Link','Unlink','Anchor']
            ,['Image','Flash','Table','HorizontalRule','Smiley','SpecialChar','PageBreak','Iframe']
            ,'/'
            ,['Styles','Format','Font','FontSize']
            ,['TextColor','BGColor']
            ,['Maximize','ShowBlocks']
            ,['About']
        ];

これを元に対応関係を見ながら自由に触ってください。
私は、

    config.extraPlugins = 'nbsp';
    config.toolbar = [
            ['Cut','Copy','Paste','PasteText','PasteFromWord','-','Undo','Redo']
            ,['Find','Replace']
              ,['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock']
            ,['NumberedList','BulletedList']
              ,['Outdent','Indent']
              ,['Table']
            ,['Source','Maximize','ShowBlocks']
            ,'/'
              ,['Format','FontSize']
            ,['Bold','Italic','Underline','Strike','Subscript','Superscript']
            ,['TextColor','BGColor']
            ,['RemoveFormat']
              ,['Blockquote','CreateDiv']
            ,['Link','Unlink','Anchor']
              ,['Image','HorizontalRule','Nbsp']
        ];

こんな感じで2段組にしています。
サイト内のお知らせ欄や簡易Blogの記入用に使うので、フォームなどのタグは外しています。
また、プレビューや保存・印刷はCMS上に機能を組み込むので外しました。
逆に、TinyMCEでは標準である「”&nbsp;”を入れる」プラグインを導入しています。pluginは、解凍後 ckeditor/plugins フォルダ内に置き、config.jsにて
config.extraPlugins = ‘hoge’;
のようにしてロードします。

【skinで見た目を変える】

デフォルトのskinが余りに地味というか視認性に欠けるので、公式のskinページから”Moono Color”をダウンロードしてきました。
ckwditor/skins/フォルダ内にskinを配置した後、
config.js にて
config.skin = ‘moonocolor’;
のようにskinを指定してあげればOKです。

【サンプル設定ファイル】

CKEDITOR.editorConfig = function( config ) {
    config.language = 'ja';

    config.filebrowserBrowseUrl = '/js/kcfinder/browse.php'; //?type=files';
    config.filebrowserImageBrowseUrl = '/js/kcfinder/browse.php'; //?type=images';
    config.filebrowserFlashBrowseUrl = '/js/kcfinder/browse.php'; //?type=flash';
    config.filebrowserUploadUrl = '/js/kcfinder/upload.php'; //?type=files';
    config.filebrowserImageUploadUrl = '/js/kcfinder/upload.php'; //?type=images';
    config.filebrowserFlashUploadUrl = '/js/kcfinder/upload.php'; //?type=flash';

    // HTMLソースの手動編集を行えるように、コードの自動整形を止める。
    config.allowedContent = true;

    config.extraPlugins = 'nbsp';
    config.toolbar = [
            ['Cut','Copy','Paste','PasteText','PasteFromWord','-','Undo','Redo']
            ,['Find','Replace']
              ,['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock']
            ,['NumberedList','BulletedList']
              ,['Outdent','Indent']
              ,['Table']
            ,['Source','Maximize','ShowBlocks']
            ,'/'
              ,['Format','FontSize']
            ,['Bold','Italic','Underline','Strike','Subscript','Superscript']
            ,['TextColor','BGColor']
            ,['RemoveFormat']
              ,['Blockquote','CreateDiv']
            ,['Link','Unlink','Anchor']
              ,['Image','HorizontalRule','Nbsp']
        ];

    config.skin = 'moonocolor';
    config.resize_enabled = 0;
    config.toolbarCanCollapse = 0;
    config.startupShowBorders = 0;
    config.enterMode = 1;
};

ファイルマネージャーを組み込む

CKEditor公式のCKFinderというものがあるのですが、そこそこお値段します。
今回はオープンソースの互換ファイルマネージャー「KCFinder」を使います。
KCFinderは2011年8月に2.51をリリースしたのが最後な為、CKEditor4系に対応してるか特に記述はないのですが、私が確認する限りでは特に問題ありませんでした。
しかも、日本語にもばっちり対応しています!
(TinyMCEにも対応しているようです)

【インストール】

KCFinder」の公式サイトより、アーカイブをダウンロードし、展開してから適当なフォルダに置きます。
(ここでは、/js/kcfinder/ にフォルダを置くものとします)

【基本的な動作確認】

kcfinder/config.phpの必要箇所を以下のように編集します。

$_CONFIG = array(
    'disabled' => false,
    'uploadURL' => "/uploads/",
    'uploadDir' => "../../uploads/",
);

KCFinderでは認証を通してからフォルダを見せるという動作を $_CONFIG['disabled']の値をON/OFFすることによって実現します。
ここでは、動作確認のため常に認証をパスさせる $_CONFIG['disabled'] = false; とします。
(trueにすると常に拒否します。デフォルトはtrueになっているので注意)

‘uploadURL’はブラウザから見たアップロードフォルダのURLになります。
サーバールートからの絶対パスにしておくと問題が少ないかと思います。
‘uploadDir’は、KCFinderのPHPスクリプトからのアップロードフォルダへのパスです。
設置フォルダからアップロードフォルダへの相対パスを入れましょう。

アップロード先のフォルダはPHPから書込が行えるようにパーミッションを設定して下さい。
通常[707]になると思われます。suexec対応サーバーの場合はそのまま[705]でいいかと。

次にCKEditorを設定します。
ckeditor/config.js に下記の設定を加えます。

CKEDITOR.editorConfig = function( config ) {
    config.filebrowserBrowseUrl = '/js/kcfinder/browse.php?type=files';
    config.filebrowserImageBrowseUrl = '/js/kcfinder/browse.php?type=images';
    config.filebrowserFlashBrowseUrl = '/js/kcfinder/browse.php?type=flash';
    config.filebrowserUploadUrl = '/js/kcfinder/upload.php?type=files';
    config.filebrowserImageUploadUrl = '/js/kcfinder/upload.php?type=images';
    config.filebrowserFlashUploadUrl = '/js/kcfinder/upload.php?type=flash';
};

リンク・イメージ・FLASHの各ボタンを押した際に呼び出すファイルマネージャーのURLになります。
type=***の部分によってKCFinderが開くフォルダを切り替えています。

以上を設定したら、ブラウザでCKEditorを設置したページにアクセスして、動作確認します。
ツールバーの「イメージ」アイコンをクリックして「サーバーブラウザ」を押してみて、ファイルマネージャーが起動すればOKです。
エラーが表示される場合は、アップロードフォルダへのパスが合っているか確認して下さい。

■メディアタイプごとのフォルダ設定とか

config.phpでは様々な設定を行えます。

    'deniedExts' => "exe com msi bat php phps phtml php3 php4 cgi pl",

実行ファイルなどのアップロード禁止のファイルタイプの拡張子を設定します。

    'types' => array(
        // CKEditor & FCKEditor types
        'files'   =>  "",
        'flash'   =>  "swf",
        'images'  =>  "*img",
    ),

CKEditorの各ボタンに対応して、アップロード可能なファイルタイプを設定出来ます。
もし、すべてuploads直下に置きたい場合は

    'types' => array(
        ''   =>  "",
    ),

のように設定する事でできます。
(ただ、エディタに渡されるファイルパスが”uploads//hoge.jpg”のようにスラッシュが重なってちょっと気持ち悪いです…(==;
なお、’types’ => array(), と設定してしまうとアップロード時にエラーとなります。

KCFinderのデフォルトではフォルダ内にPHPの実行を停止する.htaccessを作ろうとします。
が、こういったことはuploadsフォルダ自体で行えばいいと思うので、

    '_check4htaccess' => false,

上記設定で、この動作を停止します。

マルチユーザー対応の認証を組み込む

config.phpに認証機構を組み込みます。

global $_CONFIG;
$_CONFIG = array(
//  書き換え箇所のみを抜粋します。
//  基本は利用拒否する
    'disabled' => true,
    'uploadURL' => "/uploads/",
    'uploadDir' => "../../uploads/",

//  ここら辺の設定はお好みで。
    'types' => array(
        // CKEditor & FCKEditor types
        ''   =>  "",
    ),
    '_check4htaccess' => false,
);

//  ユーザー認証
if (!function_exists('KCF_CheckAuthentication')) {
    function KCF_CheckAuthentication()
    {
        global $_CONFIG;

        // 認証用のクラスを呼び出します。
        if (!class_exists('My_Auth')) {
            require('My/Auth.php');
        }

        // ここらへんで適当に認証処理します。
        // 認証成功するとアカウントIDを返し、失敗するとfalseを返すメソッドを実行したとします。
        $account = My_Auth::getAccount();
        if ($account) {
            //認証成功時に必要な処理があればする。IDを桁数揃えるとか。
        } else {
            // 認証失敗時はfalseを返して終了。
            return false;
        }

        // uploadsフォルダの下にアカウントごとにフォルダを作ってファイルを置くとします。
        $updir = '../../uploads/'.$account.'/';
        // 先にフォルダを作成しておきます。
        if (!is_dir($updir)) {
            mkdir($updir);
            chmod($updir, 0757);
        }

        // uploadURLなどをそのユーザー用の位置にセットします。
        $_CONFIG['uploadURL'] = "/uploads/".$account;
        $_CONFIG['uploadDir'] = $updir;

        return true;
    }
}

// ユーザー認証の実行
$_CONFIG['disabled'] = !KCF_CheckAuthentication();

認証関数内で$_CONFIGをglobalとしても呼び出すために、一番最初に $_CONFIG をglobal宣言しておきます。
config.phpは複数回呼び出されているようなので、function_exists関数を使って重複して宣言しないようにします。
(同じ理由で、外部のスクリプトを呼ぶ際もrequire_onceを使うなど重複させないようにしましょう)

一番最後にKCF_CheckAuthentication()を呼び出して、結果を$_CONFIG['disabled']へ返してやればOKです。
認証の実行とともにアップロード先フォルダを切り替えてやるので、アカウントごとに別のフォルダへファイルマネージャーを振ることが出来ました。

Lightbox風メディアビュアー”Fancybox”でPDFを表示する

マルチメディアギャラリーの中でLightboxのようなビュアーを組み込もうと思ったところ、PDFをどうしたものかなと。

PDFやSWF、youtubeなどに対応出来るLightboxライクなJavascriptとして、”Dumpbox“や”Fancybox“があります。

Dumpboxは、スタンドアロンなスクリプトで外部のライブラリを必要としないのですが、逆にJqueryに干渉することもあるっぽい…ようです?
後、個人的に見た目が派手すぎて気に食わなかったり(笑)

そんな理由で、今回はJqueryベースの”Fancybox“(v2.1.4)を使わせて頂く事にしました。

【設置方法】

解凍したら出てくる、”source”フォルダをfancybox等にリネームして、サーバーの適当な場所(この例ではjsフォルダの下)に置き、HTMLのheadタグ内で

<link rel="stylesheet" href="/js/fancybox/jquery.fancybox.css" type="text/css"/>
<script type="text/javascript" src="/js/jquery.js"></script>
<script src="/js/fancybox/jquery.fancybox.js" type="text/javascript"></script>

のように読み込ませます。

【基本的な使い方】

<a href=”hogehoge.jpg” class=”fancybox”>リンク用テキストorイメージ</a>

のようなタグをHTMLに書き置いて

<script type="text/javascript">
  $(document).ready(function($){
    $('a.fancybox').fancybox();
  });
</script>

でOKというお手軽仕様です。
後はブラウザ上でリンクを押すといい感じに表示してくれます。

【PDFを読ませる】
基本の例では、画像系ファイルしかビュアーが起動しません。
PDFに対応させるには一工夫要ります。
PDFなファイルの場合は別のCSSクラスを振って動作を分けるのが公式のサンプルにあるのですが……PG出力時に判定を書くのがめんどくさい(笑
ので、JS側で自動的にどうにかさせます。
いっそのこと、メディアファイルっぽいものはクラスを振らないでも全部ビュアーで見せることにします。

↓こんな感じ

<script type="text/javascript">
  $(document).ready(function($){
    $('a[href$=".jpg"] , a[href$=".gif"] , a[href$=".png"], .fancybox').fancybox();
    $('a[href$=".pdf"]').fancybox({
      autoSize: true,
      type:'iframe',
      iframe: {
        preload: false
      }
    });
  });
</script>

肝は    iframe: { preload: false } の記述です。
これが無いと、IEでPDFの読込が終わってくれたことを検知しないのか、何時までも読込画面のままになりました。

この例ではPDFの読込部分をiframeで記述してますがembedタグ(plugin読込)を使って書くことも出来ます。
↓こんな感じ

$('a[href$=".pdf"]').click( function(){
  $.fancybox({
    type: 'html',
    content: '<embed type="application/pdf" src="'+
      this.href +
      '#nameddest=self&amp;page=1&amp;view=fitH&amp;toolbar=1"' +
      ' type="application/pdf"' +
      ' height="' + Math.round( $(window).height() * 0.8 ) + '"' +
      ' width="' + Math.round( $(window).width() * 0.8 ) + '" />' +
      '<noembed>Can not load PDF</noembed>' ,
    beforeClose: function() {
      $(".fancybox-inner").unwrap();
    }
  });
  return false;
});

長いですね(^^;

iframeとembedどっちがいいかですが……
embedタグを使って書く場合、pluginがインストールされてない場合にインストール画面が表示されてしまったり、または真っ白な枠だけ出たりとよろしくないです。
iframeの場合、ブラウザ内で表示できる設定では無いときはPDFのダウンロード画面になります。

という理由で、私はiframeでの表示を採用しました。

私の作成したメディアギャラリープログラムにはPDFのサムネイル生成機能を付けてるので、サムネイルを並べた中からJPGでもPDFでも意識せずに閲覧できるギャラリーが作れました。

PHPカンファレンス関西2013

土曜にPHPカンファレンス関西2013にお邪魔してきました。
普段他の技術者の方の話を聞く機会が少ないので、かなりイイ刺激になりました。
お話下さった方々ありがとうございました。

これを機会に自分も色々してみたいなぁ…
と思い、取りあえず何かしらBlogでも書いていこうかなと。

…何書いたらいいかなぁ(苦笑
鯖ネタ(主にFreeBSD)は色々あるんですけど、コマンド手順ばっかりメモしてるから、そこの応答まで書かないと説明になりませんよね(笑
まぁ、とりあえずいいか。