メモ: CKEditorに触ってみた

* [CKEditor.com | The best web text editor for everyone](http://ckeditor.com/)

CKEditorを使ったリッチテキストエディターを作りたい。でもって見た目は全然別にしたい、いっそツールバーとか表示させないで、こちらの任意のボタン類を押したら該当機能を起動するようにしたい。

という流れ。

## 最低限必要なファイル

* ckeditor.js
* (config.js)
* contents.css 
* lang/ja.js
* (plugins/icons.png)
* (skins/moono/editor.css)
* (skins/moono/icons.png)
* styles.js

括弧書きは空の状態で置いておく。（画像は1x1で。）　なくても動くがファイルを読み込むので、HTTPステータスコード200にしてキャッシュさせるため。

あとこれでなんとなく動くけど、幾つかの機能はエラーになる。クリップボードとか。

## 設定

* http://docs.ckeditor.com/#!/api/CKEDITOR.config

### `toolbar`

### `toolbarGroups`

### `toolbarCanCollapse: true`

ツールバーを畳めるように。

### `toolbarStartupExpanded : false`

ツールバーを最初から畳むように。`toolbarCanCollapse:true`と併用。

非表示にするのはないか。

### `contentsCss`

RTEの編集欄に読み込むCSSファイル名。初期値はCKEditorの`contents.css`。

### `removePlugins`

プラグイン無効化。カンマ`,`区切りでプラグイン名を指定する。

#### `"elementspath"`

フッターに現在位置の要素パスを表示するやつ。

#### `"contextmenu"`, `"…,liststyle,tabletools"`

CKEditorの拡張コンテキストメニューをやめる。依存関係にある他のプラグインも止める。

### `plugins`

* http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-plugins

`removePlugins`の逆、使うプラグインだけを記述する。これの最小構成を探すと、こんな感じだった。

```js
plugins:
	// "dialogui,dialog,about,a11yhelp,dialogadvtab," +
	"basicstyles," +
	// "bidi,blockquote," +
	"clipboard," +
	// "button,panelbutton,panel,floatpanel,colorbutton,colordialog,templates,menu," +
	"div," +
	// "resize," +
	"toolbar," +
	// "enterkey,entities,popup,filebrowser,find,fakeobjects,flash,floatingspace,listblock,richcombo," +
	"font," +
	// "forms,format,horizontalrule,htmlwriter,iframe," +
	"wysiwygarea,image," +
	// "indent,indentblock,indentlist,smiley," +
	"justify," +
	// "menubutton,language,link,list,magicline,maximize,newpage,pagebreak,pastetext,pastefromword,preview,print,removeformat,save,selectall,showblocks,showborders,sourcearea,specialchar,stylescombo,tab,table,undo,wsc" +
	"",
```

クリップボードは使ってないんだけど、ないと文字サイズ変更時にちょっと動作が妙になった。（文字の大きさを変えてもIビーム？のサイズが変わらない。）

### `on.instanceReady : handler`

起動時のコールバック。

```js
// ヘッダー、フッターを非表示にする例
var editor = CKEDITOR.replace($textarea[0], {
	on: {
		instanceReady: function (event) {
			var id = event.editor.id;

			// 上部を非表示にしつつ、全体の高さは維持する
			var $top = $('#'+id+'_top');
			var $contents = $('#' + id + '_contents');
			$contents.height($contents.height() + $top.outerHeight(true));
			$top.hide();
		}
	}
});
```

こんなやり方で大丈夫か？

### `fontSize_sizes`

* http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-fontSize_sizes

```js
var editor = CKEDITOR.replace($textarea[0], {
	fontSize_sizes: '小/16px;中/24px;大/48px;'
});
```

### `colorButton_colors`

* http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-colorButton_colors

```js
var editor = CKEDITOR.replace($textarea[0], {
	colorButton_colors: ''
});
```

文書には`colorButton_colors: 'FontColor1/FF9900,FontColor2/0066CC,FontColor3/F00'`と例示されていたが、名前は無効な感じ。

## `browserContextMenuOnCtrl : false`

* http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-browserContextMenuOnCtrl

初期設定では、RTE上で右クリックするとCKEditorのコンテキストメニューが表示され、Ctrlないしcommandを押しながら右クリックすると本来のものが表示される。

この設定をしておくと、それが逆になる。

逆じゃなくて拡張メニューを完全にやめたいんだけど……。

### `allowedContent`

* http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-allowedContent

編集欄に出力を許す要素、属性、クラス、スタイルを定義する。

```js
var editor = CKEDITOR.replace($textarea[0], {
	allowedContent:
		"div{text-align}; p{text-align};" +
		"span{color,font-size}; img[!src,width,height,alt]; a[!href];"
});
```

定義の仕方が独特。区切りはセミコロン`;`（一部省略可能だが書いておけば間違いない）。要素は要素名だからわかる。属性は各括弧`[ ]`、クラスは丸括弧`( )`、スタイルは波括弧`{ }`にカンマ`,`区切りで羅列し、`!`を冒頭に付けたものは、それがないと駄目になる。それぞれ`*`が使える。

`true`で全通しだけど、危険な香りがするよ。

## メソッド

### `editor = CKEDITOR.replace(elem, options)`

`elem`はIDを文字列で指定しても良い。

`options`は`config.js`での設定と同じ。

```js
var editor = CKEDITOR.replace($('#the-textarea')[0], {
	toolbarGroups: [
		{ name:"insert", groups: [] }  // これがないと画像が表示されない
	],
	removePlugins: 'elementspath'  // 要素パスを非表示
});
```

`toolbarGroups`で`name:"insert"`がないと、本文の画像が表示されない。未調査。

### `editor.commands`

登録済みのコマンド一覧。

### `editor.execCommand(command, option)`

* http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-execCommand

`editor.commands`に登録されているコマンドを実行する。

```js
editor.execCommand('bold');  // 選択中の文字列を太字化
```

`editor.commands`に登録されていても、ツールバーにボタンが表示されていないと利用出来なかった。何か有効化の処理が必要らしい。

### `editor.setData(html, callback)`

* http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-setData

既存の内容を破棄し、任意のHTMLを設定する。非同期で実行される。

### `editor.getData()`

* http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-getData

HTMLを得る。こちらは同期で実行される。

### `editor.insertHtml(html)`

* http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-insertHtml

任意のHTMLコードを、現在位置に挿入する。

ブロック要素を追加しても、その内容だけが既存のブロック要素の内側へ展開されたりする。何かやり方があるのかな？

### `editor.insertText(text)`

* http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-insertText

任意の文字列を、現在位置に挿入する。HTMLコードはエスケープされる。

### `editor.insertElement(element)`

* http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-insertElement

`element`はDOMオブジェクトじゃなくて、[CKEDITOR.dom.element](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.element)オブジェクト。

```js
var tag = '<img src="img.png" />';
var element = CKEDITOR.dom.element.createFromHtml(tag);
editor.insertElement(element);
```

こっちのやり方なら、`<h1>`の途中に`<h1>`を挿入出来る。（ちゃんと分割してくれる。）

### `editor.applyStyle(style)`

* http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-applyStyle

選択中の部分に任意のスタイルを適用する。

`style`は[CKEDITOR.style](http://docs.ckeditor.com/#!/api/CKEDITOR.style)オブジェクト。

```js
var style = new CKEDITOR.style({
  attributes: {
    class: 'my-great-style and-other-class'
  },
  element: 'em',
  name: 'My Great Style',
  styles: { color:'red' }
});
editor.applyStyle(style);
```

同じスタイルが二重三重に追加される事はない。（べんり！）

### `editor.removeStyle(style)`

* http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-removeStyle

```js
var style = new CKEDITOR.style({
  element: 'em',
  name: 'My Great Style',
  styles: { color:'red' }
});
editor.applyStyle(style);
editor.removeStyle(style);
```

## 定義済みコマンド

一部、fullをダウンロードしないと駄目ぽ。

機能|コマンド名|グループ|ボタン|マークアップ
----|----------|------|----|------------
太字|`bold`|`basicstyles`|`Bold`|`<strong>`
斜体|`italic`|`basicstyles`|`Italic`|`<em>`
打ち消し線|`strike`|`basicstyles`|`Strike`|`
`
下線|`underline`|`basicstyles`|`Underline`|`<u>`
左寄せ|`justifyleft`|`align`|`JustifyLeft`|`<p>`
中央寄せ|`justifycenter`|`align`|`JustifyCenter`|`<p style="text-align: center;">`
右寄せ|`justifyright`|`align`|`JustifyRight`|`<p style="text-align: right;">`
文字サイズ|なさそう|`styles`|`FontSize`|`<span style="font-size:72px;">`
文字色|なさそう|`colors`|`TextColor`|`<span style="color:#FF0000;">`
背景色|なさそう|`colors`|`BGColor`|`<span style="background-color:#FF0000;">`
画像|なさそう|`insert`|`Image`|`<img alt="" data-cke-saved-src="…" src="…" style="width: …px; height: …px;">`

グループは`toolbarGroups:[{name:'basicstyles'}]`、ボタンは`toolbar:[['JustifyLeft']]`のようにconfigで使う。

文字のサイズと色、背景色は`execCommand()`じゃなくて`applyStyle()`に統合されてるみたい。というか、基本的に全部`applyStyle()`で良いんじゃないかって気がしてる。

## その他

### 編集欄の操作を監視

`iframe`内の`document`で`addEventListener()`する。

```js
var id = CKEDITOR.instances.editor1.id;
var $iframe = $('#' + id + '_contents iframe');
var editorWindow = $iframe.prop('contentWindow');  // or contentDocument
$(editorWindow.document).on('click', 'img', function(event) {
    console.log(event.currentTarget.src);
});
```

### カーソル移動時に検知

自前でelementspath相当の機能を実装するときとか。

```js
CKEDITOR.instances.editor1.on('selectionChange', function(event) {
  var elements = _.map(event.data.path.elements, function(el){ return el.$; });
  console.log(':selectionChange', elements);
});
```