inlineString.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. import {getFontStyleByCell, textTrim} from "../global/getdata";
  2. import {selectTextContent,selectTextContentCross,selectTextContentCollapse} from '../global/cursorPos';
  3. import locale from '../locale/locale';
  4. import Store from '../store';
  5. export const inlineStyleAffectAttribute = {"bl":1, "it":1 , "ff":1, "cl":1, "un":1,"fs":1,"fc":1};
  6. export const inlineStyleAffectCssName = {"font-weight":1, "font-style":1 , "font-family":1, "text-decoration":1, "border-bottom":1,"font-size":1,"color":1};
  7. export function isInlineStringCell(cell){
  8. let isIs = cell && cell.ct!=null && cell.ct.t=="inlineStr" && cell.ct.s!=null && cell.ct.s.length>0;
  9. return isIs;
  10. }
  11. export function isInlineStringCT(ct){
  12. let isIs = ct!=null && ct.t=="inlineStr" && ct.s!=null && ct.s.length>0;
  13. return isIs;
  14. }
  15. export function updateInlineStringFormat(cell, attr, value, $input){
  16. // let s = Store.inlineStringEditCache;
  17. var w = window.getSelection();
  18. var range;
  19. if(w.type=="None"){
  20. range = Store.inlineStringEditRange;
  21. }
  22. else{
  23. range = w.getRangeAt(0);
  24. }
  25. // if(isInlineStringCell(cell)){
  26. // if(Store.inlineStringEditCache==null){
  27. // Store.inlineStringEditCache = JSON.parse(JSON.stringify(cell.ct.s));
  28. // }
  29. // }
  30. // else{
  31. // Store.inlineStringEditCache = [{
  32. // v:cell.v
  33. // }];
  34. // }
  35. let cac = range.commonAncestorContainer;
  36. let $textEditor;
  37. if(cac.id=="luckysheet-rich-text-editor"){
  38. $textEditor = $(cac);
  39. }
  40. else{
  41. $textEditor = $(cac).closest("#luckysheet-rich-text-editor");
  42. }
  43. let $functionbox = $(cac).closest("#luckysheet-functionbox-cell");
  44. if($textEditor.length==0 && $functionbox.length==0 && Store.inlineStringEditRange!=null){
  45. range = Store.inlineStringEditRange;
  46. cac = range.commonAncestorContainer;
  47. if(cac.id=="luckysheet-rich-text-editor"){
  48. $textEditor = $(cac);
  49. }
  50. else{
  51. $textEditor = $(cac).closest("#luckysheet-rich-text-editor");
  52. }
  53. $functionbox = $(cac).closest("#luckysheet-functionbox-cell");
  54. }
  55. if(range.collapsed===true){
  56. return;
  57. }
  58. let endContainer = range.endContainer, startContainer = range.startContainer;
  59. let endOffset = range.endOffset, startOffset = range.startOffset;
  60. if($textEditor.length>0){
  61. if(startContainer===endContainer){
  62. let span = startContainer.parentNode, spanIndex, inherit=false;
  63. let content = span.innerHTML;
  64. let fullContent = $textEditor.html();
  65. if(fullContent.substr(0,5) != "<span"){
  66. inherit = true;
  67. }
  68. let left="" , mid="" , right="";
  69. let s1=0, s2=startOffset, s3 = endOffset, s4=content.length;
  70. left = content.substring(s1, s2);
  71. mid = content.substring(s2, s3);
  72. right = content.substring(s3, s4);
  73. let cont = "";
  74. if(left!=""){
  75. let cssText = span.style.cssText;
  76. if(inherit){
  77. let box = $(span).closest("#luckysheet-input-box").get(0);
  78. if(box!=null){
  79. cssText = extendCssText(box.style.cssText, cssText);
  80. }
  81. }
  82. cont += "<span style='"+ cssText +"'>" + left + "</span>";
  83. }
  84. if(mid!=""){
  85. // let styleObj = {};
  86. // styleObj[attr] = value;
  87. // let s = getFontStyleByCell(styleObj, undefined, undefined, false);
  88. // let ukey = textTrim(s.substr(0, s.indexOf(':')));
  89. // let uvalue = textTrim(s.substr(s.indexOf(':')+1));
  90. // uvalue = uvalue.substr(0, uvalue.length-1);
  91. // let cssText = span.style.cssText;
  92. // cssText = removeClassWidthCss(cssText, attr);
  93. let cssText = getCssText(span.style.cssText, attr, value);
  94. if(inherit){
  95. let box = $(span).closest("#luckysheet-input-box").get(0);
  96. if(box!=null){
  97. cssText = extendCssText(box.style.cssText, cssText);
  98. }
  99. }
  100. cont += "<span style='"+ cssText +"'>" + mid + "</span>";
  101. }
  102. if(right!=""){
  103. let cssText = span.style.cssText;
  104. if(inherit){
  105. let box = $(span).closest("#luckysheet-input-box").get(0);
  106. if(box!=null){
  107. cssText = extendCssText(box.style.cssText, cssText);
  108. }
  109. }
  110. cont += "<span style='"+ cssText +"'>" + right + "</span>";
  111. }
  112. if(startContainer.parentNode.tagName=="SPAN"){
  113. spanIndex = $textEditor.find("span").index(span);
  114. $(span).replaceWith(cont);
  115. }
  116. else{
  117. spanIndex = 0;
  118. $(span).html(cont);
  119. }
  120. let seletedNodeIndex = 0;
  121. if(s1==s2){
  122. seletedNodeIndex = spanIndex;
  123. }
  124. else{
  125. seletedNodeIndex = spanIndex+1;
  126. }
  127. selectTextContent($textEditor.find("span").get(seletedNodeIndex));
  128. }
  129. else{
  130. if(startContainer.parentNode.tagName=="SPAN" && endContainer.parentNode.tagName=="SPAN"){
  131. let startSpan = startContainer.parentNode, startSpanIndex;
  132. let endSpan = endContainer.parentNode, endSpanIndex;
  133. startSpanIndex = $textEditor.find("span").index(startSpan);
  134. endSpanIndex = $textEditor.find("span").index(endSpan);
  135. let startContent = startSpan.innerHTML, endContent = endSpan.innerHTML;
  136. let sleft="" , sright="", eleft="" , eright="";
  137. let s1=0, s2=startOffset, s3 = endOffset, s4=endContent.length;
  138. sleft = startContent.substring(s1, s2);
  139. sright = startContent.substring(s2, startContent.length);
  140. eleft = endContent.substring(0, s3);
  141. eright = endContent.substring(s3, s4);
  142. let spans = $textEditor.find("span");
  143. let replaceSpans = spans.slice(startSpanIndex, endSpanIndex+1);
  144. let cont = "";
  145. for(let i=0;i<startSpanIndex;i++){
  146. let span = spans.get(i), content = span.innerHTML;
  147. cont += "<span style='"+ span.style.cssText +"'>" + content + "</span>";
  148. }
  149. if(sleft!=""){
  150. cont += "<span style='"+ startSpan.style.cssText +"'>" + sleft + "</span>";
  151. }
  152. if(sright!=""){
  153. let cssText = getCssText(startSpan.style.cssText, attr, value);
  154. cont += "<span style='"+ cssText +"'>" + sright + "</span>";
  155. }
  156. if(startSpanIndex<endSpanIndex){
  157. for(let i=startSpanIndex+1;i<endSpanIndex;i++){
  158. let span = spans.get(i), content = span.innerHTML;
  159. let cssText = getCssText(span.style.cssText, attr, value);
  160. cont += "<span style='"+ cssText +"'>" + content + "</span>";
  161. }
  162. }
  163. if(eleft!=""){
  164. let cssText = getCssText(endSpan.style.cssText, attr, value);
  165. cont += "<span style='"+ cssText +"'>" + eleft + "</span>";
  166. }
  167. if(eright!=""){
  168. cont += "<span style='"+ endSpan.style.cssText +"'>" + eright + "</span>";
  169. }
  170. for(let i=endSpanIndex+1;i<spans.length;i++){
  171. let span = spans.get(i), content = span.innerHTML;
  172. cont += "<span style='"+ span.style.cssText +"'>" + content + "</span>";
  173. }
  174. $textEditor.html(cont);
  175. // console.log(replaceSpans, cont);
  176. // replaceSpans.replaceWith(cont);
  177. let startSeletedNodeIndex, endSeletedNodeIndex;
  178. if(s1==s2){
  179. startSeletedNodeIndex = startSpanIndex;
  180. endSeletedNodeIndex = endSpanIndex;
  181. }
  182. else{
  183. startSeletedNodeIndex = startSpanIndex+1;
  184. endSeletedNodeIndex = endSpanIndex+1;
  185. }
  186. spans = $textEditor.find("span");
  187. selectTextContentCross(spans.get(startSeletedNodeIndex), spans.get(endSeletedNodeIndex));
  188. }
  189. }
  190. }
  191. else if($functionbox.length>0){
  192. }
  193. }
  194. export function enterKeyControll(cell){
  195. var w = window.getSelection();
  196. if(w.type=="None"){
  197. return
  198. }
  199. var range = w.getRangeAt(0);
  200. let cac = range.commonAncestorContainer;
  201. let $textEditor;
  202. if(cac.id=="luckysheet-rich-text-editor"){
  203. $textEditor = $(cac);
  204. }
  205. else{
  206. $textEditor = $(cac).closest("#luckysheet-rich-text-editor");
  207. }
  208. let $functionbox = $(cac).closest("#luckysheet-functionbox-cell");
  209. // if(range.collapsed===true){
  210. // return;
  211. // }
  212. let endContainer = range.endContainer, startContainer = range.startContainer;
  213. let endOffset = range.endOffset, startOffset = range.startOffset;
  214. if($textEditor.length>0){
  215. let startSpan = startContainer.parentNode;
  216. if(startContainer.id=="luckysheet-rich-text-editor"){
  217. startSpan = $(startContainer).find("span");
  218. if(startSpan.length==0){
  219. // 在末尾换行操作会导致数据丢失(覆盖)
  220. startContainer.innerHTML = `<span>${startContainer.innerText}</span>`;
  221. startSpan = $(startContainer).find("span");
  222. }
  223. startSpan = startSpan.get(startSpan.length-1);
  224. startOffset = startSpan.innerHTML.length;
  225. }
  226. // let startSpanIndex = $textEditor.find("span").index(startSpan);
  227. if(range.collapsed===false){
  228. range.deleteContents();
  229. }
  230. // 如果拷贝的内容为:pc&web ,那么innerHTML得到的值为:pc&amp;web ,执行换行操作存在问题
  231. // let startContent = startSpan.innerHTML;
  232. let startContent = startSpan.innerText;
  233. let sleft="" , sright="";
  234. let s1=0, s2=startOffset;
  235. sleft = startContent.substring(s1, s2);
  236. sright = startContent.substring(s2, startContent.length);
  237. let spanIndex,cont;
  238. if(startContainer.parentNode.tagName=="SPAN"){
  239. let textSpan = $textEditor.find("span");
  240. spanIndex = textSpan.index(startSpan);
  241. if((spanIndex==textSpan.length-1) && sright==""){
  242. let txt = textSpan[spanIndex].innerHTML;
  243. if(txt.substr(txt.length-1, 1)=="\n"){
  244. cont = "<span style='"+ startSpan.style.cssText +"'>" + sleft + "\n" + "</span>";
  245. }
  246. else{
  247. cont = "<span style='"+ startSpan.style.cssText +"'>" + sleft + "\n\n" + "</span>";
  248. }
  249. }
  250. else{
  251. cont = "<span style='"+ startSpan.style.cssText +"'>" + sleft + "\n" + sright + "</span>";
  252. }
  253. $(startSpan).replaceWith(cont);
  254. }
  255. else{
  256. let cssText = getFontStyleByCell(cell);
  257. if(sright==""){
  258. cont = "<span style='"+ cssText +"'>" + sleft + "\n\n" + "</span>";
  259. }
  260. else{
  261. cont = "<span style='"+ cssText +"'>" + sleft + "\n" + sright + "</span>";
  262. }
  263. if(startContainer.id=="luckysheet-rich-text-editor"){
  264. $(startSpan).replaceWith(cont);
  265. let textSpan = $textEditor.find("span");
  266. spanIndex = textSpan.length-1;
  267. startOffset = textSpan.get(spanIndex).innerHTML.length-1;
  268. }
  269. else{
  270. $(startSpan).html(cont);
  271. spanIndex = 0;
  272. }
  273. }
  274. selectTextContentCollapse($textEditor.find("span").get(spanIndex), startOffset+1);
  275. }
  276. else if($functionbox.length>0){
  277. }
  278. }
  279. export function updateInlineStringFormatOutside(cell, key, value){
  280. if(cell.ct==null){
  281. return;
  282. }
  283. let s = cell.ct.s;
  284. if(s==null){
  285. return;
  286. }
  287. for(let i=0;i<s.length;i++){
  288. let item = s[i];
  289. item[key] = value;
  290. }
  291. }
  292. export function convertSpanToShareString($dom){
  293. let styles = [], preStyleList, preStyleListString=null;
  294. for(let i=0;i<$dom.length;i++){
  295. let span = $dom.get(i);
  296. let styleList = convertCssToStyleList(span.style.cssText);
  297. let curStyleListString = JSON.stringify(styleList);
  298. // let v = span.innerHTML;
  299. let v = span.innerText;
  300. v = v.replace(/\n/g, "\r\n");
  301. if(curStyleListString==preStyleListString){
  302. preStyleList.v += v;
  303. }
  304. else{
  305. styleList.v = v;
  306. styles.push(styleList);
  307. preStyleListString = curStyleListString;
  308. preStyleList = styleList;
  309. }
  310. }
  311. return styles;
  312. }
  313. export function convertCssToStyleList(cssText){
  314. if(cssText==null || cssText.length==0){
  315. return {};
  316. }
  317. let cssTextArray = cssText.split(";");
  318. const _locale = locale();
  319. const locale_fontarray = _locale.fontarray;
  320. const locale_fontjson = _locale.fontjson;
  321. let styleList = {
  322. "ff":locale_fontarray[0], //font family
  323. "fc":"#000000",//font color
  324. "fs":10,//font size
  325. "cl":0,//strike
  326. "un":0,//underline
  327. "bl":0,//blod
  328. "it":0,//italic
  329. };
  330. cssTextArray.forEach(s => {
  331. s = s.toLowerCase();
  332. let key = textTrim(s.substr(0, s.indexOf(':')));
  333. let value = textTrim(s.substr(s.indexOf(':') + 1));
  334. if(key=="font-weight"){
  335. if(value=="bold"){
  336. styleList["bl"] = 1;
  337. }
  338. else{
  339. styleList["bl"] = 0;
  340. }
  341. }
  342. if(key=="font-style"){
  343. if(value=="italic"){
  344. styleList["it"] = 1;
  345. }
  346. else{
  347. styleList["it"] = 0;
  348. }
  349. }
  350. if(key=="font-family"){
  351. let ff = locale_fontjson[value];
  352. if(ff==null){
  353. styleList["ff"] = value;
  354. }
  355. else{
  356. styleList["ff"] = ff;
  357. }
  358. }
  359. if(key=="font-size"){
  360. styleList["fs"] = parseInt(value);
  361. }
  362. if(key=="color"){
  363. styleList["fc"] = value;
  364. }
  365. if(key=="text-decoration"){
  366. styleList["cl"] = 1;
  367. }
  368. if(key=="border-bottom"){
  369. styleList["un"] = 1;
  370. }
  371. if(key=="lucky-strike"){
  372. styleList["cl"] = value;
  373. }
  374. if(key=="lucky-underline"){
  375. styleList["un"] = value;
  376. }
  377. });
  378. return styleList;
  379. }
  380. const luckyToCssName = {
  381. "bl":"font-weight",
  382. "it":"font-style",
  383. "ff":"font-family",
  384. "fs":"font-size",
  385. "fc":"color",
  386. "cl":"text-decoration",
  387. "un":"border-bottom",
  388. }
  389. function getClassWithcss(cssText, ukey){
  390. let cssTextArray = cssText.split(";");
  391. if(ukey==null || ukey.length==0){
  392. return cssText;
  393. }
  394. if(cssText.indexOf(ukey)>-1){
  395. for(let i=0;i<cssTextArray.length;i++){
  396. let s = cssTextArray[i];
  397. s = s.toLowerCase();
  398. let key = textTrim(s.substr(0, s.indexOf(':')));
  399. let value = textTrim(s.substr(s.indexOf(':') + 1));
  400. if(key==ukey){
  401. return value;
  402. }
  403. }
  404. }
  405. return "";
  406. }
  407. function upsetClassWithCss(cssText, ukey, uvalue){
  408. let cssTextArray = cssText.split(";");
  409. let newCss = "";
  410. if(ukey==null || ukey.length==0){
  411. return cssText;
  412. }
  413. if(cssText.indexOf(ukey)>-1){
  414. for(let i=0;i<cssTextArray.length;i++){
  415. let s = cssTextArray[i];
  416. s = s.toLowerCase();
  417. let key = textTrim(s.substr(0, s.indexOf(':')));
  418. let value = textTrim(s.substr(s.indexOf(':') + 1));
  419. if(key==ukey){
  420. newCss += key + ":" + uvalue + ";";
  421. }
  422. else if(key.length>0){
  423. newCss += key + ":" + value + ";";
  424. }
  425. }
  426. }
  427. else if(ukey.length>0){
  428. cssText += ukey + ":" + uvalue + ";";
  429. newCss = cssText;
  430. }
  431. return newCss;
  432. }
  433. function removeClassWidthCss(cssText, ukey){
  434. let cssTextArray = cssText.split(";");
  435. let newCss = "";
  436. let oUkey = ukey;
  437. if(ukey==null || ukey.length==0){
  438. return cssText;
  439. }
  440. if(ukey in luckyToCssName){
  441. ukey = luckyToCssName[ukey];
  442. }
  443. if(cssText.indexOf(ukey)>-1){
  444. for(let i=0;i<cssTextArray.length;i++){
  445. let s = cssTextArray[i];
  446. s = s.toLowerCase();
  447. let key = textTrim(s.substr(0, s.indexOf(':')));
  448. let value = textTrim(s.substr(s.indexOf(':') + 1));
  449. if(key==ukey || (oUkey=="cl" && key=="lucky-strike") || (oUkey=="un" && key=="lucky-underline") ){
  450. continue;
  451. }
  452. else if(key.length>0){
  453. newCss += key + ":" + value + ";";
  454. }
  455. }
  456. }
  457. else{
  458. newCss = cssText;
  459. }
  460. return newCss;
  461. }
  462. function getCssText(cssText, attr, value){
  463. let styleObj = {};
  464. styleObj[attr] = value;
  465. if(attr=="un"){
  466. let fontColor = getClassWithcss(cssText,"color");
  467. if(fontColor==""){
  468. fontColor = "#000000";
  469. }
  470. let fs = getClassWithcss(cssText,"font-size");
  471. if(fs==""){
  472. fs = 11;
  473. }
  474. fs = parseInt(fs);
  475. styleObj["_fontSize"] = fs;
  476. styleObj["_color"] = fontColor;
  477. }
  478. let s = getFontStyleByCell(styleObj, undefined, undefined, false);
  479. let ukey = textTrim(s.substr(0, s.indexOf(':')));
  480. let uvalue = textTrim(s.substr(s.indexOf(':')+1));
  481. uvalue = uvalue.substr(0, uvalue.length-1);
  482. // let cssText = span.style.cssText;
  483. cssText = removeClassWidthCss(cssText, attr);
  484. cssText = upsetClassWithCss(cssText, ukey, uvalue);
  485. return cssText;
  486. }
  487. function extendCssText(origin, cover, isLimit=true){
  488. let originArray = origin.split(";");
  489. let coverArray = cover.split(";");
  490. let newCss = "";
  491. let addKeyList = {};
  492. for(let i=0;i<originArray.length;i++){
  493. let so = originArray[i], isAdd=true;
  494. so = so.toLowerCase();
  495. let okey = textTrim(so.substr(0, so.indexOf(':')));
  496. /* 不设置文字的大小,解决设置删除线等后字体变大的问题 */
  497. if(okey == "font-size"){
  498. continue;
  499. }
  500. let ovalue = textTrim(so.substr(so.indexOf(':') + 1));
  501. if(isLimit){
  502. if(!(okey in inlineStyleAffectCssName)){
  503. continue;
  504. }
  505. }
  506. for(let a=0;a<coverArray.length;a++){
  507. let sc = coverArray[a];
  508. sc = sc.toLowerCase();
  509. let ckey = textTrim(sc.substr(0, sc.indexOf(':')));
  510. let cvalue = textTrim(sc.substr(sc.indexOf(':') + 1));
  511. if(okey==ckey){
  512. newCss += ckey + ":" + cvalue + ";";
  513. isAdd = false;
  514. continue;
  515. }
  516. }
  517. if(isAdd){
  518. newCss += okey + ":" + ovalue + ";";
  519. }
  520. addKeyList[okey] = 1;
  521. }
  522. for(let a=0;a<coverArray.length;a++){
  523. let sc = coverArray[a];
  524. sc = sc.toLowerCase();
  525. let ckey = textTrim(sc.substr(0, sc.indexOf(':')));
  526. let cvalue = textTrim(sc.substr(sc.indexOf(':') + 1));
  527. if(isLimit){
  528. if(!(ckey in inlineStyleAffectCssName)){
  529. continue;
  530. }
  531. }
  532. if(!(ckey in addKeyList)){
  533. newCss += ckey + ":" + cvalue + ";";
  534. }
  535. }
  536. return newCss;
  537. }