# 如何在網頁中使用網頁編輯器 CKEDITOR
但使用者的體驗是真實的, 不應該漠視. 所以今天看到下列這篇, 介紹十種最好用的所見即所得 HTML 編輯器後, 發現其中的 TinyMCE 似乎不錯 :
其展示範例見 :
# https://www.tinymce.com/docs/demo/full-featured/ (全功能)
TinyMCE 是可免費使用的 Open Source 軟體, 但也提供收費升級版. 可下載 zip 檔解壓縮後放在專案目錄下 :
# https://www.tinymce.com/download/
目前是 4.3.3 版, 解壓縮後會產生 tinymce/js/tinymce 的目錄結構, 只要將 js 底下的那個 tinymce 目錄放到專案目錄下即可, 我的工作日誌系統是把所有外掛放在 /plug-in 下面, 結構如下 :
裡面的 example.htm 是我自己寫的範例, 不是原 zip 檔中的內容.
TinyMCE 的用法與 CKEditor 類似, 都是利用 textarea 包裝成網頁編輯器物件 tinymce (或 tinyMCE). 只要匯入 TinyMCE 函式庫, 然後呼叫 tinymce 物件的 init() 方法, 並指定要初始化的 textarea 元件即可 :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TinyMCE 測試</title>
<script src="tinymce.min.js"></script>
</head>
<body>
<form>
<textarea id="editor1">
Hello World! 這是 TinyMCE!
</textarea>
</form>
<script>
tinymce.init({
selector:'textarea'
});
</script>
</body>
</html>
此處利用 selector 屬性選取 textarea 元件來初始化. 如果網頁中有多個 textarea, 那此種選取方法會將全部 textarea 元件都初始化. 也可以用 id 來選取 (CSS 用 # 表示選取 id) :
tinymce.init({
selector:'#editor1'
});
這樣當兩個編輯器要做不同處理時 (例如設定不同之內容), 就要用 id 選取來個別初始化. 與 CKEditor 不同的是, 它上面多了功能選單 :
範例 1 : http://mybidrobot.allalla.com/tinymce/tinymce_1.htm
預設介面是英文版的, 如果要改為中文版, 必須另外去 TinyMCE 的Archieve 網站下載語言檔 (zip) :
# http://archive.tinymce.com/i18n/download.php?download=zh_TW
解開後會得到內含 zh_TW.js 檔的 langs 目錄, 將其複製到 tinymce 目錄下覆蓋原目錄 (裡面預設無語言檔), 然後在初始化時加入 language 屬性, 指定其值為 "zh_TW" 即可 :
tinymce.init({
selector:'#editor1',
language:'zh_TW'
});
範例 2 : http://mybidrobot.allalla.com/tinymce/tinymce_2.htm
除了自備資源外, 如果專案是放在 Internet 上, 則利用 CDN 會比較方便, 不須準備檔案, 只要將 TinyMCE 函式庫指向下列網址之一即可 :
http://cdn.tinymce.com/4/tinymce.min.js
https://cdnjs.cloudflare.com/ajax/libs/tinymce/4.3.3/tinymce.min.js
但是 CDN 不提供語言檔, 只能用預設之英文版, 不可以使用 language 屬性去設定, 否則會因為找不到語言檔, 導致網頁無法渲染而發生錯誤. 如果使用 CDN 又要 Localization, 必須自行提供語言檔, 並用 language_url 屬性指定其位址, 如下例所示 :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TinyMCE 測試</title>
<script src="http://cdn.tinymce.com/4/tinymce.min.js"></script>
</head>
<body>
<form>
<textarea id="editor1">
Hello World! 這是 TinyMCE!
</textarea>
</form>
<script>
tinymce.init({
selector:'#editor1',
language_url:'http://mybidrobot.allalla.com/tinymce/langs/zh_TW.js'
});
</script>
</body>
</html>
範例 3 : http://mybidrobot.allalla.com/tinymce/tinymce_3.htm
除了繁體中文外, 我也下載了日, 韓, 簡體中文語言檔放在 langs 下, 例如使用韓文介面就把上面的 zh_TW.js 改為 ko_KR.js 即可 (但我這免費的測試網站並不穩定, 有時會無法存取).
範例 4 : http://mybidrobot.allalla.com/tinymce/tinymce_4.htm (日文)
範例 5 : http://mybidrobot.allalla.com/tinymce/tinymce_5.htm (韓文)
範例 6 : http://mybidrobot.allalla.com/tinymce/tinymce_6.htm (簡體中文)
範例 7 : http://mybidrobot.allalla.com/tinymce/tinymce_7.htm (阿拉伯文)
範例 8 : http://mybidrobot.allalla.com/tinymce/tinymce_8.htm (俄文)
預設的工具列與功能表乃最簡設定, TinyMCE 提供了 plugins 與 toobar 屬性來自定工具列, 其值為一個由工具按鈕名稱組成的陣列. 工具列上的按鈕分屬於不同的 plugins, 參考 :
# Buttons/controls
因此如果要擺上某個按鈕, 那麼其所屬的 plugins 也要列在 plugins 陣列內, 否則會沒效果. 花了一晚上測試工具列的組合, 終於得到比較滿意的排列, 如範例 9 所示 :
tinymce.init({
selector:'#editor1',
language_url:'http://mybidrobot.allalla.com/tinymce/langs/zh_TW.js',
height:300,
width:800,
plugins:[
'advlist autolink lists link image charmap print preview anchor',
'searchreplace visualblocks code fullscreen textcolor colorpicker',
'insertdatetime media table contextmenu paste code hr pagebreak nonbreaking'
],
toolbar:['newdocument preview fullscreen code print searchreplace selectall | bold italic underline strikethrough superscript subscript removeformat forecolor backcolor | alignleft aligncenter alignright alignjustify |',
'undo redo cut copy paste pastetext pasteword | bullist numlist outdent indent | blockquote nonbreaking hr pagebreak charmap anchor link unlink image table']
});
範例 9 : http://mybidrobot.allalla.com/tinymce/tinymce_9.htm
這裡我們也使用 width 與 height 設定編輯器的大小, 當然也可以在 textarea 加上 css 樣式來設定. 在 toolbar 屬性值陣列中, 管線符號用來分群, 逗號則用來跳行. 注意, 管線符號與工具按鈕名稱之間必須用空格隔開, 如果黏在一起會出現錯誤. 其次, 搜尋鈕右邊的全選 (selectall) 按鈕圖像不知何故沒有顯現, 但其實是有作用的.
如果不需要功能選項, 可以將 menubar 屬性設為 false 即可, 這樣如下範例 10 所示 :
tinymce.init({
selector:'#editor1',
language_url:'http://mybidrobot.allalla.com/tinymce/langs/zh_TW.js',
height:300,
width:800,
menubar:false,
plugins:[
'advlist autolink lists link image charmap print preview anchor',
'searchreplace visualblocks code fullscreen textcolor colorpicker',
'insertdatetime media table contextmenu paste code hr pagebreak nonbreaking'
],
toolbar:['newdocument preview fullscreen code print searchreplace selectall | bold italic underline strikethrough superscript subscript removeformat forecolor backcolor | alignleft aligncenter alignright alignjustify |',
'undo redo cut copy paste pastetext pasteword | bullist numlist outdent indent | blockquote nonbreaking hr pagebreak charmap anchor link unlink image table']
});
範例 10 : http://mybidrobot.allalla.com/tinymce/tinymce_10.htm
接下來是重頭戲, 要測試 TinyMCE 的設值 setContent() 與取值方法 getContent(), 這是網頁專案中一定會用到的, 例如編輯工作日誌中的紀錄時, 要從資料庫中取出欄位值, 將其設值給 TinyMCE 編輯器; 而要存回資料庫時, 須從 TinyMCE 編輯器中取值, 再回傳給後端處理. 參考 :
# http://archive.tinymce.com/wiki.php/API3:method.tinymce.Editor.getContent
# http://archive.tinymce.com/wiki.php/API3:method.tinymce.Editor.setContent
不過 setContent() 與 getContent() 這兩個方法不能直接在 init() 後使用, 否則會出現 "Uncaught TypeError: Cannot read property 'getContent' of null" 錯誤, 如下面範例 11 所示 :
範例 11 : http://mybidrobot.allalla.com/tinymce/tinymce_11.htm
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TinyMCE 測試</title>
<script src="http://cdn.tinymce.com/4/tinymce.min.js"></script>
</head>
<body>
<form>
<textarea id="editor1">TinyMCE</textarea>
</form>
<script type="text/javascript">
tinyMCE.init({
selector:'#editor1'
});
alert(tinyMCE.get("editor1").getContent());
tinyMCE.get("editor1").setContent('Hello World! 這是 TinyMCE!');
</script>
</body>
</html>
必須放在方法中, 然後用個按鈕來呼叫它才可以, 如下範例 12 :
範例 12 : http://mybidrobot.allalla.com/tinymce/tinymce_12.htm
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TinyMCE 測試</title>
<script src="http://cdn.tinymce.com/4/tinymce.min.js"></script>
</head>
<body>
<form>
<textarea id="editor1">TinyMCE</textarea>
<button onclick="get_content()">Get content</button>
<button onclick="set_content()">Set content</button>
</form>
<script>
tinyMCE.init({
selector:'#editor1'
});
function get_content(){
var content=tinymce.get("editor1").getContent(); //以 id 取得物件
alert(content);
}
function set_content(){
tinymce.get("editor1").setContent('Hello World! 這是 TinyMCE!');
}
</script>
</body>
</html>
但是這個範例有一個問題, 就是設值後會重新 init 編輯器, 導致所設的值像曇花一現一下子又變回預設值了. 原因是我們有用 form 元素之故, 當按了按鈕後會向後端提交, 但沒有指定 action, 這樣會向本頁提交, 結果就重新載入本網頁, 編輯器內容當然就重設為預設值了 :
範例 13 : http://mybidrobot.allalla.com/tinymce/tinymce_13.htm
這樣就能單純地驗證 getContent() 與 setContent() 方法了. 當然, 在與後端正常的互動中一定要有 form 表單元素才行, 我們可以在按下確定鈕後呼叫一個方法, 再用 getContent() 取得編輯器內容, 然後再呼叫 submit() 提交表單, 如下範例 14 所示 :
範例 14 : http://mybidrobot.allalla.com/tinymce/tinymce_14.htm
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TinyMCE 測試</title>
<script src="http://cdn.tinymce.com/4/tinymce.min.js"></script>
</head>
<body>
<form method="post" action="get_content.php">
<textarea id="editor1" name="editor1">TinyMCE</textarea>
<button onclick="check(this.form)">Submit</button>
<input type="hidden" name="content">
</form>
<script>
tinyMCE.init({
selector:'#editor1',
auto_focus:'editor1'
});
function check(formObj){
var content=tinymce.get("editor1").getContent();
content="編輯的內容 : <br>" + content;
formObj.content.value=content;
alert(content);
formObj.submit();
}
</script>
</body>
</html>
在這個範例中, 我在表單中增加一個名為 content 的隱藏元件, 當按下 Submit 按鈕時會先呼叫 check() 方法, 並傳入表單物件 this.form, 然後在 check() 中用 getContent() 取得編輯器內容, 在其前冠上額外資訊後, 設值給隱藏元件 content 後向後端 get_content.php 以 post 方法提交表單, 此後端程式很簡單, 就單純取得所傳遞的 content 參數後輸出給前端而已 :
<?php
header('Content-Type: text/html;charset=UTF-8');
echo $_POST['content'];
?>
注意, 這裡我們在初始化編輯器時, 加入了一個新屬性 auto_focus, 其值為編輯器的 id 屬性值 (但不可加 #), 這可以讓網頁載入時讓編輯器自動取得焦點 (也就是游標會在編輯區內一閃一閃的), 參考 :
# https://www.tinymce.com/docs/configure/integration-and-setup/#auto_focus
# http://fiddle.tinymce.com/
# http://stackoverflow.com/questions/31475325/tinymce-get-content
# http://fiddle.tinymce.com/WSeaab/1
其次, 編輯器物件不管是用 tinymce 或 tinyMCE 都可以, 都是別名.
以上測試範例檔可從下面網址下載 :
# 下載測試範例
其他參考資料 :
# How do I set content in TinyMCE 4, preferably within the $(document).ready(); block?
# how to enable font family and color options in tinymce editor?
# https://www.tinymce.com/docs/plugins/colorpicker/
# TinyMCE width and height disobedient!
TinyMCE 是可免費使用的 Open Source 軟體, 但也提供收費升級版. 可下載 zip 檔解壓縮後放在專案目錄下 :
# https://www.tinymce.com/download/
目前是 4.3.3 版, 解壓縮後會產生 tinymce/js/tinymce 的目錄結構, 只要將 js 底下的那個 tinymce 目錄放到專案目錄下即可, 我的工作日誌系統是把所有外掛放在 /plug-in 下面, 結構如下 :
裡面的 example.htm 是我自己寫的範例, 不是原 zip 檔中的內容.
TinyMCE 的用法與 CKEditor 類似, 都是利用 textarea 包裝成網頁編輯器物件 tinymce (或 tinyMCE). 只要匯入 TinyMCE 函式庫, 然後呼叫 tinymce 物件的 init() 方法, 並指定要初始化的 textarea 元件即可 :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TinyMCE 測試</title>
<script src="tinymce.min.js"></script>
</head>
<body>
<form>
<textarea id="editor1">
Hello World! 這是 TinyMCE!
</textarea>
</form>
<script>
tinymce.init({
selector:'textarea'
});
</script>
</body>
</html>
此處利用 selector 屬性選取 textarea 元件來初始化. 如果網頁中有多個 textarea, 那此種選取方法會將全部 textarea 元件都初始化. 也可以用 id 來選取 (CSS 用 # 表示選取 id) :
tinymce.init({
selector:'#editor1'
});
這樣當兩個編輯器要做不同處理時 (例如設定不同之內容), 就要用 id 選取來個別初始化. 與 CKEditor 不同的是, 它上面多了功能選單 :
範例 1 : http://mybidrobot.allalla.com/tinymce/tinymce_1.htm
預設介面是英文版的, 如果要改為中文版, 必須另外去 TinyMCE 的Archieve 網站下載語言檔 (zip) :
# http://archive.tinymce.com/i18n/download.php?download=zh_TW
解開後會得到內含 zh_TW.js 檔的 langs 目錄, 將其複製到 tinymce 目錄下覆蓋原目錄 (裡面預設無語言檔), 然後在初始化時加入 language 屬性, 指定其值為 "zh_TW" 即可 :
tinymce.init({
selector:'#editor1',
language:'zh_TW'
});
範例 2 : http://mybidrobot.allalla.com/tinymce/tinymce_2.htm
除了自備資源外, 如果專案是放在 Internet 上, 則利用 CDN 會比較方便, 不須準備檔案, 只要將 TinyMCE 函式庫指向下列網址之一即可 :
http://cdn.tinymce.com/4/tinymce.min.js
https://cdnjs.cloudflare.com/ajax/libs/tinymce/4.3.3/tinymce.min.js
但是 CDN 不提供語言檔, 只能用預設之英文版, 不可以使用 language 屬性去設定, 否則會因為找不到語言檔, 導致網頁無法渲染而發生錯誤. 如果使用 CDN 又要 Localization, 必須自行提供語言檔, 並用 language_url 屬性指定其位址, 如下例所示 :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TinyMCE 測試</title>
<script src="http://cdn.tinymce.com/4/tinymce.min.js"></script>
</head>
<body>
<form>
<textarea id="editor1">
Hello World! 這是 TinyMCE!
</textarea>
</form>
<script>
tinymce.init({
selector:'#editor1',
language_url:'http://mybidrobot.allalla.com/tinymce/langs/zh_TW.js'
});
</script>
</body>
</html>
範例 3 : http://mybidrobot.allalla.com/tinymce/tinymce_3.htm
範例 4 : http://mybidrobot.allalla.com/tinymce/tinymce_4.htm (日文)
範例 5 : http://mybidrobot.allalla.com/tinymce/tinymce_5.htm (韓文)
範例 6 : http://mybidrobot.allalla.com/tinymce/tinymce_6.htm (簡體中文)
範例 7 : http://mybidrobot.allalla.com/tinymce/tinymce_7.htm (阿拉伯文)
範例 8 : http://mybidrobot.allalla.com/tinymce/tinymce_8.htm (俄文)
預設的工具列與功能表乃最簡設定, TinyMCE 提供了 plugins 與 toobar 屬性來自定工具列, 其值為一個由工具按鈕名稱組成的陣列. 工具列上的按鈕分屬於不同的 plugins, 參考 :
# Buttons/controls
因此如果要擺上某個按鈕, 那麼其所屬的 plugins 也要列在 plugins 陣列內, 否則會沒效果. 花了一晚上測試工具列的組合, 終於得到比較滿意的排列, 如範例 9 所示 :
tinymce.init({
selector:'#editor1',
language_url:'http://mybidrobot.allalla.com/tinymce/langs/zh_TW.js',
height:300,
width:800,
plugins:[
'advlist autolink lists link image charmap print preview anchor',
'searchreplace visualblocks code fullscreen textcolor colorpicker',
'insertdatetime media table contextmenu paste code hr pagebreak nonbreaking'
],
toolbar:['newdocument preview fullscreen code print searchreplace selectall | bold italic underline strikethrough superscript subscript removeformat forecolor backcolor | alignleft aligncenter alignright alignjustify |',
'undo redo cut copy paste pastetext pasteword | bullist numlist outdent indent | blockquote nonbreaking hr pagebreak charmap anchor link unlink image table']
});
範例 9 : http://mybidrobot.allalla.com/tinymce/tinymce_9.htm
這裡我們也使用 width 與 height 設定編輯器的大小, 當然也可以在 textarea 加上 css 樣式來設定. 在 toolbar 屬性值陣列中, 管線符號用來分群, 逗號則用來跳行. 注意, 管線符號與工具按鈕名稱之間必須用空格隔開, 如果黏在一起會出現錯誤. 其次, 搜尋鈕右邊的全選 (selectall) 按鈕圖像不知何故沒有顯現, 但其實是有作用的.
如果不需要功能選項, 可以將 menubar 屬性設為 false 即可, 這樣如下範例 10 所示 :
tinymce.init({
selector:'#editor1',
language_url:'http://mybidrobot.allalla.com/tinymce/langs/zh_TW.js',
height:300,
width:800,
menubar:false,
plugins:[
'advlist autolink lists link image charmap print preview anchor',
'searchreplace visualblocks code fullscreen textcolor colorpicker',
'insertdatetime media table contextmenu paste code hr pagebreak nonbreaking'
],
toolbar:['newdocument preview fullscreen code print searchreplace selectall | bold italic underline strikethrough superscript subscript removeformat forecolor backcolor | alignleft aligncenter alignright alignjustify |',
'undo redo cut copy paste pastetext pasteword | bullist numlist outdent indent | blockquote nonbreaking hr pagebreak charmap anchor link unlink image table']
});
範例 10 : http://mybidrobot.allalla.com/tinymce/tinymce_10.htm
接下來是重頭戲, 要測試 TinyMCE 的設值 setContent() 與取值方法 getContent(), 這是網頁專案中一定會用到的, 例如編輯工作日誌中的紀錄時, 要從資料庫中取出欄位值, 將其設值給 TinyMCE 編輯器; 而要存回資料庫時, 須從 TinyMCE 編輯器中取值, 再回傳給後端處理. 參考 :
# http://archive.tinymce.com/wiki.php/API3:method.tinymce.Editor.getContent
# http://archive.tinymce.com/wiki.php/API3:method.tinymce.Editor.setContent
不過 setContent() 與 getContent() 這兩個方法不能直接在 init() 後使用, 否則會出現 "Uncaught TypeError: Cannot read property 'getContent' of null" 錯誤, 如下面範例 11 所示 :
範例 11 : http://mybidrobot.allalla.com/tinymce/tinymce_11.htm
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TinyMCE 測試</title>
<script src="http://cdn.tinymce.com/4/tinymce.min.js"></script>
</head>
<body>
<form>
<textarea id="editor1">TinyMCE</textarea>
</form>
<script type="text/javascript">
tinyMCE.init({
selector:'#editor1'
});
alert(tinyMCE.get("editor1").getContent());
tinyMCE.get("editor1").setContent('Hello World! 這是 TinyMCE!');
</script>
</body>
</html>
必須放在方法中, 然後用個按鈕來呼叫它才可以, 如下範例 12 :
範例 12 : http://mybidrobot.allalla.com/tinymce/tinymce_12.htm
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TinyMCE 測試</title>
<script src="http://cdn.tinymce.com/4/tinymce.min.js"></script>
</head>
<body>
<form>
<textarea id="editor1">TinyMCE</textarea>
<button onclick="get_content()">Get content</button>
<button onclick="set_content()">Set content</button>
</form>
<script>
tinyMCE.init({
selector:'#editor1'
});
function get_content(){
var content=tinymce.get("editor1").getContent(); //以 id 取得物件
alert(content);
}
function set_content(){
tinymce.get("editor1").setContent('Hello World! 這是 TinyMCE!');
}
</script>
</body>
</html>
但是這個範例有一個問題, 就是設值後會重新 init 編輯器, 導致所設的值像曇花一現一下子又變回預設值了. 原因是我們有用 form 元素之故, 當按了按鈕後會向後端提交, 但沒有指定 action, 這樣會向本頁提交, 結果就重新載入本網頁, 編輯器內容當然就重設為預設值了 :
範例 13 : http://mybidrobot.allalla.com/tinymce/tinymce_13.htm
這樣就能單純地驗證 getContent() 與 setContent() 方法了. 當然, 在與後端正常的互動中一定要有 form 表單元素才行, 我們可以在按下確定鈕後呼叫一個方法, 再用 getContent() 取得編輯器內容, 然後再呼叫 submit() 提交表單, 如下範例 14 所示 :
範例 14 : http://mybidrobot.allalla.com/tinymce/tinymce_14.htm
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TinyMCE 測試</title>
<script src="http://cdn.tinymce.com/4/tinymce.min.js"></script>
</head>
<body>
<form method="post" action="get_content.php">
<textarea id="editor1" name="editor1">TinyMCE</textarea>
<button onclick="check(this.form)">Submit</button>
<input type="hidden" name="content">
</form>
<script>
tinyMCE.init({
selector:'#editor1',
auto_focus:'editor1'
});
function check(formObj){
var content=tinymce.get("editor1").getContent();
content="編輯的內容 : <br>" + content;
formObj.content.value=content;
alert(content);
formObj.submit();
}
</script>
</body>
</html>
在這個範例中, 我在表單中增加一個名為 content 的隱藏元件, 當按下 Submit 按鈕時會先呼叫 check() 方法, 並傳入表單物件 this.form, 然後在 check() 中用 getContent() 取得編輯器內容, 在其前冠上額外資訊後, 設值給隱藏元件 content 後向後端 get_content.php 以 post 方法提交表單, 此後端程式很簡單, 就單純取得所傳遞的 content 參數後輸出給前端而已 :
<?php
header('Content-Type: text/html;charset=UTF-8');
echo $_POST['content'];
?>
# https://www.tinymce.com/docs/configure/integration-and-setup/#auto_focus
# http://fiddle.tinymce.com/
# http://stackoverflow.com/questions/31475325/tinymce-get-content
# http://fiddle.tinymce.com/WSeaab/1
其次, 編輯器物件不管是用 tinymce 或 tinyMCE 都可以, 都是別名.
以上測試範例檔可從下面網址下載 :
# 下載測試範例
其他參考資料 :
# How do I set content in TinyMCE 4, preferably within the $(document).ready(); block?
# how to enable font family and color options in tinymce editor?
# https://www.tinymce.com/docs/plugins/colorpicker/
# TinyMCE width and height disobedient!
1 則留言 :
請問您能結合ibrowser圖片上傳功能嗎?
能將圖,文寫入資料庫嗎? 若寫一有密碼登錄的後台,登陸後有發圖文功能, 這樣價格如何?
請與我聯繫好嗎? 謝謝.
張貼留言