2015年12月5日 星期六

如何在網頁中使用網頁編輯器 CKEDITOR

這兩天為了解決公司工作日誌中的舊版網頁編輯器 FCKEDITOR 在 IE10 以上無法運作問題, 找到了這款 CKEDITOR, 基本上符合我要求 (例如超連結可以設 target 在新視窗開啟等), 下面紀錄如何將此 Javascript 函式庫使用在我的 ASP 網頁專案上.

首先到 CKEDITOR 首頁下載最新版函式庫 (目前是 4.5.5 版), 下載 Standard 版本即可, 安裝方式都一樣 :

http://ckeditor.com/download

解壓縮 ckeditor_4.5.5_standard.zip 後會在目前資料夾下產生一個 ckeditor 資料夾, 目錄結構如下 :


將此 ckeditor 資料夾整個複製到我的專案目錄 myasp/plug-in/ 底下, 大小為 3.22MB, 如果要減重, 可以刪掉 samples 資料夾, 三個 .md 檔, 以及 lang 底下用不到的語言檔, 只留下 en.js 與 zh.js 即可, 這樣可減重到 2.7MB 以下 :


然後就可以開始撰寫測試網頁了, 如下 test.html 所示 :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>CKEditor 測試</title>
    <script src="ckeditor.js"></script>
  </head>
  <body>
    <form>
      <textarea id="editor1">
      Hello World! 這是 CKeditor!
      </textarea>
    </form>
    <script>
      CKEDITOR.replace( 'editor1' );
    </script>
  </body>
</html>

參考 :

http://docs.ckeditor.com/#!/guide/dev_installation

這裡最重要的當然是匯入 ckeditpr.js 這個函式庫, 由於 test.html 是放在 ckeditor 下, 所以這裡不需要加上相對路徑. 如果專案是放在 Internet 上, 則可以使用 CDN 供檔, 如此就不用自己準備上面這些環境 :

<script src="//cdn.ckeditor.com/4.5.5/standard/ckeditor.js"></script>

參考 :

http://cdn.ckeditor.com/

其次是要用一個表單元件 textarea 當作編輯器的容器, 而且務必指定 id 屬性, 像這裡我只用到一個編輯器, 如果有多個, 就可以取名 editor2, editor3, ... 或任何其他名稱. 最後是用 Javascript 程式來將 textarea 變裝為美美的 HTML 編輯器, 很簡單, 只要呼叫 CKEDITOR 物件的 replace() 函數, 傳入 textarea 的 id 即可 :

CKEDITOR.replace("editor1");

用瀏覽器檢視 test.html 結果如下 :


介面比十幾年前的 FCKEDITOR 漂亮. 它預設會將寬度撐大到父容器的寬度, 即使 textarea 有設定 cols (行數) 也是一樣, 所以 rows 與 cols 其實都不用設.

接下來是要如何用在我的 myasp 專案上呢? 我的工作日誌系統裡的 JLOG 子系統中的 add_task_form (新增工作) 模組就是要用到 HTML 編輯器以儲存來自 email 或 WORD 的內容, 我把原來套用的 FCKEDITOR 移除,  改換為 CKEDITOR 如下 :

case "add_task_form" : {
%>
...
<form method="post" action="admin.asp?op=jlog&tab=jlog&function=add_task">
...
  <textarea id="editor1"></textarea>
  <script src="plug-in/ckeditor/ckeditor.js"></script>
  <script>CKEDITOR.replace('editor1');</script>
  ...
  ...
  <input type="button" onclick="check_addtask(this.form)" value="新增">
  <input type="hidden" name="task_content" value="">

  <script language="javascript">
    function check_addtask(formObj) {
      var content=CKEDITOR.instances.editor1.getData();
      ... (對 content 進行處理, 例如去除可能的 form 元素, 以免兩層表單)
      formObj.task_content.value=content;  //處理後放入隱藏元素
      formObj.submit();
      }
  </script>
<form>
<%
  break;
  }

在這個範例中, 我有一個新增工作的表單, 放在 add_task_form 模組裡, 當按下新增工作按鈕時, 就會向伺服器提出 admin.asp?op=jlog&tab=jlog&function=add_task_form 這個 URL 要求, 在 admin.asp 所含括的 jlog.asp 程式裡, 經過解析 URL 路徑後, 就會進入上述的 case, 向前端展示一個輸入表單, 其中最重要的便是填入工作內容, 因為所紀錄的工作牽涉各方寄來的 email, WORD 或 EXCEL 內容等, 為了求真實以及閱讀方便 (開啟附檔多一道操作程序), 內容少的就直接貼到工作紀錄裡, 內容太多太複雜的就以附檔上傳處理, 這樣要追蹤工作就比較方便. 要記錄這三種多媒體內容就必須用到像 CKEDITOR 這種網頁編輯器.

由於我把 ckeditor 目錄放在我的專案 myasp/plug-in 子目錄下, 因此要匯入 cckeditor.js 時必須指明相對路徑. 填好工作內容, 按下 "新增" 按鈕時, 會執行前端 Javascript : check_addtask() 方法, 首先是要取出 CKEDITOR 的資料內容, 這要呼叫 CKEDITOR 物件中的 textarea 實體的 getData() 方法來取得 :

var content=CKEDITOR.instances.editor1.getData();

參考 :

# http://docs.ckeditor.com/#!/guide/dev_savedata

然後做一些輸入欄位值的檢查, 例如有些欄位是必填不得空白, 特別是禁止在工作內容中輸入另一張表單, 這會造成表單套疊, 使程式無法運作, 所以須去除 form 元素. 最後將調整後的輸入內容放入隱藏的 task_content 元素裡再 submit 表單.




如果貼上來自網頁, email 或 WORD 等內容時, 在 Chrome 瀏覽器會因為安全性設定的關係跳出一個視窗來讓我我們貼資料 :


但在 IE11 就直接貼上去了, 可能 IE11 對剪貼簿的安全性設定預設較鬆.

如此便完成了這次的工作日誌改版, 於 IE11, Chrome 等瀏覽器測試均無問題, 暫時可以應付這次的升版要求矣. 這個解決方案也將移植到以 PHP 開發的新版工作日誌上, 其實 ASP, JSP 與 PHP 這三種技術就像孿生兄弟一樣. 一通百通.

CKEDITOR 物件是可以設定的, 例如預設語言, 以及要顯示哪些功能按鈕等, 參考 :

http://docs.ckeditor.com/#!/guide/dev_configuration

在上面的範例中, 我們僅使用 textarea 的 id 屬性來建立 CKEDITOR 物件, 但根據 API 文件, 其實用 name 也是可以的, 或者兩個都用亦可, 不過建議僅使用 id 就可以, 參見下面文件中關於 replace() 的敘述 :

http://docs.ckeditor.com/#!/api/CKEDITOR-method-replace

由此文件可知, replace() 方法會以一個 CKEditor 物件來取代 DOM 中的 textarea 或 dir 元素, 除了傳入 textarea 的 id 或 name 外, 還可傳入一個 config 物件實體來初始化 CKEditor 物件的設定值, 也就是將預設的設定值覆蓋掉 :

replace(element, [config])

關於 config 物件實體之屬性可參考 :

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

在上面的範例中, 編輯器預設會偵測作業系統語言, 顯示中文介面, 而且會撐到 100% 父容器寬度, 我們可以用 config 指定語為英文, 寬度為 800px 如下 :

CKEDITOR.replace('editor1', {width:800,language:'en'} );

寬度也可以用百分比, 但必須用引號括起來, 例如 :

CKEDITOR.replace('editor1', {width:'50%',language:'en'} );

如果不想讓使用者直接編輯 html 原始碼, 可以用 removePlugins 屬性來取消 "原始碼" 按鈕 :

CKEDITOR.replace('editor1', {removePlugins:'sourcearea'});

參考 :

how to disable source button in ckeditor 4

如果對工具列的排列方式不滿意, 可以利用 toolbarGroups 屬性來設定, 它將同類型的工具按鈕合為一群, 範例如下 :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>CKEditor 測試</title>
    <script src="ckeditor.js"></script>
  </head>
  <body>
    <form>
      <textarea name="editor1" id="editor2">
      Hello World! 這是 CKeditor!
      </textarea>
    </form>
    <script>
      var tg=[{name:'clipboard',groups:['clipboard','undo']},
              {name:'editing',groups:['find','selection','spellchecker']},
              {name:'links'},
              {name:'insert'},
              {name:'forms'},
              {name:'tools'},
              {name:'document',groups:['mode','document','doctools']},
              {name:'others'},
              '/',
              {name:'basicstyles',groups:['basicstyles','cleanup']},
              {name:'paragraph',groups:['list','indent','blocks','align','bidi']},
              {name:'styles'},
              {name:'colors'},
              {name:'about'}];
      CKEDITOR.replace('editor1', {toolbarGroups:tg,removePlugins:'sourcearea'});
    </script>
  </body>
</html>

這裡跳行要用斜線 "/", 排列效果如下 :


也可以用 toolbars 屬性直接設定工具列要放哪些按鈕, 範例如下 :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>CKEditor 測試</title>
    <script src="ckeditor.js"></script>
  </head>
  <body>
    <form>
      <textarea name="editor1" id="editor2">
      Hello World! 這是 CKeditor!
      </textarea>
    </form>
    <script>
      var toolbar=[['Cut','Copy','Paste','PasteText','PasteFromWord',
                    'Undo','Redo'],
                   ['Scayt','SpellChecker'],
                   ['Link','Unlink','Anchor'],
                   ['Image','Table','HorizontalRule','Smiley',
                    'SpecialChar','PageBreak'],
                   ['Maximize'],
                    '/',
                   ['Bold','Italic',
                    'Underline','Strike','Subscript',
                    'Superscript','-','RemoveFormat'],
                   ['NumberedList','BulletedList','-','Outdent','Indent',
                    '-','Blockquote'],
                   ['Styles','Format'],
                   ['About']];
      CKEDITOR.replace('editor1',{toolbar:toolbar});
    </script>
  </body>
</html>

這裡使用二維陣列來宣告要顯示的工具按鈕, 然後在 replace() 的 config 參數中設為 toolbar 屬性之值即可, 效果與上面用 toolbarGroups 的完全一樣. 注意, 每一個一維陣列就是一個工具列群組, 群組內的按鈕可用 "-" 再分出子群. 如果需要顯示原始碼按鈕, 可以添加 ['Source'].

如果把 toolbar 屬性設為 null, 就會顯示此 package (basic/standard/full) 的全部工具列 :

CKEDITOR.replace('editor1',{toolbar:null});

此外還有一點要注意, 有些在完整版才有的工具列按鈕 (例如文字的前景與背景色 TextColor 與 BgColor) 在標準版設了也不會出現, 因此如果需要自訂工具列的話, 最好下載 Full 版來改裝.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>CKEditor 測試</title>
    <script src="http://cdn.ckeditor.com/4.5.5/full/ckeditor.js"></script>
  </head>
  <body>
    <form>
      <textarea name="editor1" id="editor2">
      Hello World! 這是 CKeditor!
      </textarea>
    </form>
    <script>
      var toolbar=[['Cut','Copy','Paste','PasteText','PasteFromWord',
                    'Undo','Redo'],
                   ['Scayt','SpellChecker'],
                   ['Link','Unlink','Anchor'],
                   ['Image','Table','HorizontalRule','Smiley',
                    'SpecialChar','PageBreak'],
                   ['Maximize'],
                   ['About'],
                    '/',
                   ['Bold','Italic',
                    'Underline','Strike','Subscript',
                    'Superscript','-','RemoveFormat'],
                   ['NumberedList','BulletedList','-','Outdent','Indent',
                    '-','Blockquote'],
                   ['Styles','Format'],
                   ['TextColor','BGColor']];
      CKEDITOR.replace('editor1',{toolbar:toolbar});
    </script>
  </body>
</html>

如果不想在每一個要用到 CKEDITOR 的網頁中進行設定, 其實可以在 CKEDITOR 資料夾中找到一個 config.js, 只要在這裡做設定, 所有專案中用到 CKEDITOR 的網頁都會套用相同設定, 範例如下 :

CKEDITOR.editorConfig=function(config) {
  // Define changes to default configuration here. For example:
  //config.language = 'en';
  //config.uiColor = '#AADC6E';
  config.toolbar = [['Cut','Copy','Paste','PasteText','PasteFromWord',
                    'Undo','Redo'],
                   ['Scayt','SpellChecker'],
                   ['Link','Unlink','Anchor'],
                   ['Image','Table','HorizontalRule','Smiley',
                    'SpecialChar','PageBreak'],
                   ['Maximize'],
                    '/',
                   ['Bold','Italic',
                    'Underline','Strike','Subscript',
                    'Superscript','-','RemoveFormat'],
                   ['NumberedList','BulletedList','-','Outdent','Indent',
                    '-','Blockquote'],
                   ['Styles','Format'],
                   ['TextColor','BGColor'],
                   ['About']];
  };

CKEDITOR 很棒的地方是提供客製化套件, 在下載頁面點選 "Let me customerize CKEditor", 再按下載鈕 :


然後點選 basic/stadard/full, 於下方將需要的工具按鈕移到右方再下載, 這樣它會將設定都寫在 config,js 中. 不過工具列 plugin 實在玲瑯滿目, 要從中挑選也是個問題.

參考 :

# 讓 CKEditor 更好用
CKeditor編輯器選項配置

2015-12-12 補充 :

前天完成工作日誌改版後, 發覺編輯時按 enter 跳行似乎間距過大, 我之前已知悉 CKEditor 是用段落標籤 p 來處理跳行, 而非用 br, 昨日在下列網站找到解決辦法 :

CKEditor 編輯器 換行 空格 解決 辦法

就是在 config.js 中加入下列兩行 :

config.enterMode = CKEDITOR.ENTER_BR;
config.shiftEnterMode = CKEDITOR.ENTER_P;

2016-03-01 補充 :

今天因為同事反映 TinyMCE 編輯器貼上頗長的信件內容時一直 Waiting, 三十分鐘後出現沒有回應訊息問題, 就去網搜是否有此問題的解決辦法, 結果找到一篇很棒的文章, 但與 TinyMCE 問題無關, 反而是我想取代掉的 CKEditor :

# 神調校讓 CKEditor 更好用


沒有留言 :