font.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  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 (
  162. parent.tagName == "SPAN" &&
  163. domUtils.getChildCount(parent, function(child) {
  164. return !domUtils.isBookmarkNode(child) && !domUtils.isBr(child);
  165. }) == 1
  166. ) {
  167. parent.style.cssText += node.style.cssText;
  168. domUtils.remove(node, true);
  169. node = parent;
  170. } else {
  171. break;
  172. }
  173. }
  174. }
  175. function mergeChild(rng, cmdName, value) {
  176. if (needSetChild[cmdName]) {
  177. rng.adjustmentBoundary();
  178. if (!rng.collapsed && rng.startContainer.nodeType == 1) {
  179. var start = rng.startContainer.childNodes[rng.startOffset];
  180. if (start && domUtils.isTagNode(start, "span")) {
  181. var bk = rng.createBookmark();
  182. utils.each(domUtils.getElementsByTagName(start, "span"), function(
  183. span
  184. ) {
  185. if (!span.parentNode || domUtils.isBookmarkNode(span)) return;
  186. if (
  187. cmdName == "backcolor" &&
  188. domUtils
  189. .getComputedStyle(span, "background-color")
  190. .toLowerCase() === value
  191. ) {
  192. return;
  193. }
  194. domUtils.removeStyle(span, needSetChild[cmdName]);
  195. if (span.style.cssText.replace(/^\s+$/, "").length == 0) {
  196. domUtils.remove(span, true);
  197. }
  198. });
  199. rng.moveToBookmark(bk);
  200. }
  201. }
  202. }
  203. }
  204. function mergesibling(rng, cmdName, value) {
  205. var collapsed = rng.collapsed,
  206. bk = rng.createBookmark(),
  207. common;
  208. if (collapsed) {
  209. common = bk.start.parentNode;
  210. while (dtd.$inline[common.tagName]) {
  211. common = common.parentNode;
  212. }
  213. } else {
  214. common = domUtils.getCommonAncestor(bk.start, bk.end);
  215. }
  216. utils.each(domUtils.getElementsByTagName(common, "span"), function(span) {
  217. if (!span.parentNode || domUtils.isBookmarkNode(span)) return;
  218. if (/\s*border\s*:\s*none;?\s*/i.test(span.style.cssText)) {
  219. if (/^\s*border\s*:\s*none;?\s*$/.test(span.style.cssText)) {
  220. domUtils.remove(span, true);
  221. } else {
  222. domUtils.removeStyle(span, "border");
  223. }
  224. return;
  225. }
  226. if (
  227. /border/i.test(span.style.cssText) &&
  228. span.parentNode.tagName == "SPAN" &&
  229. /border/i.test(span.parentNode.style.cssText)
  230. ) {
  231. span.style.cssText = span.style.cssText.replace(
  232. /border[^:]*:[^;]+;?/gi,
  233. ""
  234. );
  235. }
  236. if (!(cmdName == "fontborder" && value == "none")) {
  237. var next = span.nextSibling;
  238. while (next && next.nodeType == 1 && next.tagName == "SPAN") {
  239. if (domUtils.isBookmarkNode(next) && cmdName == "fontborder") {
  240. span.appendChild(next);
  241. next = span.nextSibling;
  242. continue;
  243. }
  244. if (next.style.cssText == span.style.cssText) {
  245. domUtils.moveChild(next, span);
  246. domUtils.remove(next);
  247. }
  248. if (span.nextSibling === next) break;
  249. next = span.nextSibling;
  250. }
  251. }
  252. mergeWithParent(span);
  253. if (browser.ie && browser.version > 8) {
  254. //拷贝父亲们的特别的属性,这里只做背景颜色的处理
  255. var parent = domUtils.findParent(span, function(n) {
  256. return (
  257. n.tagName == "SPAN" && /background-color/.test(n.style.cssText)
  258. );
  259. });
  260. if (parent && !/background-color/.test(span.style.cssText)) {
  261. span.style.backgroundColor = parent.style.backgroundColor;
  262. }
  263. }
  264. });
  265. rng.moveToBookmark(bk);
  266. mergeChild(rng, cmdName, value);
  267. }
  268. me.addInputRule(function(root) {
  269. utils.each(root.getNodesByTagName("u s del font strike"), function(node) {
  270. if (node.tagName == "font") {
  271. var cssStyle = [];
  272. for (var p in node.attrs) {
  273. switch (p) {
  274. case "size":
  275. cssStyle.push(
  276. "font-size:" +
  277. ({
  278. "1": "10",
  279. "2": "12",
  280. "3": "16",
  281. "4": "18",
  282. "5": "24",
  283. "6": "32",
  284. "7": "48"
  285. }[node.attrs[p]] || node.attrs[p]) +
  286. "px"
  287. );
  288. break;
  289. case "color":
  290. cssStyle.push("color:" + node.attrs[p]);
  291. break;
  292. case "face":
  293. cssStyle.push("font-family:" + node.attrs[p]);
  294. break;
  295. case "style":
  296. cssStyle.push(node.attrs[p]);
  297. }
  298. }
  299. node.attrs = {
  300. style: cssStyle.join(";")
  301. };
  302. } else {
  303. var val = node.tagName == "u" ? "underline" : "line-through";
  304. node.attrs = {
  305. style: (node.getAttr("style") || "") + "text-decoration:" + val + ";"
  306. };
  307. }
  308. node.tagName = "span";
  309. });
  310. // utils.each(root.getNodesByTagName('span'), function (node) {
  311. // var val;
  312. // if(val = node.getAttr('class')){
  313. // if(/fontstrikethrough/.test(val)){
  314. // node.setStyle('text-decoration','line-through');
  315. // if(node.attrs['class']){
  316. // node.attrs['class'] = node.attrs['class'].replace(/fontstrikethrough/,'');
  317. // }else{
  318. // node.setAttr('class')
  319. // }
  320. // }
  321. // if(/fontborder/.test(val)){
  322. // node.setStyle('border','1px solid #000');
  323. // if(node.attrs['class']){
  324. // node.attrs['class'] = node.attrs['class'].replace(/fontborder/,'');
  325. // }else{
  326. // node.setAttr('class')
  327. // }
  328. // }
  329. // }
  330. // });
  331. });
  332. // me.addOutputRule(function(root){
  333. // utils.each(root.getNodesByTagName('span'), function (node) {
  334. // var val;
  335. // if(val = node.getStyle('text-decoration')){
  336. // if(/line-through/.test(val)){
  337. // if(node.attrs['class']){
  338. // node.attrs['class'] += ' fontstrikethrough';
  339. // }else{
  340. // node.setAttr('class','fontstrikethrough')
  341. // }
  342. // }
  343. //
  344. // node.setStyle('text-decoration')
  345. // }
  346. // if(val = node.getStyle('border')){
  347. // if(/1px/.test(val) && /solid/.test(val)){
  348. // if(node.attrs['class']){
  349. // node.attrs['class'] += ' fontborder';
  350. //
  351. // }else{
  352. // node.setAttr('class','fontborder')
  353. // }
  354. // }
  355. // node.setStyle('border')
  356. //
  357. // }
  358. // });
  359. // });
  360. for (var p in fonts) {
  361. (function(cmd, style) {
  362. UE.commands[cmd] = {
  363. execCommand: function(cmdName, value) {
  364. value =
  365. value ||
  366. (this.queryCommandState(cmdName)
  367. ? "none"
  368. : cmdName == "underline"
  369. ? "underline"
  370. : cmdName == "fontborder" ? "1px solid #000" : "line-through");
  371. var me = this,
  372. range = this.selection.getRange(),
  373. text;
  374. if (value == "default") {
  375. if (range.collapsed) {
  376. text = me.document.createTextNode("font");
  377. range.insertNode(text).select();
  378. }
  379. me.execCommand("removeFormat", "span,a", style);
  380. if (text) {
  381. range.setStartBefore(text).collapse(true);
  382. domUtils.remove(text);
  383. }
  384. mergesibling(range, cmdName, value);
  385. range.select();
  386. } else {
  387. if (!range.collapsed) {
  388. if (needCmd[cmd] && me.queryCommandValue(cmd)) {
  389. me.execCommand("removeFormat", "span,a", style);
  390. }
  391. range = me.selection.getRange();
  392. range.applyInlineStyle("span", { style: style + ":" + value });
  393. mergesibling(range, cmdName, value);
  394. range.select();
  395. } else {
  396. var span = domUtils.findParentByTagName(
  397. range.startContainer,
  398. "span",
  399. true
  400. );
  401. text = me.document.createTextNode("font");
  402. if (
  403. span &&
  404. !span.children.length &&
  405. !span[browser.ie ? "innerText" : "textContent"].replace(
  406. fillCharReg,
  407. ""
  408. ).length
  409. ) {
  410. //for ie hack when enter
  411. range.insertNode(text);
  412. if (needCmd[cmd]) {
  413. range.selectNode(text).select();
  414. me.execCommand("removeFormat", "span,a", style, null);
  415. span = domUtils.findParentByTagName(text, "span", true);
  416. range.setStartBefore(text);
  417. }
  418. span && (span.style.cssText += ";" + style + ":" + value);
  419. range.collapse(true).select();
  420. } else {
  421. range.insertNode(text);
  422. range.selectNode(text).select();
  423. span = range.document.createElement("span");
  424. if (needCmd[cmd]) {
  425. //a标签内的不处理跳过
  426. if (domUtils.findParentByTagName(text, "a", true)) {
  427. range.setStartBefore(text).setCursor();
  428. domUtils.remove(text);
  429. return;
  430. }
  431. me.execCommand("removeFormat", "span,a", style);
  432. }
  433. span.style.cssText = style + ":" + value;
  434. text.parentNode.insertBefore(span, text);
  435. //修复,span套span 但样式不继承的问题
  436. if (!browser.ie || (browser.ie && browser.version == 9)) {
  437. var spanParent = span.parentNode;
  438. while (!domUtils.isBlockElm(spanParent)) {
  439. if (spanParent.tagName == "SPAN") {
  440. //opera合并style不会加入";"
  441. span.style.cssText =
  442. spanParent.style.cssText + ";" + span.style.cssText;
  443. }
  444. spanParent = spanParent.parentNode;
  445. }
  446. }
  447. if (opera) {
  448. setTimeout(function() {
  449. range.setStart(span, 0).collapse(true);
  450. mergesibling(range, cmdName, value);
  451. range.select();
  452. });
  453. } else {
  454. range.setStart(span, 0).collapse(true);
  455. mergesibling(range, cmdName, value);
  456. range.select();
  457. }
  458. //trace:981
  459. //domUtils.mergeToParent(span)
  460. }
  461. domUtils.remove(text);
  462. }
  463. }
  464. return true;
  465. },
  466. queryCommandValue: function(cmdName) {
  467. var startNode = this.selection.getStart();
  468. //trace:946
  469. if (cmdName == "underline" || cmdName == "strikethrough") {
  470. var tmpNode = startNode,
  471. value;
  472. while (
  473. tmpNode &&
  474. !domUtils.isBlockElm(tmpNode) &&
  475. !domUtils.isBody(tmpNode)
  476. ) {
  477. if (tmpNode.nodeType == 1) {
  478. value = domUtils.getComputedStyle(tmpNode, style);
  479. if (value != "none") {
  480. return value;
  481. }
  482. }
  483. tmpNode = tmpNode.parentNode;
  484. }
  485. return "none";
  486. }
  487. if (cmdName == "fontborder") {
  488. var tmp = startNode,
  489. val;
  490. while (tmp && dtd.$inline[tmp.tagName]) {
  491. if ((val = domUtils.getComputedStyle(tmp, "border"))) {
  492. if (/1px/.test(val) && /solid/.test(val)) {
  493. return val;
  494. }
  495. }
  496. tmp = tmp.parentNode;
  497. }
  498. return "";
  499. }
  500. if (cmdName == "FontSize") {
  501. var styleVal = domUtils.getComputedStyle(startNode, style),
  502. tmp = /^([\d\.]+)(\w+)$/.exec(styleVal);
  503. if (tmp) {
  504. return Math.floor(tmp[1]) + tmp[2];
  505. }
  506. return styleVal;
  507. }
  508. return domUtils.getComputedStyle(startNode, style);
  509. },
  510. queryCommandState: function(cmdName) {
  511. if (!needCmd[cmdName]) return 0;
  512. var val = this.queryCommandValue(cmdName);
  513. if (cmdName == "fontborder") {
  514. return /1px/.test(val) && /solid/.test(val);
  515. } else {
  516. return cmdName == "underline"
  517. ? /underline/.test(val)
  518. : /line\-through/.test(val);
  519. }
  520. }
  521. };
  522. })(p, fonts[p]);
  523. }
  524. };