1 /** 2 * bubble or tip view for kissy editor 3 * @author yiminghe@gmail.com 4 */ 5 KISSY.add("editor/plugin/bubble/index", function (S, Overlay, Editor) { 6 var Event = S.Event, 7 undefined = {}['a'], 8 DOM = S.DOM, 9 BUBBLE_CFG = { 10 zIndex:Editor.baseZIndex(Editor.zIndexManager.BUBBLE_VIEW), 11 elCls:"ks-editor-bubble", 12 prefixCls:"ks-editor-", 13 effect:{ 14 effect:"fade", 15 duration:0.3 16 } 17 }; 18 19 function inRange(t, b, r) { 20 return t <= r && b >= r; 21 } 22 23 /** 24 * 是否两个bubble上下重叠? 25 */ 26 function overlap(b1, b2) { 27 var b1_top = b1.get("y"), 28 b1_bottom = b1_top + b1.get("el").outerHeight(), 29 b2_top = b2.get("y"), 30 b2_bottom = b2_top + b2.get("el").outerHeight(); 31 32 return inRange(b1_top, b1_bottom, b2_bottom) || 33 inRange(b1_top, b1_bottom, b2_top); 34 } 35 36 /** 37 * 得到依附在同一个节点上的所有 bubble 中的最下面一个 38 */ 39 function getTopPosition(self) { 40 var archor = null, 41 editor = self.get("editor"), 42 myBubbles = editor.getControls(); 43 S.each(myBubbles, function (bubble) { 44 if (bubble.get && (bubble.get("elCls") || "").indexOf("bubble") != -1 && 45 bubble !== self && 46 bubble.get("visible") && 47 overlap(self, bubble)) { 48 if (!archor) { 49 archor = bubble; 50 } else if (archor.get("y") < bubble.get("y")) { 51 archor = bubble; 52 } 53 } 54 return archor; 55 }); 56 } 57 58 function getXy(bubble) { 59 60 var el = bubble.get("editorSelectedEl"); 61 62 63 if (!el) { 64 return undefined; 65 } 66 67 var editor = bubble.get("editor"), 68 editorWin = editor.get("window")[0], 69 iframeXY = editor.get("iframe").offset(), 70 top = iframeXY.top, 71 left = iframeXY.left, 72 right = left + DOM.width(editorWin), 73 bottom = top + DOM.height(editorWin), 74 elXY = el.offset(undefined, window), 75 elTop = elXY.top, 76 elLeft = elXY.left, 77 elRight = elLeft + el.width(), 78 elBottom = elTop + el.height(), 79 x, 80 y; 81 82 // 对其下边 83 // el 位于编辑区域,下边界超了编辑区域下边界 84 if (elBottom > bottom && elTop < bottom) { 85 // 别挡着滚动条 86 y = bottom - 30; 87 } 88 // el bottom 在编辑区域内 89 else if (elBottom > top && elBottom < bottom) { 90 y = elBottom; 91 } 92 93 // 同上,对齐左边 94 if (elRight > left && elLeft < left) { 95 x = left; 96 } else if (elLeft > left && elLeft < right) { 97 x = elLeft; 98 } 99 100 if (x !== undefined && y !== undefined) { 101 return [x, y]; 102 } 103 return undefined; 104 } 105 106 Editor.prototype.addBubble = function (id, filter, cfg) { 107 var editor = this, 108 bubble; 109 110 cfg = cfg || {}; 111 112 cfg.editor = editor; 113 114 S.mix(cfg, BUBBLE_CFG); 115 116 bubble = new Overlay(cfg); 117 118 editor.addControl(id + "/bubble", bubble); 119 120 // 借鉴google doc tip提示显示 121 editor.on("selectionChange", function (ev) { 122 var elementPath = ev.path, 123 elements = elementPath.elements, 124 a, 125 lastElement; 126 if (elementPath && elements) { 127 lastElement = elementPath.lastElement; 128 if (!lastElement) { 129 return; 130 } 131 a = filter(lastElement); 132 if (a) { 133 bubble.set("editorSelectedEl", a); 134 // 重新触发 bubble show 事件 135 bubble.hide(); 136 // 等所有 bubble hide 再show 137 S.later(onShow, 10); 138 } else { 139 onHide(); 140 } 141 } 142 }); 143 144 // 代码模式下就消失 145 // !TODO 耦合--- 146 function onHide() { 147 bubble.hide(); 148 var editorWin = editor.get("window")[0]; 149 Event.remove(editorWin, "scroll", onScroll); 150 } 151 152 editor.on("sourceMode", onHide); 153 154 155 156 function showImmediately() { 157 158 var xy = getXy(bubble); 159 if (xy) { 160 bubble.set("xy", xy); 161 var archor = getTopPosition(bubble); 162 if (archor) { 163 xy[1] = archor.get("y") + archor.get("el").outerHeight(); 164 bubble.set("xy", xy); 165 } 166 if (!bubble.get("visible")) { 167 bubble.show(); 168 } else { 169 S.log("already show by selectionChange"); 170 } 171 } 172 } 173 174 var bufferScroll = S.buffer(showImmediately, 350); 175 176 function onScroll() { 177 if (!bubble.get("editorSelectedEl")) { 178 return; 179 } 180 var el = bubble.get("el"); 181 bubble.hide(); 182 bufferScroll(); 183 } 184 185 function onShow() { 186 var editorWin = editor.get("window")[0]; 187 Event.on(editorWin, "scroll", onScroll); 188 showImmediately(); 189 } 190 }; 191 }, { 192 requires:['overlay', 'editor'] 193 });