font.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. /**
  2. * 字体颜色,背景色,字号,字体,下划线,删除线
  3. * @file
  4. * @since 1.2.6.1
  5. */
  6. /**
  7. * 字体颜色
  8. * @command forecolor
  9. * @method execCommand
  10. * @param { String } cmd 命令字符串
  11. * @param { String } value 色值(必须十六进制)
  12. * @example
  13. * ```javascript
  14. * editor.execCommand( 'forecolor', '#000' );
  15. * ```
  16. */
  17. /**
  18. * 返回选区字体颜色
  19. * @command forecolor
  20. * @method queryCommandValue
  21. * @param { String } cmd 命令字符串
  22. * @return { String } 返回字体颜色
  23. * @example
  24. * ```javascript
  25. * editor.queryCommandValue( 'forecolor' );
  26. * ```
  27. */
  28. /**
  29. * 字体背景颜色
  30. * @command backcolor
  31. * @method execCommand
  32. * @param { String } cmd 命令字符串
  33. * @param { String } value 色值(必须十六进制)
  34. * @example
  35. * ```javascript
  36. * editor.execCommand( 'backcolor', '#000' );
  37. * ```
  38. */
  39. /**
  40. * 返回选区字体颜色
  41. * @command backcolor
  42. * @method queryCommandValue
  43. * @param { String } cmd 命令字符串
  44. * @return { String } 返回字体背景颜色
  45. * @example
  46. * ```javascript
  47. * editor.queryCommandValue( 'backcolor' );
  48. * ```
  49. */
  50. /**
  51. * 字体大小
  52. * @command fontsize
  53. * @method execCommand
  54. * @param { String } cmd 命令字符串
  55. * @param { String } value 字体大小
  56. * @example
  57. * ```javascript
  58. * editor.execCommand( 'fontsize', '14px' );
  59. * ```
  60. */
  61. /**
  62. * 返回选区字体大小
  63. * @command fontsize
  64. * @method queryCommandValue
  65. * @param { String } cmd 命令字符串
  66. * @return { String } 返回字体大小
  67. * @example
  68. * ```javascript
  69. * editor.queryCommandValue( 'fontsize' );
  70. * ```
  71. */
  72. /**
  73. * 字体样式
  74. * @command fontfamily
  75. * @method execCommand
  76. * @param { String } cmd 命令字符串
  77. * @param { String } value 字体样式
  78. * @example
  79. * ```javascript
  80. * editor.execCommand( 'fontfamily', '微软雅黑' );
  81. * ```
  82. */
  83. /**
  84. * 返回选区字体样式
  85. * @command fontfamily
  86. * @method queryCommandValue
  87. * @param { String } cmd 命令字符串
  88. * @return { String } 返回字体样式
  89. * @example
  90. * ```javascript
  91. * editor.queryCommandValue( 'fontfamily' );
  92. * ```
  93. */
  94. /**
  95. * 字体下划线,与删除线互斥
  96. * @command underline
  97. * @method execCommand
  98. * @param { String } cmd 命令字符串
  99. * @example
  100. * ```javascript
  101. * editor.execCommand( 'underline' );
  102. * ```
  103. */
  104. /**
  105. * 字体删除线,与下划线互斥
  106. * @command strikethrough
  107. * @method execCommand
  108. * @param { String } cmd 命令字符串
  109. * @example
  110. * ```javascript
  111. * editor.execCommand( 'strikethrough' );
  112. * ```
  113. */
  114. /**
  115. * 字体边框
  116. * @command fontborder
  117. * @method execCommand
  118. * @param { String } cmd 命令字符串
  119. * @example
  120. * ```javascript
  121. * editor.execCommand( 'fontborder' );
  122. * ```
  123. */
  124. UE.plugins['font'] = function () {
  125. var me = this,
  126. fonts = {
  127. 'forecolor': 'color',
  128. 'backcolor': 'background-color',
  129. 'fontsize': 'font-size',
  130. 'fontfamily': 'font-family',
  131. 'underline': 'text-decoration',
  132. 'strikethrough': 'text-decoration',
  133. 'fontborder': 'border'
  134. },
  135. needCmd = {'underline': 1, 'strikethrough': 1, 'fontborder': 1},
  136. needSetChild = {
  137. 'forecolor': 'color',
  138. 'backcolor': 'background-color',
  139. 'fontsize': 'font-size',
  140. 'fontfamily': 'font-family'
  141. };
  142. me.setOpt({
  143. 'fontfamily': [
  144. { name: 'songti', val: '宋体,SimSun'},
  145. { name: 'yahei', val: '微软雅黑,Microsoft YaHei'},
  146. { name: 'kaiti', val: '楷体,楷体_GB2312, SimKai'},
  147. { name: 'heiti', val: '黑体, SimHei'},
  148. { name: 'lishu', val: '隶书, SimLi'},
  149. { name: 'andaleMono', val: 'andale mono'},
  150. { name: 'arial', val: 'arial, helvetica,sans-serif'},
  151. { name: 'arialBlack', val: 'arial black,avant garde'},
  152. { name: 'comicSansMs', val: 'comic sans ms'},
  153. { name: 'impact', val: 'impact,chicago'},
  154. { name: 'timesNewRoman', val: 'times new roman'}
  155. ],
  156. 'fontsize': [10, 11, 12, 14, 16, 18, 20, 24, 36]
  157. });
  158. function mergeWithParent(node){
  159. var parent;
  160. while(parent = node.parentNode){
  161. if(parent.tagName == 'SPAN' && domUtils.getChildCount(parent,function(child){
  162. return !domUtils.isBookmarkNode(child) && !domUtils.isBr(child)
  163. }) == 1) {
  164. parent.style.cssText += node.style.cssText;
  165. domUtils.remove(node,true);
  166. node = parent;
  167. }else{
  168. break;
  169. }
  170. }
  171. }
  172. function mergeChild(rng,cmdName,value){
  173. if(needSetChild[cmdName]){
  174. rng.adjustmentBoundary();
  175. if(!rng.collapsed && rng.startContainer.nodeType == 1){
  176. var start = rng.startContainer.childNodes[rng.startOffset];
  177. if(start && domUtils.isTagNode(start,'span')){
  178. var bk = rng.createBookmark();
  179. utils.each(domUtils.getElementsByTagName(start, 'span'), function (span) {
  180. if (!span.parentNode || domUtils.isBookmarkNode(span))return;
  181. if(cmdName == 'backcolor' && domUtils.getComputedStyle(span,'background-color').toLowerCase() === value){
  182. return;
  183. }
  184. domUtils.removeStyle(span,needSetChild[cmdName]);
  185. if(span.style.cssText.replace(/^\s+$/,'').length == 0){
  186. domUtils.remove(span,true)
  187. }
  188. });
  189. rng.moveToBookmark(bk)
  190. }
  191. }
  192. }
  193. }
  194. function mergesibling(rng,cmdName,value) {
  195. var collapsed = rng.collapsed,
  196. bk = rng.createBookmark(), common;
  197. if (collapsed) {
  198. common = bk.start.parentNode;
  199. while (dtd.$inline[common.tagName]) {
  200. common = common.parentNode;
  201. }
  202. } else {
  203. common = domUtils.getCommonAncestor(bk.start, bk.end);
  204. }
  205. utils.each(domUtils.getElementsByTagName(common, 'span'), function (span) {
  206. if (!span.parentNode || domUtils.isBookmarkNode(span))return;
  207. if (/\s*border\s*:\s*none;?\s*/i.test(span.style.cssText)) {
  208. if(/^\s*border\s*:\s*none;?\s*$/.test(span.style.cssText)){
  209. domUtils.remove(span, true);
  210. }else{
  211. domUtils.removeStyle(span,'border');
  212. }
  213. return
  214. }
  215. if (/border/i.test(span.style.cssText) && span.parentNode.tagName == 'SPAN' && /border/i.test(span.parentNode.style.cssText)) {
  216. span.style.cssText = span.style.cssText.replace(/border[^:]*:[^;]+;?/gi, '');
  217. }
  218. if(!(cmdName=='fontborder' && value=='none')){
  219. var next = span.nextSibling;
  220. while (next && next.nodeType == 1 && next.tagName == 'SPAN' ) {
  221. if(domUtils.isBookmarkNode(next) && cmdName == 'fontborder') {
  222. span.appendChild(next);
  223. next = span.nextSibling;
  224. continue;
  225. }
  226. if (next.style.cssText == span.style.cssText) {
  227. domUtils.moveChild(next, span);
  228. domUtils.remove(next);
  229. }
  230. if (span.nextSibling === next)
  231. break;
  232. next = span.nextSibling;
  233. }
  234. }
  235. mergeWithParent(span);
  236. if(browser.ie && browser.version > 8 ){
  237. //拷贝父亲们的特别的属性,这里只做背景颜色的处理
  238. var parent = domUtils.findParent(span,function(n){return n.tagName == 'SPAN' && /background-color/.test(n.style.cssText)});
  239. if(parent && !/background-color/.test(span.style.cssText)){
  240. span.style.backgroundColor = parent.style.backgroundColor;
  241. }
  242. }
  243. });
  244. rng.moveToBookmark(bk);
  245. mergeChild(rng,cmdName,value)
  246. }
  247. me.addInputRule(function (root) {
  248. utils.each(root.getNodesByTagName('u s del font strike'), function (node) {
  249. if (node.tagName == 'font') {
  250. var cssStyle = [];
  251. for (var p in node.attrs) {
  252. switch (p) {
  253. case 'size':
  254. cssStyle.push('font-size:' +
  255. ({
  256. '1':'10',
  257. '2':'12',
  258. '3':'16',
  259. '4':'18',
  260. '5':'24',
  261. '6':'32',
  262. '7':'48'
  263. }[node.attrs[p]] || node.attrs[p]) + 'px');
  264. break;
  265. case 'color':
  266. cssStyle.push('color:' + node.attrs[p]);
  267. break;
  268. case 'face':
  269. cssStyle.push('font-family:' + node.attrs[p]);
  270. break;
  271. case 'style':
  272. cssStyle.push(node.attrs[p]);
  273. }
  274. }
  275. node.attrs = {
  276. 'style': cssStyle.join(';')
  277. };
  278. } else {
  279. var val = node.tagName == 'u' ? 'underline' : 'line-through';
  280. node.attrs = {
  281. 'style': (node.getAttr('style') || '') + 'text-decoration:' + val + ';'
  282. }
  283. }
  284. node.tagName = 'span';
  285. });
  286. // utils.each(root.getNodesByTagName('span'), function (node) {
  287. // var val;
  288. // if(val = node.getAttr('class')){
  289. // if(/fontstrikethrough/.test(val)){
  290. // node.setStyle('text-decoration','line-through');
  291. // if(node.attrs['class']){
  292. // node.attrs['class'] = node.attrs['class'].replace(/fontstrikethrough/,'');
  293. // }else{
  294. // node.setAttr('class')
  295. // }
  296. // }
  297. // if(/fontborder/.test(val)){
  298. // node.setStyle('border','1px solid #000');
  299. // if(node.attrs['class']){
  300. // node.attrs['class'] = node.attrs['class'].replace(/fontborder/,'');
  301. // }else{
  302. // node.setAttr('class')
  303. // }
  304. // }
  305. // }
  306. // });
  307. });
  308. // me.addOutputRule(function(root){
  309. // utils.each(root.getNodesByTagName('span'), function (node) {
  310. // var val;
  311. // if(val = node.getStyle('text-decoration')){
  312. // if(/line-through/.test(val)){
  313. // if(node.attrs['class']){
  314. // node.attrs['class'] += ' fontstrikethrough';
  315. // }else{
  316. // node.setAttr('class','fontstrikethrough')
  317. // }
  318. // }
  319. //
  320. // node.setStyle('text-decoration')
  321. // }
  322. // if(val = node.getStyle('border')){
  323. // if(/1px/.test(val) && /solid/.test(val)){
  324. // if(node.attrs['class']){
  325. // node.attrs['class'] += ' fontborder';
  326. //
  327. // }else{
  328. // node.setAttr('class','fontborder')
  329. // }
  330. // }
  331. // node.setStyle('border')
  332. //
  333. // }
  334. // });
  335. // });
  336. for (var p in fonts) {
  337. (function (cmd, style) {
  338. UE.commands[cmd] = {
  339. execCommand: function (cmdName, value) {
  340. value = value || (this.queryCommandState(cmdName) ? 'none' : cmdName == 'underline' ? 'underline' :
  341. cmdName == 'fontborder' ? '1px solid #000' :
  342. 'line-through');
  343. var me = this,
  344. range = this.selection.getRange(),
  345. text;
  346. if (value == 'default') {
  347. if (range.collapsed) {
  348. text = me.document.createTextNode('font');
  349. range.insertNode(text).select();
  350. }
  351. me.execCommand('removeFormat', 'span,a', style);
  352. if (text) {
  353. range.setStartBefore(text).collapse(true);
  354. domUtils.remove(text);
  355. }
  356. mergesibling(range,cmdName,value);
  357. range.select()
  358. } else {
  359. if (!range.collapsed) {
  360. if (needCmd[cmd] && me.queryCommandValue(cmd)) {
  361. me.execCommand('removeFormat', 'span,a', style);
  362. }
  363. range = me.selection.getRange();
  364. range.applyInlineStyle('span', {'style': style + ':' + value});
  365. mergesibling(range, cmdName,value);
  366. range.select();
  367. } else {
  368. var span = domUtils.findParentByTagName(range.startContainer, 'span', true);
  369. text = me.document.createTextNode('font');
  370. if (span && !span.children.length && !span[browser.ie ? 'innerText' : 'textContent'].replace(fillCharReg, '').length) {
  371. //for ie hack when enter
  372. range.insertNode(text);
  373. if (needCmd[cmd]) {
  374. range.selectNode(text).select();
  375. me.execCommand('removeFormat', 'span,a', style, null);
  376. span = domUtils.findParentByTagName(text, 'span', true);
  377. range.setStartBefore(text);
  378. }
  379. span && (span.style.cssText += ';' + style + ':' + value);
  380. range.collapse(true).select();
  381. } else {
  382. range.insertNode(text);
  383. range.selectNode(text).select();
  384. span = range.document.createElement('span');
  385. if (needCmd[cmd]) {
  386. //a标签内的不处理跳过
  387. if (domUtils.findParentByTagName(text, 'a', true)) {
  388. range.setStartBefore(text).setCursor();
  389. domUtils.remove(text);
  390. return;
  391. }
  392. me.execCommand('removeFormat', 'span,a', style);
  393. }
  394. span.style.cssText = style + ':' + value;
  395. text.parentNode.insertBefore(span, text);
  396. //修复,span套span 但样式不继承的问题
  397. if (!browser.ie || browser.ie && browser.version == 9) {
  398. var spanParent = span.parentNode;
  399. while (!domUtils.isBlockElm(spanParent)) {
  400. if (spanParent.tagName == 'SPAN') {
  401. //opera合并style不会加入";"
  402. span.style.cssText = spanParent.style.cssText + ";" + span.style.cssText;
  403. }
  404. spanParent = spanParent.parentNode;
  405. }
  406. }
  407. if (opera) {
  408. setTimeout(function () {
  409. range.setStart(span, 0).collapse(true);
  410. mergesibling(range, cmdName,value);
  411. range.select();
  412. });
  413. } else {
  414. range.setStart(span, 0).collapse(true);
  415. mergesibling(range,cmdName,value);
  416. range.select();
  417. }
  418. //trace:981
  419. //domUtils.mergeToParent(span)
  420. }
  421. domUtils.remove(text);
  422. }
  423. }
  424. return true;
  425. },
  426. queryCommandValue: function (cmdName) {
  427. var startNode = this.selection.getStart();
  428. //trace:946
  429. if (cmdName == 'underline' || cmdName == 'strikethrough') {
  430. var tmpNode = startNode, value;
  431. while (tmpNode && !domUtils.isBlockElm(tmpNode) && !domUtils.isBody(tmpNode)) {
  432. if (tmpNode.nodeType == 1) {
  433. value = domUtils.getComputedStyle(tmpNode, style);
  434. if (value != 'none') {
  435. return value;
  436. }
  437. }
  438. tmpNode = tmpNode.parentNode;
  439. }
  440. return 'none';
  441. }
  442. if (cmdName == 'fontborder') {
  443. var tmp = startNode, val;
  444. while (tmp && dtd.$inline[tmp.tagName]) {
  445. if (val = domUtils.getComputedStyle(tmp, 'border')) {
  446. if (/1px/.test(val) && /solid/.test(val)) {
  447. return val;
  448. }
  449. }
  450. tmp = tmp.parentNode;
  451. }
  452. return ''
  453. }
  454. if( cmdName == 'FontSize' ) {
  455. var styleVal = domUtils.getComputedStyle(startNode, style),
  456. tmp = /^([\d\.]+)(\w+)$/.exec( styleVal );
  457. if( tmp ) {
  458. return Math.floor( tmp[1] ) + tmp[2];
  459. }
  460. return styleVal;
  461. }
  462. return domUtils.getComputedStyle(startNode, style);
  463. },
  464. queryCommandState: function (cmdName) {
  465. if (!needCmd[cmdName])
  466. return 0;
  467. var val = this.queryCommandValue(cmdName);
  468. if (cmdName == 'fontborder') {
  469. return /1px/.test(val) && /solid/.test(val)
  470. } else {
  471. return cmdName == 'underline' ? /underline/.test(val) : /line\-through/.test(val);
  472. }
  473. }
  474. };
  475. })(p, fonts[p]);
  476. }
  477. };