導(dǎo)語
在ckeditor中,列表是多層嵌套結(jié)構(gòu),li元素是ul或ol的唯一類型元素,所以被嵌套列表ul或ol必須被包在li下,由于層級的計(jì)算比較困難,所以改為單層嵌套。邏輯梳理如下:
列表有三種類型,分別為有序列表、無序列表以及選擇列表。其中有序列表與無序列表都封裝在UL標(biāo)簽中,而選擇列表由自定義標(biāo)簽CL來封裝。列表結(jié)構(gòu)為單層結(jié)構(gòu),即無嵌套DOM li節(jié)點(diǎn)。
有序列表
<ul>
<li ce-para-type="ORDERED_LIST">
~
</li>
</ul>
無序列表
<ul>
<li ce-para-type="UNORDERED_LIST">
~
</li>
</ul>
選擇列表
<ul>
<li ce-para-type="CHECKED_LIST">
~
</li>
</ul>
一.列表操作邏輯
代碼主要在list/plugin.js文件中,描述列表在操作時(shí)的功能展現(xiàn)。
添加列表
在文檔加載完成后,添加列表指的是由P段落轉(zhuǎn)變成各個(gè)列表的過程。
入口代碼:
createList.call( this, editor, groupObj, listsCreated );
在進(jìn)入入口之前,選取選擇區(qū)域的節(jié)點(diǎn)數(shù)組(groupObj.contents),依次處理數(shù)組中的內(nèi)容,變?yōu)橹付斜?。最后重新?jì)算序號標(biāo)簽。
變換列表
列表三種樣式互換的過程。
入口代碼:
changeListType.call( this, editor, groupObj, database, listsCreated );
通過listArray方法將實(shí)際列表節(jié)點(diǎn)包裝成指定數(shù)組,操作數(shù)組,將每個(gè)元素替換標(biāo)簽。同時(shí)將元素所在的列表群同時(shí)變換樣式。其中選擇列表變?yōu)橛行蚧驘o序列表時(shí),會(huì)消除最外層的刪除線(局部刪除線保留)。
刪除列表
入口代碼:
removeList.call( this, editor, groupObj, database );
刪除列表指的是由各個(gè)列表轉(zhuǎn)變成P段落的過程。
將選中的列表(列表組)的屬性和子節(jié)點(diǎn)全部放在新建的普通段落中,若普通段落里面沒有內(nèi)容,用br填充,其后的節(jié)點(diǎn)序號重算,并放入一個(gè)新建的與原父節(jié)點(diǎn)相同的標(biāo)簽中。插入在新建的普通段落之后。
列表層級變換
樣式全部由CSS來控制,層級變換是通過修改節(jié)點(diǎn)屬性來實(shí)現(xiàn)。共8級層級。
///script/ckeditor/plugins/indentlist/plugin.js
function indent( listNode ) {
···
var indentOffset = that.isIndent ? 1 : -1;
listArray[k].indent += indentOffset;
···
}
層級變換需要確定選中的都是列表,在代碼中在這方面寫了保護(hù)機(jī)制。在CL中input框需要重寫響應(yīng)事件。每次縮進(jìn)操作都會(huì)重算序號。
二.列表同步與加載邏輯
代碼主要在coedit/plugin.js文件中,描述列表加載與同步的功能展現(xiàn)。
有序列表和無序列表加載與更新是一組函數(shù),選擇列表加載和更新是另外一組函數(shù)。
列表查找
編輯框中根據(jù)ID全查找,入特定數(shù)組。
數(shù)組格式
[列表類型,列表縮進(jìn)值,列表本身節(jié)點(diǎn)]
或 無法找到節(jié)點(diǎn)
[-1,undefined,undefined]
列表加載
依賴段落ID(string)與插入位置(bool)
有序列表和無序列表插入
判斷基本段落類型,分情況插入
//找到段落
if(basePara[1] >= 0 && basePara[0] != 3)//有序列表和無序列表
}else if(basePara[0] == 3){//選擇列表
else{//普通段落
}
//找不到段落
//插入首個(gè)帶有ID段落的前面
newNodePack.insertBefore( baseElement );
插入段落后進(jìn)行段落序號重排
有序列表和無序列表更新
判斷被更新段落類型,分情況更新
if(baseType == 'other'){
//普通段落轉(zhuǎn)列表
}else if(newNodeTag == 'other'){
//列表轉(zhuǎn)普通段落
}else{
//列表更新為列表
oNewElement.insertAfter(basePara[2]);
}
列表更新完成后,查看被更新段落的父節(jié)點(diǎn)(ul)是否將會(huì)出現(xiàn)沒有子元素的情況,若將會(huì)出現(xiàn),則刪除父節(jié)點(diǎn);若不出現(xiàn),重新計(jì)算,上下段落合并。
選擇列表的插入
對選擇列表的上下環(huán)境進(jìn)行判斷,對列表節(jié)點(diǎn)進(jìn)行包裹
switch(basePara[0]){
case 0:
readyToInsert = newNodePack;
break;
case 1:
case 2:
var listLevel = basePara[1];
readyToInsert = newNodePack;
baseElement = baseElement.getParent();
break;
case 3:
break;
default:
break;
}
包裹后前后插入,若找不到段落,處理情況和普通列表無法找到段落的情況一致。
選擇列表的更新
只有被更新項(xiàng)為選擇列表或者將要更新為選擇列表,回進(jìn)入此函數(shù)執(zhí)行
if(basePara[0] == 3){
if(newNodeTag == 'cl'){
//check變check
}else if(newNodeTag != 'other'){
//check變列表,basePara中的所有節(jié)點(diǎn)都要變
}else{
//check變普通段落
}
}else if(newNodeTag == 'cl'){
if(basePara[0] == 0){
//普通段落變check
}else if(basePara[0] == 1 || basePara[0] == 2){
//列表變check,增加小框
}
}
變成普通段落:原段落序號重算
變成選擇列表:對Input事件添加
變?yōu)槠渌斜恚盒蛱栔厮悖舷露温浜喜?br>
若找不到段落,控制臺(tái)出現(xiàn)警告提醒。