CKEditor跟jQuery UI Dialog的結合

CKEditor跟jQuery UI Dialog的結合

身為一個堪用的網路工程師

不可能不知道CKEditor跟jQuery Dialog這兩大利器

 

強大, 簡單,  好用到一個不行

雖然說CKEditor有點肥大

 

不過還是強大到可以忽略掉他的臃腫了

像我這種半調子的工程師基本上是寫不出來的  orz

 

 

本來想厚臉皮介紹一下這兩個的使用心得

 

後來想了一想

網路上的資源多到恐怖  相關的文章快滿出來

 

哪差我這一兩篇

 

 

這篇就拿來分享一下當時想把CKEditor放進jQuery Dialog遇到的一些瓶頸

 

 

在開始之前先貼上這兩個元件的官方網頁

 

1. jQuery UI    -   http://jqueryui.com/

2. CKEditor   -   http://ckeditor.com/

 

 

首先要先介紹一個CKEditor本身對jQuery的支援

 

 

在不知道哪一版,  CKEditor檔案包裡面多了一個檔案 ckeditor\adapters\jquery.js

網頁中同時匯入這個檔案,  就可以使用jQuery存取CKEditor的一些屬性

 

例如說初始化 $('[selector]').ckeditor();

就可以把指定的dom轉成ckediotr了

 

 

我個人是覺得比原本的宣告方式直覺又明確的多了啦

 

 

回歸問題的重點,  CKEditor放在Dialog的時候,  會互相衝突而沒辦法好好運作

尤其是在設定dialog({modal:true})的時候

會發現CKEditor連點都不能點

 

 

要討論背後的機制跟發生的原因太麻煩, 簡單來說UI套上去, 我們的html就加上了他們的程式邏輯

例如搬到form外面

 

改成絕對位置等等

 

 

因此兩套ui就會有衝突的可能

 

===================================================================================================================

最簡單的解法,  利用dialog所提供的兩個屬性 

   1.  open – 在dialog打開的時候呼叫的function

   2.  close – 在dialog關閉的時候呼叫的function

 

至於要怎麼使用

 

$(function(){ 
	$('#dialog').dialog({
		open: function () {
			$(this).find('textarea').ckeditor();
		},
		close: function () {
			$(this).find('textarea').each(function(){
				$(this).ckeditorGet().destroy();
			});
		}
	});
});

簡單說明程式邏輯如下

 

dialog在open跟close的時候會把container的dom用this傳進去

 

因此我們可以去找出container下面的textarea把他轉成ckeditor  ( 注意,  此處為了方便直接找出全部的textarea, 實際在使用的時候可以自己在修改[selector])

而在Close的時候把textarea的ckeditor給destroy掉

 

而這樣ckeditor的生命週期就會在dialog之間,  而不會衝突

 

至於詳細點可以看到open的時候可以直接接ckeditor()

但是close的時候卻要用each去一個一個destroy

 

 

這個原因牽扯到ckeditor內部套用$.fn機制的回傳型別,  因此一個可以直接串接一個不行

這算是題外話了

 

===================================================================================================================

而在用下去會發現另外一個問題

 

CKEditor可以用歸可以用, 但是在dialog modal的情況下,  點選超連結等CKEditor本身的對話方塊

會發現連點都不能點

 

基本上這又是兩個ui另外一個衝突的地方

 

而CKEditor少掉了那些好用的插入超連結等功能,  基本上等於半殘

 

當時為了找這個的解法找得好辛苦 = =

 

就當成留做筆記放在這邊

 

 

在程式中加上這段

/*修正 dialog modal, ckeditor的dialog會失去作用的問題*/
$.extend($.ui.dialog.overlay, { create: function (dialog) {
    
    if (this.instances.length === 0) {
        // prevent use of anchors and inputs
        // we use a setTimeout in case the overlay is created from an
        // event that we're going to be cancelling (see #2804)
        setTimeout(function () {
            // handle $(el).dialog().dialog('close') (see #4065)
            if ($.ui.dialog.overlay.instances.length) {
                $(document).bind($.ui.dialog.overlay.events, function (event) {
                    var parentDialog = $(event.target).parents('.ui-dialog');
                    if (parentDialog.length > 0) {
                        var parentDialogZIndex = parentDialog.css('zIndex') || 0;
                        return parentDialogZIndex > $.ui.dialog.overlay.maxZ;
                    }

                    var aboveOverlay = false;
                    $(event.target).parents().each(function () {
                        var currentZ = $(this).css('zIndex') || 0;
                        if (currentZ > $.ui.dialog.overlay.maxZ) {
                            aboveOverlay = true;
                            return;
                        }
                    });

                    return aboveOverlay;
                });
            }
        }, 1);

        // allow closing by pressing the escape key
        $(document).bind('keydown.dialog-overlay', function (event) {
            (dialog.options.closeOnEscape && event.keyCode
					&& event.keyCode == $.ui.keyCode.ESCAPE && dialog.close(event));
        });

        // handle window resize
        $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize);
    }

    var $el = $('<div></div>').appendTo(document.body)
		.addClass('ui-widget-overlay').css({
		    width: this.width(),
		    height: this.height()
		});

    (dialog.options.stackfix && $.fn.stackfix && $el.stackfix());

    this.instances.push($el);
    return $el;
}
});

就可以修正這個問題,  裡面程式的邏輯比較複雜,  這邊就不多做說明了

 

總之是從國外copy paste回來的解法

 

可以在dialog modal:true的情況下,  在其中的CKEditor仍可以保有自身的功能正常

 

而我是直接把這段貼在ckeditor.js裡面

 

 

在這邊要致歉的是因為有一段時間了,  我也忘記這段程式碼從哪邊看來

 

就沒辦法把來源列在這邊讓人參考了

 

===================================================================================================================

最後一個部份是常用的ckeditor設定值

 

因為匯入了ckeditor\adapters\jquery.js 這個檔案

 

讓我們可以用一些jquery的方法去操作ckeditor

 

 

最簡單的方法就是可以在宣告的同時傳入設定值去調整ckeditor的屬性

例如說

$('[selector]').ckeditor(
	{ 
		width:400,  height:500,  
		toolbarStartupExpanded : false 
	}
);

 

簡單說明如下,

 

a. width: ckeditor的寬度

b. height: ckeditor的高度

c. toolbarStartUpExpanded : toolbar預設顯示還是隱藏

 

 

還有其他東西就希望前輩幫我補充了

 

--

本文可能有理解錯誤  或不盡不實的地方

請路過的前輩不要客氣  用力打醒

這會是我們成長的主要養分