版本是
YUI editor 2.7.0,全称是YUI Rich Text Editor,富文本编辑器。(BTW, 本blog使用的就是这玩意儿,不过功能配置的比较少)
它的改变字体大小是用了一个很神奇的东西,叫 spin ,一个有上下小箭头的按钮,按上下按钮可以把字体大小加一减一。 但是这有2个问题:第一,箭头太小,很难点中(而且还有选择一次后lost focus的bug);第二,大多数用户不需要这么精细的字体大小控制(默认一共75个级别),其实只要有5、6个级别就行了,很小、小、中、大、超大之类的。总之,多数的已经是,改变字体大小还是用 select 下拉框的样式比较好。
淘宝最新使用的编辑器也是YUI editor, 不过他们做了很多hack,在
这里。在这个
例子的页面,可以看到,淘宝已经通过包装,在初始化时加入一个自定义的value为 fontsize2 的 select 到toolbar上,然后再监听 fontsize2Click, afterNodeChange 等事件,让 select 被选择的时候,按照响应的字体大小去调用 this.execCommand("fontsize", value + "pt") 的命令,来改变字体大小,于是,我们也有样学样,搬过来做了一套。
于是又发生了一个bug:敲入一行文字,选中一半,改变一下颜色。再次将有颜色的几个字和没有颜色的几个字选中,改变字体大小。结果:字体大小改变了,这几个字也变成了同一种颜色,大部分时候是默认的黑色。 其实后来发现这个 bug 不是 spin 改成 select 后导致的,因为其实是 this.execCommand("fontsize", value + "pt") 中实现的问题,不过,我们还是的解决它)。
经过追踪YUI editor的代码,选择字体大小后,将字体颜色属性去掉或者一部分颜色取代另一 颜色的原因在于,在执行 cmd_fontsize 的时候,调用了 _getSelectedElement 来取得当前选择的元素,然后调用 _createCurrentElement 创建新的同tag元素替换当前选择的元素,创建的时候保留原来元素的大部分样式属性,但是更改 fontSize 来达到改变字体的目的。
冲突的地方在于:用户当前选择的可能不是一个元素,而是 abc<span style="font-color:red">de</span> 这样的一个片段,而这时候 _createCurrentElement 会返回 iframe 的 body 元素,而 body 元素是没有style的颜色等属性的。所以,在随后的 _createCurrentElement 的创建替代原素的时候,所有被标记了 fontname 是 'yui-tmp' 的元素会被用body元素的属性替换,比如无色,这样,原来的颜色就没有了
现在的问题应该在于: yui 调用 _getSelectedElement 的时候,get得到了错误的html 片段。导致 _createCurrentElement 调用时候的参数错误。而 _createCurrentElement 并不是处理一个元素(因为用户可能选中多个元素的,比如一半红色的字一般黑色的字), _createCurrentElement 里面用传入的样式,用 'yui-tmp' 标记找到所有需要修改的元素,用这个统一的样式修改。这里的逻辑就错了
既然 _createCurrentElement 需要处理多个元素,那么,它的除了当前要修改到得属性值(在这里是字体大小),其他的属性值应该是需要被修改的多个元素自身带有的,而不应该用 _getSelectedElement 返回值的这一个元素的属性值来代替(因为在选择了多个元素的时候,这个函数不能返回一个原素,只好返回他们的parent,即 iframe 的 body
所以,现在改写 _createCurrentElement 的逻辑,应该可以解决这个问题。
实际修改了simpleeditor.js 这个源文件,实现如下:
将 6154 行的
this._createCurrentElement('span', {'fontSize': value, fontFamily: el.style.fontFamily, color: el.style.color, backgroundColor: el.style.backgroundColor });修改为:
this._createCurrentElement('span', {'fontSize': value, fontFamily: el.style.fontFamily, color: el.style.color, backgroundColor: el.style.backgroundColor }, {'fontSize' : value});额外传递字体参数。
在 _createCurrentElement 方法的实现中 6351 行前面插入一行,由:
_tmp[i].parentNode.replaceChild(el, _tmp[i]);
改为:
YAHOO.lang.augmentObject(el.style, _tmp[i].style, arguments[2] || {});
_tmp[i].parentNode.replaceChild(el, _tmp[i]);
调用将要被替换的元素的 style 属性填充新元素的 style 属性,并且用参数里面真正在被设置的属性覆盖原有属性。
经过测试,problem solved.