1function JCLightHTMLEditor(arConfig) {this.Init(arConfig);} 2 3JCLightHTMLEditor.items = {}; 4 5JCLightHTMLEditor.prototype = { 6Init: function(arConfig) 7{ 8 this.id = arConfig.id; 9 JCLightHTMLEditor.items[this.id] = this; 10 11 var _this = this; 12 this.arConfig = arConfig; 13 this.bxTags = {}; 14 this.bFocused = false; 15 arConfig.timeoutCount = arConfig.timeoutCount || 0; 16 17 this.bPopup = false; 18 this.buttonsIndex = {}; 19 this.parseAlign = true; 20 this.parseTable = true; 21 this.lastCursorId = 'bxed-last-cursor'; 22 this.bHandleOnPaste = this.arConfig.bHandleOnPaste !== false; 23 24 this.arBBTags = ['p', 'u', 'div', 'table', 'tr', 'td', 'th', 'img', 'a', 'center', 'left', 'right', 'justify']; 25 this._turnOffCssCount = 0; 26 27 if (this.arConfig.arBBTags) 28 this.arBBTags = this.arBBTags.concat(this.arConfig.arBBTags); 29 30 this.arConfig.width = this.arConfig.width ? parseInt(this.arConfig.width) + (this.arConfig.width.indexOf('%') == -1 ? "px" : '%') : "100%"; 31 this.arConfig.height = this.arConfig.height ? parseInt(this.arConfig.height) + (this.arConfig.height.indexOf('%') == -1 ? "px" : '%') : "100%"; 32 this.SetConstants(); 33 this.sEditorMode = 'html'; 34 this.toolbarLineCount = 1; 35 36 console.log('arConfig', arConfig); 37 this.CACHE = {}; 38 this.arVideos = {}; 39 40 // Set content from config; 41 this.content = this.arConfig.content; 42 this.oSpecialParsers = {}; 43 BX.onCustomEvent(window, 'LHE_OnBeforeParsersInit', [this]); 44 45 this.oSpecialParsers.cursor = { 46 Parse: function(sName, sContent, pLEditor) 47 { 48 return sContent.replace(/#BXCURSOR#/ig, '<span id="' + pLEditor.lastCursorId + '"></span>'); 49 }, 50 UnParse: function(bxTag, pNode, pLEditor) 51 { 52 return '#BXCURSOR#'; 53 } 54 }; 55 56 if (arConfig.parsers) 57 { 58 for (var p in arConfig.parsers) 59 { 60 if (arConfig.parsers[p]) 61 this.oSpecialParsers[p] = arConfig.parsers[p]; 62 } 63 } 64 65 this.bDialogOpened = false; 66 67 // Sceleton 68 this.pFrame = BX('bxlhe_frame_' + this.id); 69 if (!this.pFrame) 70 { 71 if (arConfig.timeoutCount < 100) 72 { 73 setTimeout(function() 74 { 75 arConfig.timeoutCount++; 76 _this.Init(arConfig); 77 }, 1); 78 } 79 return; 80 } 81 82 this.pFrame.style.display = "block"; 83 84 this.pFrame.style.width = this.arConfig.width; 85 this.pFrame.style.height = this.arConfig.height; 86 87 this.pFrameTable = this.pFrame.firstChild; 88 this.pButtonsCell = this.pFrameTable.rows[0].cells[0]; 89 this.pButtonsCont = this.pButtonsCell.firstChild; 90 this.pEditCont = this.pFrameTable.rows[1].cells[0]; 91 92 if (this.arConfig.height.indexOf('%') == -1) 93 { 94 var h = parseInt(this.arConfig.height) - this.toolbarLineCount * 27; 95 if (h > 0) 96 this.pEditCont.style.height = h + 'px'; 97 } 98 99 // iFrame 100 this.CreateFrame(); 101 102 // Textarea 103 this.pSourceDiv = this.pEditCont.appendChild(BX.create("DIV", {props: {className: 'lha-source-div' }})); 104 this.pTextarea = this.pSourceDiv.appendChild(BX.create("TEXTAREA", {props: {className: 'lha-textarea', rows: 25, id: this.arConfig.inputId}})); 105 this.pHiddenInput = this.pFrame.appendChild(BX.create("INPUT", {props: {type: 'hidden', name: this.arConfig.inputName}})); 106 107 this.pTextarea.onfocus = function(){_this.bTextareaFocus = true;}; 108 this.pTextarea.onblur = function(){_this.bTextareaFocus = false;}; 109 110 this.pTextarea.style.fontFamily = this.arConfig.fontFamily; 111 this.pTextarea.style.fontSize = this.arConfig.fontSize; 112 this.pTextarea.style.fontSize = this.arConfig.lineHeight; 113 114 if (this.pHiddenInput.form) 115 { 116 BX.bind(this.pHiddenInput.form, 'submit', function(){ 117 try{ 118 _this.SaveContent(); 119 _this.pHiddenInput.value = _this.pTextarea.value = _this.pHiddenInput.value.replace(/#BXCURSOR#/ig, ''); 120 } 121 catch(e){} 122 }); 123 } 124 125 // Sort smiles 126 if (this.arConfig.arSmiles && this.arConfig.arSmiles.length > 0) 127 { 128 this.sortedSmiles = []; 129 var i, l, smile, j, k, arCodes; 130 for (i = 0, l = this.arConfig.arSmiles.length; i < l; i++) 131 { 132 smile = this.arConfig.arSmiles[i]; 133 if (!smile['codes'] || smile['codes'] == smile['code']) 134 { 135 this.sortedSmiles.push(smile); 136 } 137 else if(smile['codes'].length > 0) 138 { 139 arCodes = smile['codes'].split(' '); 140 for(j = 0, k = arCodes.length; j < k; j++) 141 this.sortedSmiles.push({name: smile.name, path: smile.path, code: arCodes[j]}); 142 } 143 } 144 145 //this.sortedSmiles = BX.clone(this.arConfig.arSmiles); 146 this.sortedSmiles = this.sortedSmiles.sort(function(a, b){return b.code.length - a.code.length;}); 147 } 148 149 if (!this.arConfig.bBBCode && this.arConfig.bConvertContentFromBBCodes
149) 150 this.arConfig.bBBCode = true; 151 152 this.bBBCode = this.arConfig.bBBCode; 153 if (this.bBBCode) 154 { 155 if (this.InitBBCode && typeof this.InitBBCode == 'function') 156 this.InitBBCode(); 157 } 158 159 this.bBBParseImageSize = this.arConfig.bBBParseImageSize; 160 161 if (this.arConfig.bResizable) 162 { 163 if (this.arConfig.bManualResize) 164 { 165 this.pResizer = BX('bxlhe_resize_' + this.id); 166 /*this.pResizer.style.width = this.arConfig.width;*/ 167 this.pResizer.title = BX.message.ResizerTitle; 168 169 if (!this.arConfig.minHeight || parseInt(this.arConfig.minHeight) <= 0) 170 this.arConfig.minHeight = 100; 171 if (!this.arConfig.maxHeight || parseInt(this.arConfig.maxHeight) <= 0) 172 this.arConfig.maxHeight = 2000; 173 174 this.pResizer.unselectable = "on"; 175 this.pResizer.ondragstart = function (e){return BX.PreventDefault(e);}; 176 this.pResizer.onmousedown = function(){_this.InitResizer(); return false;}; 177 } 178 179 if (this.arConfig.bAutoResize) 180 { 181 BX.bind(this.pTextarea, 'keydown', BX.proxy(this.AutoResize, this)); 182 BX.addCustomEvent(this, 'onShow', BX.proxy(this.AutoResize, this)); 183 } 184 } 185 186 // Add buttons 187 this.AddButtons(); 188 189 // Check if ALIGN tags allowed 190 this.parseAlign = !this.arConfig.bBBCode || !!(this.buttonsIndex['Justify'] || this.buttonsIndex['JustifyLeft']); 191 this.parseTable = !this.arConfig.bBBCode || !!this.buttonsIndex['Table']; 192 193 if (!this.parseAlign || !this.parseTable) 194 { 195 var arBBTags = []; 196 for (var k in this.arBBTags) 197 { 198 // Align tags 199 if (!this.parseAlign && ( 200 this.arBBTags[k] == 'center' || this.arBBTags[k] == 'left' || 201 this.arBBTags[k] == 'right' || this.arBBTags[k] == 'justify' 202 )) 203 continue; 204 205 // Table tags 206 if (!this.parseTable && ( 207 this.arBBTags[k] == 'table' || this.arBBTags[k] == 'tr' || 208 this.arBBTags[k] == 'td' || this.arBBTags[k] == 'th' 209 )) 210 continue; 211 212 arBBTags.push(this.arBBTags[k]); 213 } 214 this.arBBTags = arBBTags; 215 } 216 217 this.SetContent(this.content); 218 this.SetEditorContent(this.content); 219 this.oTransOverlay = new LHETransOverlay({}, this); 220 // TODO: Fix it 221 //this.oContextMenu = new LHEContextMenu({zIndex: 1000}, this); 222 223 BX.onCustomEvent(window, 'LHE_OnInit', [this, false]); 224 225 // Init events 226 BX.bind(this.pEditorDocument, 'click', BX.proxy(this.OnClick, this)); 227 BX.bind(this.pEditorDocument, 'mousedown', BX.proxy(this.OnMousedown, this)); 228 //BX.bind(this.pEditorDocument, 'contextmenu', BX.proxy(this.OnContextMenu, this)); 229 230 if (this.arConfig.bSaveOnBlur) 231 BX.bind(document, "mousedown", BX.proxy(this.OnDocMousedown, this)); 232 233 if (this.arConfig.ctrlEnterHandler && typeof window[this.arConfig.ctrlEnterHandler] == 'function') 234 this.ctrlEnterHandler = window[this.arConfig.ctrlEnterHandler]; 235 236 // Android < 4.x 237 if (BX.browser.IsAndroid() && /Android\s[1-3].[0-9]/i.test(navigator.userAgent)) 238 { 239 this.arConfig.bSetDefaultCodeView = true; 240 } 241 242 if (this.arConfig.bSetDefaultCodeView) 243 { 244 if (this.sourseBut) 245 this.sourseBut.oBut.handler(this.sourseBut); 246 else 247 this.SetView('code'); 248 } 249 250 BX.ready(function(){ 251 if (_this.pFrame.offsetWidth == 0 && _this.pFrame.offsetWidth == 0) 252 { 253 _this.onShowInterval = setInterval(function(){ 254 if (_this.pFrame.offsetWidth != 0 && _this.pFrame.offsetWidth != 0) 255 { 256 BX.onCustomEvent(_this, 'onShow'); 257 clearInterval(_this.onShowInterval); 258 } 259 }, 500); 260 } 261 else 262 { 263 BX.onCustomEvent(_this, 'onShow'); 264 } 265 }); 266 267 this.adjustBodyInterval = 1000; 268 this._AdjustBodyWidth(); 269 BX.removeClass(this.pButtonsCont, "lhe-stat-toolbar-cont-preload"); /**/ 270}, 271 272CreateFrame: function() 273{ 274 if (this.iFrame && this.iFrame.parentNode) 275 { 276 this.pEditCont.removeChild(this.iFrame); 277 this.iFrame = null; 278 } 279 280 this.iFrame = this.pEditCont.appendChild(BX.create("IFRAME", {props: { id: 'LHE_iframe_' + this.id, className: 'lha-iframe', src: "javascript:void(0)", frameborder: 0}})); 281 282 if (this.iFrame.contentDocument && !BX.browser.IsIE()) 283 this.pEditorDocument = this.iFrame.contentDocument; 284 else 285 this.pEditorDocument = this.iFrame.contentWindow.document; 286 this.pEditorWindow = this.iFrame.contentWindow; 287}, 288 289ReInit: function(content) 290{ 291 if (typeof content == 'undefined') 292 content = ''; 293 this.SetContent(content); 294 this.CreateFrame(); 295 this.SetEditorContent(this.content); 296 this.SetFocus(); 297 298 BX.onCustomEvent(window, 'LHE_OnInit', [this, true]); 299}, 300 301SetConstants: function() 302{
303 //this.reBlockElements = /^(BR|TITLE|TABLE|SCRIPT|TR|TBODY|P|DIV|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI)$/i; 304 this.reBlockElements = /^(TITLE|TABLE|SCRIPT|TR|TBODY|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI)$/i; 305 this.oneGif = this.arConfig.oneGif; 306 this.imagePath = this.arConfig.imagePath; 307 308 if (!this.arConfig.fontFamily) 309 { 310 const editorContainer = BX('bxlhe_frame_' + this.id); 311 const styleContainer = editorContainer ? editorContainer : document.body; 312 const primaryFont = BX.Dom.style(styleContainer, '--ui-font-family-primary'); 313 const fallbackFont = BX.Dom.style(styleContainer, '--ui-font-family-helvetica'); 314 315 const currentFont = BX.Type.isStringFilled(primaryFont) ? primaryFont : fallbackFont; 316 if (BX.Type.isStringFilled(currentFont)) 317 { 318 this.arConfig.fontFamily = currentFont; 319 } 320 } 321 322 if (!this.arConfig.fontSize) 323 this.arConfig.fontSize = '14px'; 324 if (!this.arConfig.lineHeight) 325 this.arConfig.lineHeight = '16px'; 326 327 this.arColors = [ 328 '#FF0000', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF', '#FF00FF', '#FFFFFF', '#EBEBEB', '#E1E1E1', '#D7D7D7', '#CCCCCC', '#C2C2C2', '#B7B7B7', '#ACACAC', '#A0A0A0', '#959595', 329 '#EE1D24', '#FFF100', '#00A650', '#00AEEF', '#2F3192', '#ED008C', '#898989', '#7D7D7D', '#707070', '#626262', '#555', '#464646', '#363636', '#262626', '#111', '#000000', 330 '#F7977A', '#FBAD82', '#FDC68C', '#FFF799', '#C6DF9C', '#A4D49D', '#81CA9D', '#7BCDC9', '#6CCFF7', '#7CA6D8', '#8293CA', '#8881BE', '#A286BD', '#BC8CBF', '#F49BC1', '#F5999D', 331 '#F16C4D', '#F68E54', '#FBAF5A', '#FFF467', '#ACD372', '#7DC473', '#39B778', '#16BCB4', '#00BFF3', '#438CCB', '#5573B7', '#5E5CA7', '#855FA8', '#A763A9', '#EF6EA8', '#F16D7E', 332 '#EE1D24', '#F16522', '#F7941D', '#FFF100', '#8FC63D', '#37B44A', '#00A650', '#00A99E', '#00AEEF', '#0072BC', '#0054A5', '#2F3192', '#652C91', '#91278F', '#ED008C', '#EE105A', 333 '#9D0A0F', '#A1410D', '#A36209', '#ABA000', '#588528', '#197B30', '#007236', '#00736A', '#0076A4', '#004A80', '#003370', '#1D1363', '#450E61', '#62055F', '#9E005C', '#9D0039', 334 '#790000', '#7B3000', '#7C4900', '#827A00', '#3E6617', '#045F20', '#005824', '#005951', '#005B7E', '#003562', '#002056', '#0C004B', '#30004A', '#4B0048', '#7A0045', '#7A0026' 335 ]; 336 337 this.systemCSS = "img.bxed-anchor{background-image: url(" + this.imagePath + "lhe_iconkit.gif)!important; background-position: -260px 0!important; height: 20px!important; width: 20px!important;}\n" + 338 "body{font-family:" + this.arConfig.fontFamily + "; font-size: " + this.arConfig.fontSize + "; line-height:" + this.arConfig.lineHeight + "}\n" + 339 "p{padding:0!important; margin: 0!important;}\n" + 340 "span.bxed-noscript{color: #0000a0!important; padding: 2px!important; font-style:italic!important; font-size: 90%!important;}\n" + 341 "span.bxed-noindex{color: #004000!important; padding: 2px!important; font-style:italic!important; font-size: 90%!important;}\n" + 342 "img.bxed-flash{border: 1px solid #B6B6B8!important; background: url(" + this.imagePath + "flash.gif) #E2DFDA center center no-repeat !important;}\n" + 343 "table{border: 1px solid #B6B6B8!important; border-collapse: collapse;}\n" + 344 "table td{border: 1px solid #B6B6B8!important; padding: 2px 5px;}\n" + 345 "img.bxed-video{border: 1px solid #B6B6B8!important; background-color: #E2DFDA!important; background-image: url(" + this.imagePath + "video.gif); background-position: center center!important; background-repeat:no-repeat!important;}\n" + 346 "img.bxed-hr{padding: 2px!important; width: 100%!important; height: 2px!important;}\n"; 347 348 if (this.arConfig.documentCSS) 349 this.systemCSS += "\n" + this.arConfig.documentCSS; 350 351 this.tabNbsp = " "; // x 6 352 this.tabNbspRe1 = new RegExp(String.fromCharCode(160) + String.fromCharCode(160) + String.fromCharCode(160) + String.fromCharCode(160) + String.fromCharCode(160) + String.fromCharCode(160), 'ig'); // 353 this.tabNbspRe2 = new RegExp(String.fromCharCode(160) + String.fromCharCode(160) + String.fromCharCode(160) + String.fromCharCode(160) + String.fromCharCode(160) + ' ', 'ig'); // 354}, 355 356OnMousedown: function(e) 357{ 358 if (!e) 359 e = window.event; 360 this.bFocused = true; 361}, 362 363OnClick: function(e) 364{ 365 this.bFocused = true; 366 this.CheckBr(); 367}, 368 369OnDblClick: function(e) 370{ 371 return; 372}, 373 374OnContextMenu: function(e, pElement) 375{ 376 return; 377 var 378 _this = this, 379 oFramePos, 380 x, y; 381 if (!e) e = this.pEditorWindow.event; 382
383 if(e.pageX || e.pageY) 384 { 385 x = e.pageX - this.pEditorDocument.body.scrollLeft; 386 y = e.pageY - this.pEditorDocument.body.scrollTop; 387 } 388 else if(e.clientX || e.clientY) 389 { 390 x = e.clientX; 391 y = e.clientY; 392 } 393 394 oFramePos = this.CACHE['frame_pos']; 395 if (!oFramePos) 396 this.CACHE['frame_pos'] = oFramePos = BX.pos(this.pEditCont); 397 398 x += oFramePos.left; 399 y += oFramePos.top; 400 401 var targ; 402 if (e.target) 403 targ = e.target; 404 else if (e.srcElement) 405 targ = e.srcElement; 406 if (targ.nodeType == 3) // defeat Safari bug 407 targ = targ.parentNode; 408 409 if (!targ || !targ.nodeName) 410 return; 411 var res = this.oContextMenu.Show({oPos: {left : x, top : y}, pElement: targ}); 412 413 return BX.PreventDefault(e); 414}, 415 416OnKeyDown: function(e) 417{ 418 if(!e) 419 e = window.event; 420 BX.onCustomEvent(this, 'OnDocumentKeyDown', [e]); 421 422 var key = e.which || e.keyCode; 423 if (e.ctrlKey && !e.shiftKey && !e.altKey) 424 { 425 // if (!BX.browser.IsIE() && !BX.browser.IsOpera()) 426 // { 427 switch (key) 428 { 429 case 66 : // B 430 case 98 : // b 431 this.executeCommand('Bold'); 432 return BX.PreventDefault(e); 433 case 105 : // i 434 case 73 : // I 435 this.executeCommand('Italic'); 436 return BX.PreventDefault(e); 437 case 117 : // u 438 case 85 : // U 439 this.executeCommand('Underline'); 440 return BX.PreventDefault(e); 441 case 81 : // Q - quote 442 if (this.quoteBut) 443 { 444 this.quoteBut.oBut.handler(this.quoteBut); 445 return BX.PreventDefault(e); 446 } 447 } 448 //} 449 } 450 451 if (this.bHandleOnPaste 452 && 453 ( 454 (e.ctrlKey && !e.shiftKey && !e.altKey && e.keyCode == 86) /* Ctrl+V */ 455 || 456 (!e.ctrlKey && e.shiftKey && !e.altKey && e.keyCode == 45) /*Shift+Ins*/ 457 || 458 (e.metaKey && !e.shiftKey && !e.altKey && e.keyCode == 86) /* Cmd+V */ 459 ) 460 ) 461 { 462 this.OnPaste(); 463 } 464 465 // Shift +Del - Deleting code fragment in WYSIWYG 466 if (this.bCodeBut && e.shiftKey && e.keyCode == 46 /* Del*/) 467 { 468 var pSel = this.GetSelectionObject(); 469 if (pSel) 470 { 471 if (pSel.className == 'lhe-code') 472 { 473 pSel.parentNode.removeChild(pSel); 474 return BX.PreventDefault(e); 475 } 476 else if(pSel.parentNode) 477 { 478 var pCode = BX.findParent(pSel, {className: 'lhe-code'}); 479 if (pCode) 480 { 481 pCode.parentNode.removeChild(pCode); 482 return BX.PreventDefault(e); 483 } 484 } 485 } 486 } 487 488 // Tab 489 if (key == 9 && this.arConfig.bReplaceTabToNbsp) 490 { 491 this.InsertHTML(this.tabNbsp); 492 return BX.PreventDefault(e); 493 } 494 495 if (this.bCodeBut && e.keyCode == 13) 496 { 497 if (BX.browser.IsIE() || BX.browser.IsSafari() || BX.browser.IsChrome()) 498 { 499 var pElement = this.GetSelectionObject(); 500 if (pElement) 501 { 502 var bFind = false; 503 if (pElement && pElement.nodeName && pElement.nodeName.toLowerCase() == 'pre') 504 bFind = true; 505 506 if (!bFind) 507 bFind = !!BX.findParent(pElement, {tagName: 'pre'}); 508 509 if (bFind) 510 { 511 if (BX.browser.IsIE()) 512 this.InsertHTML("<br/><img src=\"" + this.oneGif + "\" height=\"20\" width=\"1\"/>"); 513 else if (BX.browser.IsSafari() || BX.browser.IsChrome()) 514 this.InsertHTML(" \r\n"); 515 516 return BX.PreventDefault(e); 517 } 518 } 519 } 520 } 521 522 // Ctrl + Enter 523 if ((e.keyCode == 13 || e.keyCode == 10) && e.ctrlKey && this.ctrlEnterHandler) 524 { 525 this.SaveContent(); 526 this.ctrlEnterHandler(); 527 } 528 529 if (this.arConfig.bAutoResize && this.arConfig.bResizable) 530 { 531 if (this._resizeTimeout) 532 { 533 clearTimeout(this._resizeTimeout); 534 this._resizeTimeout = null; 535 } 536 537 this._resizeTimeout = setTimeout(BX.proxy(this.AutoResize, this), 200); 538 } 539 540 if (this._CheckBrTimeout) 541 { 542 clearTimeout(this._CheckBrTimeout); 543 this._CheckBrTimeout = null; 544 } 545 546 this._CheckBrTimeout = setTimeout(BX.proxy(this.CheckBr, this), 1000); 547}, 548 549OnDocMousedown: function(e) 550{ 551 if (this.bFocused) 552 { 553 if (!e) 554 e = window.event; 555 556 var pEl; 557 if (e.target) 558 pEl = e.target; 559 else if (e.srcElement) 560 pEl = e.srcElement; 561 if (pEl.nodeType == 3) 562 pEl = pEl.parentNode; 563 564 if (!this.bPopup && !BX.findParent(pEl, {className: 'bxlhe-frame'})) 565 { 566 this.SaveContent(); 567 this.bFocused = false; 568 } 569 } 570}, 571 572SetView: function(sType) 573{ 574 if (this.sEditorMode == sType) 575 return; 576 577 this.SaveContent(); 578 if (sType == 'code') 579 { 580 this.iFrame.style.display = "none"; 581 this.pSourceDiv.style.display = "block"; 582 this.SetCodeEditorContent(this.GetContent()); 583 } 584 else 585 { 586 this.iFrame.style.display = "block"; 587 this.pSourceDiv.style.display = "none"; 588 this.SetEditorContent(this.GetContent()); 589 this.CheckBr(); 590 } 591 this.sEditorMode = sType; 592 BX.onCustomEvent(this, "OnChangeView"); 593}, 594 595SaveContent: function() 596{ 597 var sContent = this.sEditorMode == 'code' ? this.GetCodeEditorContent() : this.GetEditorContent(); 598 if (this.bBBCode) 599 sContent = this.OptimizeBB(sContent); 600 601 this.SetContent(sContent); 602 603 BX.onCustomEvent(this, 'OnSaveContent', [sContent]); 604}, 605 606SetContent: function(sContent) 607{ 608 this.pHiddenInput.value = this.pTextarea.value = this.content = sContent; 609}, 610 611GetContent: function() 612{ 613 return this.content.toString(); 614}, 615 616SetEditorContent: function(sContent) 617{ 618 if (this.pEditorDocument) 619 { 620 sContent = this.ParseContent(sContent); 621 622 if (this.pEditorDocument.designMode) 623 { 624 try{ 625 this.pEditorDocument.designMode = 'off'; 626 }catch(e){alert('SetEditorContent: designMode=\'off\'');} 627 } 628 629 this.pEditorDocument.open();
630 this.pEditorDocument.write('<html><head></head><body>' + sContent + '</body></html>'); 631 this.pEditorDocument.close(); 632 633 this.pEditorDocument.body.style.padding = "8px"; 634 this.pEditorDocument.body.style.margin = "0"; 635 this.pEditorDocument.body.style.borderWidth = "0"; 636 637 this.pEditorDocument.body.style.fontFamily = this.arConfig.fontFamily; 638 this.pEditorDocument.body.style.fontSize = this.arConfig.fontSize; 639 this.pEditorDocument.body.style.lineHeight = this.arConfig.lineHeight; 640 641 // Set events 642 BX.bind(this.pEditorDocument, 'keydown', BX.proxy(this.OnKeyDown, this)); 643 644 if(BX.browser.IsIE()) 645 { 646 if (this.bHandleOnPaste) 647 BX.bind(this.pEditorDocument.body, 'paste', BX.proxy(this.OnPaste, this)); 648 this.pEditorDocument.body.contentEditable = true; 649 } 650 else if (this.pEditorDocument.designMode) 651 { 652 this.pEditorDocument.designMode = "on"; 653 this._TurnOffStyleWithCSS(true); 654 } 655 656 if (this.arConfig.bConvertContentFromBBCodes) 657 this.ShutdownBBCode(); 658 } 659}, 660 661_TurnOffStyleWithCSS: function(bTimeout) 662{ 663 try{ 664 this._turnOffCssCount++; 665 if (this._turnOffCssCount < 5 && bTimeout !== false) 666 bTimeout = true; 667 668 this.pEditorDocument.execCommand("styleWithCSS", false, false); 669 try{this.pEditorDocument.execCommand("useCSS", false, true);}catch(e){} 670 } 671 catch(e) 672 { 673 if (bTimeout === true) 674 setTimeout(BX.proxy(this._TurnOffStyleWithCSS, this), 500); 675 } 676}, 677 678_AdjustBodyWidth: function() 679{ 680 if (!BX.browser.IsChrome()) 681 { 682 if (this.pEditorDocument && this.pEditorDocument.body) 683 { 684 var html = this.pEditorDocument.body.innerHTML; 685 if (html != this.lastEditedBodyHtml) 686 { 687 this.adjustBodyInterval = 500; 688 var _this = this; 689 this.pEditorDocument.body.style.width = null; 690 this.lastEditedBodyHtml = html; 691 setTimeout(function(){ 692 var scrollWidth = BX.GetWindowScrollSize(_this.pEditorDocument).scrollWidth - 16; 693 if (scrollWidth > 0) 694 _this.pEditorDocument.body.style.width = scrollWidth + 'px'; 695 }, 50); 696 } 697 else 698 { 699 this.adjustBodyInterval = 5000; 700 } 701 } 702 703 setTimeout(BX.proxy(this._AdjustBodyWidth, this), this.adjustBodyInterval) 704 } 705}, 706 707GetEditorContent: function() 708{ 709 var sContent = this.UnParseContent(); 710 return sContent; 711}, 712 713SetCodeEditorContent: function(sContent) 714{ 715 this.pHiddenInput.value = this.pTextarea.value = sContent; 716}, 717 718GetCodeEditorContent: function() 719{ 720 return this.pTextarea.value; 721}, 722 723OptimizeHTML: function(str) 724{ 725 var 726 iter = 0, 727 bReplasing = true, 728 arTags = ['b', 'em', 'font', 'h\\d', 'i', 'li', 'ol', 'p', 'small', 'span', 'strong', 'u', 'ul'], 729 replaceEmptyTags = function(){i--; bReplasing = true; return ' ';}, 730 re, tagName, i, l; 731 732 while(iter++ < 20 && bReplasing) 733 { 734 bReplasing = false; 735 for (i = 0, l = arTags.length; i < l; i++) 736 { 737 tagName = arTags[i]; 738 re = new RegExp('<'+tagName+'[^>]*?>\\s*?</'+tagName+'>', 'ig'); 739 str = str.replace(re, replaceEmptyTags); 740 741 re = new RegExp('<' + tagName + '\\s+?[^>]*?/>', 'ig'); 742 str = str.replace(re, replaceEmptyTags); 743 744 // Replace <b>text1</b> <b>text2</b> ===>> <b>text1 text2</b> 745 re = new RegExp('<((' + tagName + '+?)(?:\\s+?[^>]*?)?)>([\\s\\S]+?)<\\/\\2>\\s*?<\\1>([\\s\\S]+?)<\\/\\2>', 'ig'); 746 str = str.replace(re, function(str, b1, b2, b3, b4) 747 { 748 bReplasing = true; 749 return '<' + b1 + '>' + b3 + ' ' + b4 + '</' + b2 + '>'; 750 } 751 ); 752 } 753 } 754 return str; 755}, 756 757_RecursiveDomWalker: function(pNode, pParentNode) 758{ 759 var oNode = 760 { 761 arAttributes : {}, 762 arNodes : [], 763 type : null, 764 text : "", 765 arStyle : {} 766 }; 767 768 switch(pNode.nodeType) 769 { 770 case 9: 771 oNode.type = 'document'; 772 break; 773 case 1: 774 if(pNode.tagName.length <= 0 || pNode.tagName.substring(0, 1) == "/") 775 return; 776 777 oNode.text = pNode.tagName.toLowerCase(); 778 if (oNode.text == 'script') 779 break; 780 781 oNode.type = 'element'; 782 var 783 attr = pNode.attributes, 784 j, l = attr.length; 785 786 if (pNode.nodeName.toLowerCase() == 'a' && pNode.innerHTML == '' && (this.bBBCode || !pNode.getAttribute("name"))) 787 return; 788 789 for(j = 0; j < l; j++) 790 { 791 if(attr[j].specified || (oNode.text == "input" && attr[j].nodeName.toLowerCase()=="value")) 792 { 793 var attrName = attr[j].nodeName.toLowerCase(); 794 795 if(attrName == "style") 796 { 797 oNode.arAttributes[attrName] = pNode.style.cssText; 798 oNode.arStyle = pNode.style; 799 800 if(oNode.arStyle.display == 'none') 801 { 802 oNode.type = 'text'; 803 oNode.text = ''; 804 break; 805 } 806 807 if(oNode.arStyle.textAlign && (oNode.text == 'div' || oNode.text == 'p' || oNode.text == 'span')) 808 { 809 var align = oNode.arStyle.textAlign; 810 BX.util.in_array(oNode.arStyle.textAlign, ['left', 'right', 'center', 'justify']) 811 { 812 oNode.arStyle = {}; 813 oNode.text = 'span'; 814 oNode.arAttributes['style'] = 'text-align:' + align + ';display:block;'; 815 oNode.arStyle.textAlign = align; 816 oNode.arStyle.display = 'block'; 817 } 818 } 819 } 820 else if(attrName=="src" || attrName=="href" || attrName=="width" || attrName=="height") 821 { 822 oNode.arAttributes[attrName] = pNode.getAttribute(attrName, 2); 823 } 824 else if(!this.bBBCode && attrName == 'align' && BX.util.in_array(attr[j].nodeValue, ['left', 'right', 'center', 'justify'])) 825 { 826 oNode.text = 'span'; 827 oNode.arAttributes['style'] = 'text-align:' + attr[j].nodeValue + ';display:block;'; 828 oNode.arStyle.textAlign = attr[j].nodeValue; 829 oNode.arStyle.display = 'block'; 830 } 831 else 832 { 833 oNode.arAttributes[attrName] = attr[j].nodeValue; 834 } 835 } 836 } 837 break; 838 case 3: 839 oNode.type = 'text'; 840 var res = pNode.nodeValue; 841 842 if (this.arConfig.bReplaceTabToNbsp) 843 { 844 res = res.replace(this.tabNbspRe1, "\t"); 845 res = res.replace(this.tabNbspRe2, "\t"); 846 } 847 848 if(!pParentNode || (pParentNode.text != 'pre' && pParentNode.arAttributes['class'] != 'lhe-code')) 849 { 850 res = res.replace(/\n+/g, ' '); 851 res = res.replace(/ +/g, ' '); 852 } 853 854 oNode.text = res; 855 break; 856 } 857 858 if (oNode.type != 'text') 859 { 860 var 861 arChilds = pNode.childNodes, 862 i, l = arChilds.length; 863 864 for(i = 0; i < l; i++) 865 oNode.arNodes.push(this._RecursiveDomWalker(arChilds[i], oNode)); 866 } 867 868 return oNode; 869}, 870 871_RecursiveGetHTML: function(pNode) 872{ 873 if (!pNode || typeof pNode != 'object' || !pNode.arAttributes) 874 return ""; 875 876 var ob, res = "", id = pNode.arAttributes["id"]; 877 878 if (pNode.text == 'img' && !id) // Images pasted by Ctrl+V 879 id = this.SetBxTag(false, {tag: 'img', params: {src: pNode.arAttributes["src"]}}); 880 881 if (id) 882 { 883 var bxTag = this.GetBxTag(id); 884 if(bxTag.tag) 885 { 886 var parser = this.oSpecialParsers[bxTag.tag]; 887 if (parser && parser.UnParse) 888 return parser.UnParse(bxTag, pNode, this); 889 else if (bxTag.params && bxTag.params.value) 890 return '\n' + bxTag.params.value + '\n'; 891 else 892 return ''; 893 } 894 } 895 896 if (pNode.arAttributes["_moz_editor_bogus_node"]) 897 return ''; 898 899 if (this.bBBCode) 900 { 901 var bbRes = this.UnParseNodeBB(pNode); 902 if (bbRes !== false) 903 return bbRes; 904 } 905 906 bFormatted = true; 907 908 if (pNode.text.toLowerCase() != 'body') 909 res = this.GetNodeHTMLLeft(pNode); 910 911 var bNewLine = false;
912 913 var sIndent = ''; 914 if (typeof pNode.bFormatted != 'undefined') 915 bFormatted = !!pNode.bFormatted; 916 917 if (bFormatted && pNode.type != 'text') 918 { 919 if (this.reBlockElements.test(pNode.text) && !(pNode.oParent && pNode.oParent.text && pNode.oParent.text.toLowerCase() == 'pre')) 920 { 921 for (var j = 0; j < pNode.iLevel - 3; j++) 922 sIndent += " "; 923 bNewLine = true; 924 res = "\r\n" + sIndent + res; 925 } 926 } 927 928 for (var i = 0; i < pNode.arNodes.length; i++) 929 res += this._RecursiveGetHTML(pNode.arNodes[i]); 930 931 if (pNode.text.toLowerCase() != 'body') 932 res += this.GetNodeHTMLRight(pNode); 933 934 if (bNewLine) 935 res += "\r\n" + (sIndent == '' ? '' : sIndent.substr(2)); 936 937 return res; 938}, 939 940// Redeclared in BBCode mode 941GetNodeHTMLLeft: function(pNode) 942{ 943 if(pNode.type == 'text') 944 return BX.util.htmlspecialchars(pNode.text); 945 946 var atrVal, attrName, res; 947 948 if(pNode.type == 'element') 949 { 950 res = "<" + pNode.text; 951 952 for(attrName in pNode.arAttributes) 953 { 954 atrVal = pNode.arAttributes[attrName]; 955 if(attrName.substring(0,4).toLowerCase() == '_moz') 956 continue; 957 958 if(pNode.text.toUpperCase()=='BR' && attrName.toLowerCase() == 'type' && atrVal == '_moz') 959 continue; 960 961 if(attrName == 'style') 962 { 963 if (atrVal.length > 0 && atrVal.indexOf('-moz') != -1) // Kill -moz* styles from firefox 964 atrVal = BX.util.trim(atrVal.replace(/-moz.*?;/ig, '')); 965 966 if (pNode.text == 'td') // Kill border-image: none; styles from firefox for <td> 967 atrVal = BX.util.trim(atrVal.replace(/border-image:\s*none;/ig, '')); 968 969 if(atrVal.length <= 0) 970 continue; 971 } 972 973 res += ' ' + attrName + '="' + (pNode.bDontUseSpecialchars ? atrVal : BX.util.htmlspecialchars(atrVal)) + '"'; 974 } 975 976 if(pNode.arNodes.length <= 0 && !this.IsPairNode(pNode.text)) 977 return res + " />"; 978 return res + ">"; 979 } 980 return ""; 981}, 982 983// Redeclared in BBCode mode 984GetNodeHTMLRight: function(pNode) 985{ 986 if(pNode.type == 'element' && (pNode.arNodes.length>0 || this.IsPairNode(pNode.text))) 987 return "</" + pNode.text + ">"; 988 return ""; 989}, 990 991IsPairNode: function(text) 992{ 993 if(text.substr(0, 1) == 'h' || text == 'br' || text == 'img' || text == 'input') 994 return false; 995 return true; 996}, 997 998executeCommand: function(commandName, sValue) 999{ 1000 this.SetFocus(); 1001 //try{ 1002 var res = this.pEditorWindow.document.execCommand(commandName, false, sValue); 1003 //}catch(e){}; 1004 this.SetFocus(); 1005 //this.OnEvent("OnSelectionChange"); 1006 //this.OnChange("executeCommand", commandName); 1007 1008 if (this.arConfig.bAutoResize && this.arConfig.bResizable) 1009 this.AutoResize(); 1010 1011 return res; 1012}, 1013 1014queryCommand: function(commandName) 1015{ 1016 var sValue = ''; 1017 if (!this.pEditorDocument.queryCommandEnabled || !this.pEditorDocument.queryCommandValue) 1018 return null; 1019 1020 if(!this.pEditorDocument.queryCommandEnabled(commandName)) 1021 return null; 1022 1023 return this.pEditorDocument.queryCommandValue(commandName); 1024}, 1025 1026SetFocus: function() 1027{ 1028 if (this.sEditorMode != 'html') 1029 return; 1030 1031 BX.focus(this.pEditorWindow.focus ? this.pEditorWindow : this.pEditorDocument.body); 1032 this.bFocused = true; 1033}, 1034 1035SetFocusToEnd: function() 1036{ 1037 this.CheckBr(); 1038 var ss = BX.GetWindowScrollSize(this.pEditorDocument); 1039 this.pEditorWindow.scrollTo(0, ss.scrollHeight); 1040 1041 this.SetFocus(); 1042 this.SelectElement(this.pEditorDocument.body.lastChild); 1043}, 1044 1045SetCursorFF: function() 1046{ 1047 if (this.sEditorMode != 'code' && !BX.browser.IsIE()) 1048 { 1049 var _this = this; 1050 try{ 1051 this.iFrame.blur(); 1052 this.iFrame.focus(); 1053 1054 setTimeout(function(){ 1055 _this.iFrame.blur(); 1056 _this.iFrame.focus(); 1057 }, 600); 1058 1059 setTimeout(function(){ 1060 _this.iFrame.blur(); 1061 _this.iFrame.focus(); 1062 }, 1000); 1063 }catch(e){} 1064 } 1065}, 1066 1067CheckBr: function() 1068{ 1069 if (this.CheckBrTimeout) 1070 { 1071 clearTimeout(this.CheckBrTimeout); 1072 this.CheckBrTimeout = false; 1073 } 1074 1075 var _this = this; 1076 this.CheckBrTimeout = setTimeout(function() 1077 { 1078 var lastChild = _this.pEditorDocument.body.lastChild; 1079 if (lastChild && lastChild.nodeType == 1) 1080 { 1081 var nn = lastChild.nodeName.toUpperCase(); 1082 var reBlockElements = /^(TITLE|TABLE|SCRIPT|DIV|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI|BLOCKQUOTE|FORM|CENTER|)$/i; 1083 if (reBlockElements.test(nn)) 1084 _this.pEditorDocument.body.appendChild(_this.pEditorDocument.createElement("BR")); 1085 } 1086 }, 200); 1087}, 1088 1089ParseContent: function(sContent, bJustParse) // HTML -> WYSIWYG 1090{ 1091 var _this = this; 1092 var arCodes = []; 1093 sContent = sContent.replace(/\[code\]((?:\s|\S)*?)\[\/code\]/ig, function(str, code) 1094 { 1095 var strId = ''; 1096 if (!_this.bBBCode) 1097 strId = " id=\"" + _this.SetBxTag(false, {tag: "code"}) + "\" "; 1098 1099 arCodes.push('<pre ' + strId + 'class="lhe-code" title="' + BX.message.CodeDel + '">' + BX.util.htmlspecialchars(code) + '</pre>'); 1100 return '#BX_CODE' + (arCodes.length - 1) + '#'; 1101 }); 1102 1103 if (!bJustParse) 1104 BX.onCustomEvent(this, 'OnParseContent'); 1105 1106 if (this.arConfig.bBBCode) 1107 sContent = this.ParseBB(sContent); 1108 1109 sContent = sContent.replace(/(<td[^>]*>)\s*(<\/td>)/ig, "$1<br _moz_editor_bogus_node=\"on\">$2"); 1110 1111 if (this.arConfig.bReplaceTabToNbsp) 1112 sContent = sContent.replace(/\t/ig, this.tabNbsp); 1113 1114 if (!BX.browser.IsIE()) 1115 { 1116 sContent = sContent.replace(/<hr[^>]*>/ig, function(sContent) 1117 { 1118 return '<img class="bxed-hr" src="' + _this.imagePath + 'break_page.gif" id="' + _this.SetBxTag(false, {tag: "hr", params: {value : sContent}}) + '"/>'; 1119 } 1120 ); 1121 } 1122 1123 for (var p in this.oSpecialParsers) 1124 { 1125 if (this.oSpecialParsers[p] && this.oSpecialParsers[p].Parse) 1126 sContent = this.oSpecialParsers[p].Parse(p, sContent, this); 1127 } 1128 1129 if (!bJustParse) 1130 setTimeout(function(){
1131 _this.AppendCSS(_this.systemCSS); 1132 // Hack for chrome: we have to unset font family 1133 // because than user paste text - chrome wraps it with [FONT=..... 1134 setTimeout(function(){ 1135 _this.pEditorDocument.body.style.fontFamily = ''; 1136 _this.pEditorDocument.body.style.fontSize = ''; 1137 }, 1); 1138 }, 300); 1139 1140 if (arCodes.length > 0) // Replace back CODE content without modifications 1141 sContent = sContent.replace(/#BX_CODE(\d+)#/ig, function(s, num){return arCodes[num] || s;}); 1142 1143 if (this.bBBCode) 1144 { 1145 sContent = sContent.replace(/&#91;/ig, "["); 1146 sContent = sContent.replace(/&#93;/ig, "]"); 1147 } 1148 1149 sContent = BX.util.trim(sContent); 1150 1151 // Add <br> in the end of the message if text not ends with <br> 1152 if (this.arConfig.bBBCode && !sContent.match(/(<br[^>]*>)$/ig)) 1153 sContent += '<br/>'; 1154 1155 return sContent; 1156}, 1157 1158UnParseContent: function() // WYSIWYG - > html 1159{ 1160 BX.onCustomEvent(this, 'OnUnParseContent'); 1161 1162 var sContent = this._RecursiveGetHTML(this._RecursiveDomWalker(this.pEditorDocument.body, false)); 1163 1164 if (this.bBBCode) 1165 { 1166 if (!BX.browser.IsIE()) 1167 sContent = sContent.replace(/\r/ig, ''); 1168 sContent = sContent.replace(/\n/ig, ''); 1169 } 1170 1171 var arDivRules = [ 1172 ['#BR#(#TAG_BEGIN#)', "$1"], // 111<br><div>... => 111<> 1173 ['(#TAG_BEGIN#)(?:#BR#)*?(#TAG_END#)', "$1$2"], // [DIV]#BR#[/DIV] ==> [DIV][/DIV] 1174 ['(#TAG_BEGIN#)([\\s\\S]*?)#TAG_END#(?:\\n|\\r|\\s)*?#TAG_BEGIN#([\\s\\S]*?)(#TAG_END#)', function(str, s1, s2,s3,s4){return s1 + s2 + '#BR#' + s3 + s4;}, true], 1175 ['^#TAG_BEGIN#', ""], //kill [DIV] in the begining of the text 1176 ['([\\s\\S]*?(\\[\\/\\w+\\])*?)#TAG_BEGIN#([\\s\\S]*?)#TAG_END#([\\s\\S]*?)', function(str, s1, s2,s3,s4) 1177 { 1178 if (s2 && s2.toLowerCase && s2.toLowerCase() == '[/list]') 1179 return s1 + s3 + '#BR#' + s4; 1180 return s1 + '#BR#' + s3 + '#BR#' + s4; 1181 }, true], // [/list][DIV]wwww[/div]wwww => [/list]wwww#BR#wwwww, text[DIV]wwww[/div]wwww => text#BR#www#BR# 1182 ['#TAG_END#', "#BR#"] // [/DIV] ==> \n 1183 ]; 1184 1185 var re, i, l = arDivRules.length, str; 1186 if (this.bBBCode) 1187 { 1188 // 1189 if (BX.browser.IsOpera()) 1190 sContent = sContent.replace(/(?:#BR#)*?\[\/P\]/ig, "[/P]"); // #BR#[/P] ==> [/P] for opera 1191 1192 for (i = 0; i < l; i++) 1193 { 1194 re = arDivRules[i][0]; 1195 re = re.replace(/#TAG_BEGIN#/g, '\\[P\\]'); 1196 re = re.replace(/#TAG_END#/g, '\\[\\/P\\]'); 1197 re = re.replace(/\\\\/ig, '\\\\'); 1198 re = new RegExp(re, 'igm'); 1199 if (arDivRules[i][2] === true) 1200 while(true) 1201 { 1202 str = sContent.replace(re, arDivRules[i][1]); 1203 if (str == sContent) 1204 break; 1205 else 1206 sContent = str; 1207 } 1208 else 1209 sContent = sContent.replace(re, arDivRules[i][1]); 1210 } 1211 sContent = sContent.replace(/^((?:\s|\S)*?)(?:\n|\r|\s)+$/ig, "$1\n\n"); //kill multiple \n in the end 1212 1213 // Handle [DIV] tags from safari, chrome 1214 for (i = 0; i < l; i++) 1215 { 1216 re = arDivRules[i][0]; 1217 re = re.replace(/#TAG_BEGIN#/g, '\\[DIV\\]'); 1218 re = re.replace(/#TAG_END#/g, '\\[\\/DIV\\]'); 1219 re = re.replace(/\\\\/ig, '\\\\'); 1220 1221 if (arDivRules[i][2] === true) 1222 while(true) 1223 { 1224 str = sContent.replace(new RegExp(re, 'igm'), arDivRules[i][1]); 1225 if (str == sContent) 1226 break; 1227 else 1228 sContent = str; 1229 } 1230 else 1231 sContent = sContent.replace(new RegExp(re, 'igm'), arDivRules[i][1]); 1232 } 1233 1234 sContent = sContent.replace(/#BR#/ig, "\n"); 1235 sContent = sContent.replace(/\[DIV]/ig, ""); 1236 sContent = BX.util.htmlspecialcharsback(sContent); 1237 } 1238 1239 this.__sContent = sContent; 1240 BX.onCustomEvent(this, 'OnUnParseContentAfter'); 1241 sContent = this.__sContent; 1242 return sContent; 1243}, 1244 1245InitResizer: function() 1246{ 1247 this.oTransOverlay.Show(); 1248 1249 var 1250 _this = this, 1251 coreContPos = BX.pos(this.pFrame), 1252 newHeight = false; 1253 1254 var MouseMove = function(e) 1255 { 1256 e = e || window.event; 1257 BX.fixEventPageY(e); 1258 newHeight = e.pageY - coreContPos.top; 1259 1260 // New height 1261 if (newHeight < _this.arConfig.minHeight) 1262 { 1263 newHeight = _this.arConfig.minHeight; 1264 document.body.style.cursor = "not-allowed"; 1265 } 1266 else if (newHeight > _this.arConfig.maxHeight) 1267 { 1268 newHeight = _this.arConfig.maxHeight; 1269 document.body.style.cursor = "not-allowed"; 1270 } 1271 else 1272 { 1273 document.body.style.cursor = "n-resize"; 1274 } 1275 1276 _this.pFrame.style.height = newHeight + "px"; 1277 _this.ResizeFrame(newHeight); 1278 }; 1279 1280 var MouseUp = function(e) 1281 { 1282 if (_this.arConfig.autoResizeSaveSize) 1283 BX.userOptions.save('fileman', 'LHESize_' + _this.id, 'height', newHeight); 1284 _this.arConfig.height = newHeight; 1285 1286 document.body.style.cursor = ""; 1287 if (_this.oTransOverlay && _this.oTransOverlay.bShowed) 1288 _this.oTransOverlay.Hide(); 1289 1290 BX.unbind(document, "mousemove", MouseMove); 1291 BX.unbind(document, "mouseup", MouseUp); 1292 }; 1293 1294 BX.bind(document, "mousemove", MouseMove); 1295 BX.bind(document, "mouseup", MouseUp); 1296}, 1297 1298AutoResize: function() 1299{ 1300 var 1301 heightOffset = parseInt(this.arConfig.autoResizeOffset || 80),
1302 maxHeight = parseInt(this.arConfig.autoResizeMaxHeight || 0), 1303 minHeight = parseInt(this.arConfig.autoResizeMinHeight || 50), 1304 newHeight, 1305 _this = this; 1306 1307 if (this.autoResizeTimeout) 1308 clearTimeout(this.autoResizeTimeout); 1309 1310 this.autoResizeTimeout = setTimeout(function() 1311 { 1312 if (_this.sEditorMode == 'html') 1313 { 1314 //newHeight = _this.pEditorDocument.body.offsetHeight + heightOffset; 1315 newHeight = _this.pEditorDocument.body.offsetHeight; 1316 var 1317 body = _this.pEditorDocument.body, 1318 node = body.lastChild, 1319 offsetTop = false, i; 1320 1321 while (true) 1322 { 1323 if (!node) 1324 break; 1325 if (node.offsetTop) 1326 { 1327 offsetTop = node.offsetTop + (node.offsetHeight || 0); 1328 newHeight = offsetTop + heightOffset; 1329 break; 1330 } 1331 else 1332 { 1333 node = node.previousSibling; 1334 } 1335 } 1336 1337 var oEdSize = BX.GetWindowSize(_this.pEditorDocument); 1338 if (oEdSize.scrollHeight - oEdSize.innerHeight > 5) 1339 newHeight = Math.max(oEdSize.scrollHeight + heightOffset, newHeight); 1340 } 1341 else 1342 { 1343 newHeight = (_this.pTextarea.value.split("\n").length /* rows count*/ + 5) * 17; 1344 } 1345 1346 if (newHeight > parseInt(_this.arConfig.height)) 1347 { 1348 if (BX.browser.IsIOS()) 1349 maxHeight = Infinity; 1350 else if (!maxHeight || maxHeight < 10) 1351 maxHeight = Math.round(BX.GetWindowInnerSize().innerHeight * 0.9); // 90% from screen height 1352 1353 newHeight = Math.min(newHeight, maxHeight); 1354 newHeight = Math.max(newHeight, minHeight); 1355 1356 _this.SmoothResizeFrame(newHeight); 1357 } 1358 }, 300); 1359}, 1360 1361MousePos: function (e) 1362{ 1363 if(window.event) 1364 e = window.event; 1365 1366 if(e.pageX || e.pageY) 1367 { 1368 e.realX = e.pageX; 1369 e.realY = e.pageY; 1370 } 1371 else if(e.clientX || e.clientY) 1372 { 1373 e.realX = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) - document.documentElement.clientLeft; 1374 e.realY = e.clientY + (document.documentElement.scrollTop || document.body.scrollTop) - document.documentElement.clientTop; 1375 } 1376 return e; 1377}, 1378 1379SmoothResizeFrame: function(height) 1380{ 1381 var 1382 _this = this, 1383 curHeight = parseInt(this.pFrame.offsetHeight), 1384 count = 0, 1385 bRise = height > curHeight, 1386 timeInt = BX.browser.IsIE() ? 50 : 50, 1387 dy = 5; 1388 1389 if (!bRise) 1390 return; 1391 1392 if (this.smoothResizeInterval) 1393 clearInterval(this.smoothResizeInterval); 1394 1395 this.smoothResizeInterval = setInterval(function() 1396 { 1397 if (bRise) 1398 { 1399 curHeight += Math.round(dy * count); 1400 if (curHeight > height) 1401 { 1402 clearInterval(_this.smoothResizeInterval); 1403 if (curHeight > height) 1404 curHeight = height; 1405 } 1406 } 1407 else 1408 { 1409 curHeight -= Math.round(dy * count); 1410 if (curHeight < height) 1411 { 1412 curHeight = height; 1413 clearInterval(_this.smoothResizeInterval); 1414 } 1415 } 1416 1417 _this.pFrame.style.height = curHeight + "px"; 1418 _this.ResizeFrame(curHeight); 1419 count++; 1420 }, 1421 timeInt 1422 ); 1423}, 1424 1425ResizeFrame: function(newHeight) 1426{ 1427 var 1428 deltaWidth = 7, 1429 resizeHeight = this.arConfig.bManualResize ? 3 : 0, // resize row 1430 height = newHeight || parseInt(this.pFrame.offsetHeight), 1431 width = this.pFrame.offsetWidth; 1432 1433 this.pFrameTable.style.height = height + 'px'; 1434 var contHeight = height - this.buttonsHeight - resizeHeight; 1435 1436 if (contHeight > 0) 1437 { 1438 this.pEditCont.style.height = contHeight + 'px'; 1439 this.pTextarea.style.height = contHeight + 'px'; 1440 } 1441 1442 this.pTextarea.style.width = (width > deltaWidth) ? (width - deltaWidth) + 'px' : 'auto'; 1443 this.pButtonsCell.style.height = this.buttonsHeight + 'px'; 1444 1445 /*if (this.arConfig.bResizable) 1446 this.pResizer.parentNode.style.height = resizeHeight + 'px';*/ 1447}, 1448 1449AddButtons: function() 1450{ 1451 var 1452 i, l, butId, grInd, arButtons, 1453 toolbarConfig = this.arConfig.toolbarConfig; 1454 this.buttonsCount = 0; 1455 1456 if(!toolbarConfig) 1457 toolbarConfig = [ 1458 //'Source', 1459 'Bold', 'Italic', 'Underline', 'Strike', 'RemoveFormat', 'InsertHR', 1460 'Anchor', 1461 'CreateLink', 'DeleteLink', 'Image', //'SpecialChar', 1462 'Justify', 1463 'InsertOrderedList', 'InsertUnorderedList', 'Outdent', 'Indent', 1464 'BackColor', 'ForeColor', 1465 'Video', 1466 'StyleList', 'HeaderList', 1467 'FontList', 'FontSizeList', 1468 'Table' 1469 //smiles:['SmileList'] 1470 ]; 1471 1472 if (oBXLEditorUtils.oTune && oBXLEditorUtils.oTune[this.id]) 1473 { 1474 var 1475 ripButtons = oBXLEditorUtils.oTune[this.id].ripButtons, 1476 addButtons = oBXLEditorUtils.oTune[this.id].buttons; 1477 1478 if (ripButtons) 1479 { 1480 i = 0; 1481 while(i < toolbarConfig.length) 1482 { 1483 if (ripButtons[toolbarConfig[i]]) 1484 toolbarConfig = BX.util.deleteFromArray(toolbarConfig, i); 1485 else 1486 i++; 1487 } 1488 } 1489 1490 if (addButtons) 1491 { 1492 for (var j = 0, n = addButtons.length; j < n; j++) 1493 { 1494 if (addButtons[j].ind == -1 || addButtons[j].ind >= toolbarConfig.length) 1495 toolbarConfig.push(addButtons[j].but.id); 1496 else 1497 toolbarConfig = BX.util.insertIntoArray(toolbarConfig, addButtons[j].ind, addButtons[j].but.id); 1498 } 1499 } 1500 } 1501 1502 var 1503 begWidth = 0, 1504 endWidth = 0, // 4 1505 curLineWidth = begWidth, pCont, 1506 butContWidth = parseInt(this.pButtonsCont.offsetWidth); 1507 1508 this.ToolbarStartLine(true); 1509 for(i in toolbarConfig) 1510 { 1511 butId = toolbarConfig[i]; 1512 if (typeof butId != 'string' || !toolbarConfig.hasOwnProperty(i)) 1513 continue; 1514 1515 if (butId == '=|=') 1516 { 1517 this.ToolbarNewLine(); 1518 curLineWidth = begWidth; 1519 } 1520 else if (LHEButtons[butId]) 1521 { 1522 if (this.bBBCode && LHEButtons[butId].bBBHide) 1523 continue; 1524 1525 this.buttonsIndex[butId] = i; 1526 pCont = this.AddButton(LHEButtons[butId], butId); 1527 if (pCont) 1528 { 1529 curLineWidth += parseInt(pCont.style.width) || 23; 1530 if (curLineWidth + endWidth > butContWidth && butContWidth > 0) 1531 { 1532 butContWidth = parseInt(this.pButtonsCont.offsetWidth); // Doublecheck 1533 if (curLineWidth + endWidth > butContWidth && butContWidth > 0) 1534 { 1535 this.ToolbarNewLine(); 1536 this.pButtonsCont.appendChild(pCont); 1537 curLineWidth = begWidth; 1538 } 1539 } 1540 } 1541 } 1542 } 1543 this.ToolbarEndLine(); 1544 1545 if (typeof this.arConfig.controlButtonsHeight == 'undefined') 1546 this.buttonsHeight = this.toolbarLineCount * 27; 1547 else 1548 this.buttonsHeight = parseInt(this.arConfig.controlButtonsHeight || 0
1548); 1549 1550 this.arConfig.minHeight += this.buttonsHeight; 1551 this.arConfig.maxHeight += this.buttonsHeight; 1552 1553 BX.addCustomEvent(this, 'onShow', BX.proxy(this.ResizeFrame, this)); 1554}, 1555 1556AddButton: function(oBut, buttonId) 1557{ 1558 if (oBut.parser && oBut.parser.obj) 1559 this.oSpecialParsers[oBut.parser.name] = oBut.parser.obj; 1560 1561 this.buttonsCount++; 1562 var result; 1563 if (!oBut.type || !oBut.type == 'button') 1564 { 1565 if (buttonId == 'Code') 1566 this.bCodeBut = true; 1567 1568 var pButton = new window.LHEButton(oBut, this); 1569 if (pButton && pButton.oBut) 1570 { 1571 if (buttonId == 'Source') 1572 this.sourseBut = pButton; 1573 else if(buttonId == 'Quote') 1574 this.quoteBut = pButton; 1575 1576 result = this.pButtonsCont.appendChild(pButton.pCont); 1577 } 1578 } 1579 else if (oBut.type == 'Colorpicker') 1580 { 1581 var pColorpicker = new window.LHEColorPicker(oBut, this); 1582 result = this.pButtonsCont.appendChild(pColorpicker.pCont); 1583 } 1584 else if (oBut.type == 'List') 1585 { 1586 var pList = new window.LHEList(oBut, this); 1587 result = this.pButtonsCont.appendChild(pList.pCont); 1588 } 1589 1590 if (oBut.parsers) 1591 { 1592 for(var i = 0, cnt = oBut.parsers.length; i < cnt; i++) 1593 if (oBut.parsers[i] && oBut.parsers[i].obj) 1594 this.oSpecialParsers[oBut.parsers[i].name] = oBut.parsers[i].obj; 1595 } 1596 1597 return result; 1598}, 1599 1600AddParser: function(parser) 1601{
1602 if (parser && parser.name && typeof parser.obj == 'object') 1603 this.oSpecialParsers[parser.name] = parser.obj; 1604}, 1605 1606ToolbarStartLine: function(bFirst) 1607{ 1608 // Hack for IE 7 1609 if (!bFirst && BX.browser.IsIE()) 1610 this.pButtonsCont.appendChild(BX.create("IMG", {props: {src: this.oneGif, className: "lhe-line-ie"}})); 1611 1612 this.pButtonsCont.appendChild(BX.create("DIV", {props: {className: 'lhe-line-begin'}})); 1613}, 1614 1615ToolbarEndLine: function() 1616{ 1617 this.pButtonsCont.appendChild(BX.create("DIV", {props: {className: 'lhe-line-end'}})); 1618}, 1619 1620ToolbarNewLine: function() 1621{ 1622 this.toolbarLineCount++; 1623 this.ToolbarEndLine(); 1624 this.ToolbarStartLine(); 1625}, 1626 1627OpenDialog: function(arParams) 1628{ 1629 var oDialog = new window.LHEDialog(arParams, this); 1630}, 1631 1632GetSelectionObject: function() 1633{ 1634 var oSelection, oRange, root; 1635 if(this.pEditorDocument.selection) // IE 1636 { 1637 oSelection = this.pEditorDocument.selection; 1638 oRange = oSelection.createRange(); 1639 1640 if(oSelection.type=="Control") 1641 return oRange.commonParentElement(); 1642 1643 return oRange.parentElement(); 1644 } 1645 else // FF 1646 { 1647 oSelection = this.pEditorWindow.getSelection(); 1648 if(!oSelection) 1649 return false; 1650 1651 var container, i, rangeCount = oSelection.rangeCount, obj; 1652 for(var i = 0; i < rangeCount; i++) 1653 { 1654 oRange = oSelection.getRangeAt(i); 1655 container = oRange.startContainer; 1656 if(container.nodeType != 3) 1657 { 1658 if(container.nodeType == 1 && container.childNodes.length <= 0) 1659 obj = container; 1660 else 1661 obj = container.childNodes[oRange.startOffset]; 1662 } 1663 else 1664 { 1665 temp = oRange.commonAncestorContainer; 1666 while(temp && temp.nodeType == 3) 1667 temp = temp.parentNode; 1668 obj = temp; 1669 } 1670 root = (i == 0) ? obj : BXFindParentElement(root, obj); 1671 } 1672 return root; 1673 } 1674}, 1675 1676GetSelectionObjects: function() 1677{ 1678 var oSelection; 1679 if(this.pEditorDocument.selection) // IE 1680 { 1681 oSelection = this.pEditorDocument.selection; 1682 var s = oSelection.createRange(); 1683 1684 if(oSelection.type=="Control") 1685 return s.commonParentElement(); 1686 1687 return s.parentElement(); 1688 } 1689 else // FF 1690 { 1691 oSelection = this.pEditorWindow.getSelection(); 1692 if(!oSelection) 1693 return false; 1694 var oRange; 1695 var container, temp; 1696 var res = []; 1697 for(var i = 0; i < oSelection.rangeCount; i++) 1698 { 1699 oRange = oSelection.getRangeAt(i); 1700 container = oRange.startContainer; 1701 if(container.nodeType != 3) 1702 { 1703 if(container.nodeType == 1 && container.childNodes.length <= 0) 1704 res[res.length] = container; 1705 else 1706 res[res.length] = container.childNodes[oRange.startOffset]; 1707 } 1708 else 1709 { 1710 temp = oRange.commonAncestorContainer; 1711 while(temp && temp.nodeType == 3) 1712 temp = temp.parentNode; 1713 res[res.length] = temp; 1714 } 1715 } 1716 if(res.length > 1) 1717 return res; 1718 return res[0]; 1719 } 1720}, 1721 1722GetSelectionRange: function(doc, win) 1723{ 1724 try{ 1725 var 1726 oDoc = doc || this.pEditorDocument, 1727 oWin = win || this.pEditorWindow, 1728 oRange, 1729 oSel = this.GetSelection(oDoc, oWin); 1730 1731 if (oSel) 1732 { 1733 if (oDoc.createRange) 1734 { 1735 if (oSel.getRangeAt) 1736 oRange = oSel.getRangeAt(0); 1737 else 1738 { 1739 oRange = document.createRange(); 1740 oRange.setStart(oSel.anchorNode, oSel.anchorOffset); 1741 oRange.setEnd(oSel.focusNode, oSel.focusOffset); 1742 } 1743 } 1744 else 1745 oRange = oSel.createRange(); 1746 } 1747 else 1748 { 1749 oRange = false; 1750 } 1751 1752 } catch(e) {oRange = false;} 1753 1754 return oRange; 1755}, 1756 1757SelectRange: function(oRange, doc, win) 1758{ 1759 try{ // IE9 sometimes generete JS error 1760 if (!oRange) 1761 return; 1762 1763 var 1764 oDoc = doc || this.pEditorDocument, 1765 oWin = win || this.pEditorWindow; 1766 1767 this.ClearSelection(oDoc, oWin); 1768 if (oDoc.createRange) // FF 1769 { 1770 var oSel = oWin.getSelection(); 1771 oSel.removeAllRanges(); 1772 oSel.addRange(oRange); 1773 } 1774 else //IE 1775 { 1776 oRange.select(); 1777 } 1778 1779 }catch(e){} 1780}, 1781 1782SelectElement: function(pElement) 1783{ 1784 try{ 1785 var 1786 oRange, 1787 oDoc = this.pEditorDocument, 1788 oWin = this.pEditorWindow; 1789 1790 if(oWin.getSelection) 1791 { 1792 var oSel = oWin.getSelection(); 1793 oSel.selectAllChildren(pElement); 1794 oRange = oSel.getRangeAt(0); 1795 if (oRange.selectNode) 1796 oRange.selectNode(pElement); 1797 } 1798 else 1799 { 1800 oDoc.selection.empty(); 1801 oRange = oDoc.selection.createRange(); 1802 oRange.moveToElementText(pElement); 1803 oRange.select(); 1804 } 1805 return oRange; 1806 }catch(e){} 1807}, 1808 1809GetSelectedText: function(oRange) 1810{ 1811 // Get selected text 1812 var selectedText = ''; 1813 if (oRange.startContainer && oRange.endContainer) // DOM Model 1814 { 1815 if (oRange.startContainer == oRange.endContainer && (oRange.endContainer.nodeType == 3 || oRange.endContainer.nodeType == 1)
1815) 1816 selectedText = oRange.startContainer.textContent.substring(oRange.startOffset, oRange.endOffset); 1817 } 1818 else // IE 1819 { 1820 if (oRange.text == oRange.htmlText) 1821 selectedText = oRange.text; 1822 } 1823 return selectedText || ''; 1824}, 1825 1826ClearSelection: function(doc, win) 1827{ 1828 var 1829 oDoc = doc || this.pEditorDocument, 1830 oWin = win || this.pEditorWindow; 1831 1832 if (oWin.getSelection) 1833 oWin.getSelection().removeAllRanges(); 1834 else 1835 oDoc.selection.empty(); 1836}, 1837 1838GetSelection: function(oDoc, oWin) 1839{ 1840 if (!oDoc) 1841 oDoc = document; 1842 if (!oWin) 1843 oWin = window; 1844 1845 var oSel = false; 1846 if (oWin.getSelection) 1847 oSel = oWin.getSelection(); 1848 else if (oDoc.getSelection) 1849 oSel = oDoc.getSelection(); 1850 else if (oDoc.selection) 1851 oSel = oDoc.selection; 1852 return oSel; 1853}, 1854 1855InsertHTML: function(sContent) 1856{ 1857 try{ // Don't clear "try catch"... Some times browsers generetes failures 1858 this.SetFocus(); 1859 1860 if(BX.browser.IsIE()) 1861 { 1862 var oRng = this.pEditorDocument.selection.createRange(); 1863 if (oRng.pasteHTML) 1864 { 1865 oRng.pasteHTML(sContent); 1866 oRng.collapse(false); 1867 oRng.select(); 1868 } 1869 } 1870 else if(BX.browser.IsIE11()) 1871 { 1872 this.PasteHtmlAtCaret(sContent); 1873 } 1874 else 1875 { 1876 this.pEditorWindow.document.execCommand('insertHTML', false, sContent); 1877 } 1878 }catch(e){} 1879 1880 if (this.arConfig.bAutoResize && this.arConfig.bResizable) 1881 this.AutoResize(); 1882}, 1883 1884PasteHtmlAtCaret: function(html, selectPastedContent) 1885{ 1886 var 1887 win = this.pEditorWindow, 1888 doc = this.pEditorDocument, 1889 sel, range; 1890 1891 if (win.getSelection) 1892 { 1893 // IE9 and non-IE 1894 sel = win.getSelection(); 1895 if (sel.getRangeAt && sel.rangeCount) 1896 { 1897 range = sel.getRangeAt(0); 1898 range.deleteContents(); 1899 1900 // Range.createContextualFragment() would be useful here but is 1901 // only relatively recently standardized and is not supported in 1902 // some browsers (IE9, for one) 1903 var el = doc.createElement("div"); 1904 el.innerHTML = html; 1905 var frag = doc.createDocumentFragment(), node, lastNode; 1906 while ((node = el.firstChild)) 1907 lastNode = frag.appendChild(node); 1908 1909 var firstNode = frag.firstChild; 1910 range.insertNode(frag); 1911 1912 // Preserve the selection 1913 if (lastNode) 1914 { 1915 range = range.cloneRange(); 1916 range.setStartAfter(lastNode); 1917 if (selectPastedContent) 1918 range.setStartBefore(firstNode); 1919 else 1920 range.collapse(true); 1921 1922 sel.removeAllRanges(); 1923 sel.addRange(range); 1924 } 1925 } 1926 } 1927 else if ((sel = doc.selection) && sel.type != "Control") 1928 { 1929 // IE < 9 1930 var originalRange = sel.createRange(); 1931 originalRange.collapse(true); 1932 sel.createRange().pasteHTML(html); 1933 if (selectPastedContent) 1934 { 1935 range = sel.createRange(); 1936 range.setEndPoint("StartToStart", originalRange); 1937 range.select(); 1938 } 1939 } 1940}, 1941 1942AppendCSS: function(styles) 1943{ 1944 styles = BX.util.trim(styles); 1945 if (styles.length <= 0) 1946 return false; 1947 1948 var 1949 pDoc = this.pEditorDocument, 1950 pHeads = pDoc.getElementsByTagName("HEAD"); 1951 1952 if(pHeads.length != 1) 1953 return false; 1954 1955 if(BX.browser.IsIE()) 1956 { 1957 setTimeout(function() 1958 { 1959 try{ 1960 if (pDoc.styleSheets.length == 0) 1961 pHeads[0].appendChild(pDoc.createElement("STYLE")); 1962 pDoc.styleSheets[0].cssText += styles; 1963 }catch(e){} 1964 }, 100); 1965 } 1966 else 1967 { 1968 try{ 1969 var xStyle = pDoc.createElement("STYLE"); 1970 pHeads[0].appendChild(xStyle); 1971 xStyle.appendChild(pDoc.createTextNode(styles)); 1972 }catch(e){} 1973 } 1974 return true; 1975}, 1976 1977SetBxTag: function(pElement, params) 1978{ 1979 var id; 1980 if (params.id || pElement && pElement.id) 1981 id = params.id || pElement.id; 1982 1983 if (!id) 1984 id = 'bxid_' + Math.round(Math.random() * 1000000); 1985 else if (this.bxTags[id] && !params.tag) 1986 params.tag = this.bxTags[id].tag; 1987 1988 params.id = id; 1989 if (pElement) 1990 pElement.id = params.id; 1991 1992 this.bxTags[params.id] = params; 1993 return params.id; 1994}, 1995 1996GetBxTag: function(id) 1997{ 1998 if (id) 1999 { 2000 if (typeof id != "string" && id.id) 2001 id = id.id; 2002 2003 if (id && id.length > 0 && this.bxTags[id] && this.bxTags[id].tag) 2004 { 2005 this.bxTags[id].tag = this.bxTags[id].tag.toLowerCase(); 2006 return this.bxTags[id]; 2007 } 2008 } 2009 2010 return {tag: false}; 2011}, 2012 2013GetAttributesList: function(str) 2014{ 2015 str = str + " "; 2016 2017 var arParams = {}, arPHP = [], bPhp = false, _this = this; 2018 // 1. Replace PHP by #BXPHP# 2019 str = str.replace(/<\?.*?\?>/ig, function(s) 2020 { 2021 arPHP.push(s); 2022 return "#BXPHP" + (arPHP.length - 1) + "#"; 2023 }); 2024 2025 // 2.0 Parse params - without quotes 2026 str = str.replace(/([^\w]??)(\w+?)=([^\s\'"]+?)(\s)/ig, function(s, b0, b1, b2, b3) 2027 { 2028 b2 = b2.replace(/#BXPHP(\d+)#/ig, function(s, num){return arPHP[num] || s;}); 2029 arParams[b1.toLowerCase()] = BX.util.htmlspecialcharsback(b2); 2030 return b0; 2031 }); 2032 2033 // 2.1 Parse params 2034 str = str.replace(/([^\w]??)(\w+?)\s*=\s*("|\')([^\3]*?)\3/ig, function(s, b0, b1, b2, b3) 2035 { 2036 // 3. Replace PHP back 2037 b3 = b3.replace(/#BXPHP(\d+)#/ig, function(s, num){return arPHP[num] || s;}); 2038 arParams[b1.toLowerCase()] = BX.util.htmlspecialcharsback(b3); 2039 return b0; 2040 }); 2041
2042 return arParams; 2043}, 2044 2045RidOfNode: function (pNode, bHard) 2046{ 2047 if (!pNode || pNode.nodeType != 1) 2048 return; 2049 2050 var i, nodeName = pNode.tagName.toLowerCase(), 2051 nodes = ['span', 'strike', 'del', 'font', 'code', 'div']; 2052 2053 if (BX.util.in_array(nodeName, nodes)) // Check node names 2054 { 2055 if (bHard !== true) 2056 { 2057 for (i = pNode.attributes.length - 1; i >= 0; i--) 2058 { 2059 if (BX.util.trim(pNode.getAttribute(pNode.attributes[i].nodeName.toLowerCase())) != "") 2060 return false; // Node have attributes, so we cant get rid of it without loosing info 2061 } 2062 } 2063 2064 var arNodes = pNode.childNodes; 2065 while(arNodes.length > 0) 2066 pNode.parentNode.insertBefore(arNodes[0], pNode); 2067 2068 pNode.parentNode.removeChild(pNode); 2069 //this.OnEvent("OnSelectionChange"); 2070 return true; 2071 } 2072 2073 return false; 2074}, 2075 2076WrapSelectionWith: function (tagName, arAttributes) 2077{ 2078 this.SetFocus(); 2079 var oRange, oSelection; 2080 2081 if (!tagName) 2082 tagName = 'SPAN'; 2083 2084 var sTag = 'FONT', i, pEl, arTags, arRes = []; 2085 2086 try{this.pEditorDocument.execCommand("styleWithCSS", false, false);}catch(e){} 2087 this.executeCommand("FontName", "bitrixtemp"); 2088 2089 arTags = this.pEditorDocument.getElementsByTagName(sTag); 2090 2091 for(i = arTags.length - 1; i >= 0; i--) 2092 { 2093 if (arTags[i].getAttribute('face') != 'bitrixtemp') 2094 continue; 2095 2096 pEl = BX.create(tagName, arAttributes, this.pEditorDocument); 2097 arRes.push(pEl); 2098 2099 while(arTags[i].firstChild) 2100 pEl.appendChild(arTags[i].firstChild); 2101 2102 arTags[i].parentNode.insertBefore(pEl, arTags[i]); 2103 arTags[i].parentNode.removeChild(arTags[i]); 2104 } 2105 2106 if (this.arConfig.bAutoResize && this.arConfig.bResizable) 2107 this.AutoResize(); 2108 2109 return arRes; 2110}, 2111 2112SaveSelectionRange: function() 2113{ 2114 if (this.sEditorMode == 'code') 2115 this.oPrevRangeText = this.GetSelectionRange(document, window); 2116 else 2117 this.oPrevRange = this.GetSelectionRange(); 2118}, 2119 2120RestoreSelectionRange: function() 2121{ 2122 if (this.sEditorMode == 'code') 2123 this.IESetCarretPos(this.oPrevRangeText); 2124 else if(this.oPrevRange) 2125 this.SelectRange(this.oPrevRange); 2126}, 2127 2128focus: function(el, bSelect) 2129{ 2130 setTimeout(function() 2131 { 2132 try{ 2133 el.focus(); 2134 if(bSelect) 2135 el.select(); 2136 }catch(e){} 2137 }, 100); 2138}, 2139 2140// Methods below used in BB-mode 2141// Earlier was in bb.js 2142InitBBCode: function() 2143{ 2144 this.stack = []; 2145 var _this = this; 2146 this.pTextarea.onkeydown = BX.proxy(this.OnKeyDownBB, this); 2147 2148 // Backup parser functions 2149 this._GetNodeHTMLLeft = this.GetNodeHTMLLeft; 2150 this._GetNodeHTMLRight = this.GetNodeHTMLRight; 2151 2152 this.GetNodeHTMLLeft = this.GetNodeHTMLLeftBB; 2153 this.GetNodeHTMLRight = this.GetNodeHTMLRightBB; 2154}, 2155 2156ShutdownBBCode: function() 2157{ 2158 this.bBBCode = false; 2159 this.arConfig.bBBCode = false; 2160 2161 this.pTextarea.onkeydown = null; 2162 2163 // Restore parser functions 2164 this.GetNodeHTMLLeft = this._GetNodeHTMLLeft; 2165 this.GetNodeHTMLRight = this._GetNodeHTMLRight; 2166 2167 this.arConfig.bConvertContentFromBBCodes = false; 2168}, 2169 2170FormatBB: function(params) 2171{ 2172 var 2173 pBut = params.pBut, 2174 value = params.value, 2175 tag = params.tag.toUpperCase(), 2176 tag_end = tag; 2177 2178 if (tag == 'FONT' || tag == 'COLOR' || tag == 'SIZE') 2179 tag += "=" + value; 2180 2181 if ((!BX.util.in_array(tag, this.stack) || this.GetTextSelection()) && !(tag == 'FONT' && value == 'none')) 2182 { 2183 if (!this.WrapWith("[" + tag + "]", "[/" + tag_end + "]")) 2184 { 2185 this.stack.push(tag); 2186 2187 if (pBut && pBut.Check) 2188 pBut.Check(true); 2189 } 2190 } 2191 else 2192 { 2193 var res = false; 2194 while (res = this.stack.pop()) 2195 { 2196 this.WrapWith("[/" + res + "]", ""); 2197 if (pBut && pBut.Check) 2198 pBut.Check(false); 2199 2200 if (res == tag) 2201 break; 2202 } 2203 } 2204}, 2205 2206GetTextSelection: function() 2207{ 2208 var res = false; 2209 if (typeof this.pTextarea.selectionStart != 'undefined') 2210 { 2211 res = this.pTextarea.value.substr(this.pTextarea.selectionStart, this.pTextarea.selectionEnd - this.pTextarea.selectionStart); 2212 } 2213 else if (document.selection && document.selection.createRange) 2214 { 2215 res = document.selection.createRange().text; 2216 } 2217 else if (window.getSelection) 2218 { 2219 res = window.getSelection(); 2220 res = res.toString(); 2221 } 2222 2223 return res; 2224}, 2225 2226IESetCarretPos: function(oRange) 2227{ 2228 if (!oRange || !BX.browser.IsIE() || oRange.text.length != 0 /* text selected*/) 2229 return; 2230 2231 oRange.moveStart('character', - this.pTextarea.value.length); 2232 var pos = oRange.text.length; 2233 2234 var range = this.pTextarea.createTextRange(); 2235 range.collapse(true); 2236 range.moveEnd('character', pos); 2237 range.moveStart('character', pos); 2238 range.select(); 2239}, 2240 2241WrapWith: function (tagBegin, tagEnd, postText) 2242{ 2243 if (!tagBegin) 2244 tagBegin = ""; 2245 if (!tagEnd) 2246 tagEnd = "" 2247 2248 if (!postText) 2249 postText = ""; 2250 2251 if (tagBegin.length <= 0 && tagEnd.length <= 0 && postText.length <= 0) 2252 return true; 2253 2254 var bReplaceText = !!postText; 2255 var sSelectionText = this.GetTextSelection(); 2256 2257 if (!this.bTextareaFocus) 2258 this.pTextarea.focus(); // BUG IN IE 2259 2260 var isSelect = (sSelectionText ? 'select' : bReplaceText ? 'after' : 'in'); 2261 2262 if (bReplaceText) 2263 postText = tagBegin + postText + tagEnd; 2264 else if (sSelectionText)
2265 postText = tagBegin + sSelectionText + tagEnd; 2266 else 2267 postText = tagBegin + tagEnd; 2268 2269 if (typeof this.pTextarea.selectionStart != 'undefined') 2270 { 2271 var 2272 currentScroll = this.pTextarea.scrollTop, 2273 start = this.pTextarea.selectionStart, 2274 end = this.pTextarea.selectionEnd; 2275 2276 this.pTextarea.value = this.pTextarea.value.substr(0, start) + postText + this.pTextarea.value.substr(end); 2277 2278 if (isSelect == 'select') 2279 { 2280 this.pTextarea.selectionStart = start; 2281 this.pTextarea.selectionEnd = start + postText.length; 2282 } 2283 else if (isSelect == 'in') 2284 { 2285 this.pTextarea.selectionStart = this.pTextarea.selectionEnd = start + tagBegin.length; 2286 } 2287 else 2288 { 2289 this.pTextarea.selectionStart = this.pTextarea.selectionEnd = start + postText.length; 2290 } 2291 this.pTextarea.scrollTop = currentScroll; 2292 } 2293 else if (document.selection && document.selection.createRange) 2294 { 2295 var sel = document.selection.createRange(); 2296 var selection_copy = sel.duplicate(); 2297 postText = postText.replace(/\r?\n/g, '\n'); 2298 sel.text = postText; 2299 sel.setEndPoint('StartToStart', selection_copy); 2300 sel.setEndPoint('EndToEnd', selection_copy); 2301 2302 if (isSelect == 'select') 2303 { 2304 sel.collapse(true); 2305 postText = postText.replace(/\r\n/g, '1'); 2306 sel.moveEnd('character', postText.length); 2307 } 2308 else if (isSelect == 'in') 2309 { 2310 sel.collapse(false); 2311 sel.moveEnd('character', tagBegin.length); 2312 sel.collapse(false); 2313 } 2314 else 2315 { 2316 sel.collapse(false); 2317 sel.moveEnd('character', postText.length); 2318 sel.collapse(false); 2319 } 2320 sel.select(); 2321 } 2322 else 2323 { 2324 // failed - just stuff it at the end of the message 2325 this.pTextarea.value += postText; 2326 } 2327 return true; 2328}, 2329 2330ParseBB: function (sContent) // BBCode -> WYSIWYG 2331{ 2332 sContent = BX.util.htmlspecialchars(sContent); 2333 2334 // Table 2335 sContent = sContent.replace(/[\r\n\s\t]?\[table\][\r\n\s\t]*?\[tr\]/ig, '[TABLE][TR]'); 2336 sContent = sContent.replace(/\[tr\][\r\n\s\t]*?\[td\]/ig, '[TR][TD]'); 2337 sContent = sContent.replace(/\[tr\][\r\n\s\t]*?\[th\]/ig, '[TR][TH]'); 2338 sContent = sContent.replace(/\[\/td\][\r\n\s\t]*?\[td\]/ig, '[/TD][TD]'); 2339 sContent = sContent.replace(/\[\/tr\][\r\n\s\t]*?\[tr\]/ig, '[/TR][TR]'); 2340 sContent = sContent.replace(/\[\/td\][\r\n\s\t]*?\[\/tr\]/ig, '[/TD][/TR]'); 2341 sContent = sContent.replace(/\[\/th\][\r\n\s\t]*?\[\/tr\]/ig, '[/TH][/TR]'); 2342 sContent = sContent.replace(/\[\/tr\][\r\n\s\t]*?\[\/table\][\r\n\s\t]?/ig, '[/TR][/TABLE]'); 2343 2344 // List 2345 sContent = sContent.replace(/[\r\n\s\t]*?\[\/list\]/ig, '[/LIST]'); 2346 sContent = sContent.replace(/[\r\n\s\t]*?\[\*\]?/ig, '[*]'); 2347 2348 var 2349 arSimpleTags = [ 2350 'b','u', 'i', ['s', 'del'], // B, U, I, S 2351 'table', 'tr', 'td', 'th'//, // Table 2352 ], 2353 bbTag, tag, i, l = arSimpleTags.length, re; 2354 2355 for (i = 0; i < l; i++) 2356 { 2357 if (typeof arSimpleTags[i] == 'object') 2358 { 2359 bbTag = arSimpleTags[i][0]; 2360 tag = arSimpleTags[i][1]; 2361 } 2362 else 2363 { 2364 bbTag = tag = arSimpleTags[i]; 2365 } 2366 2367 sContent = sContent.replace(new RegExp('\\[(\\/?)' + bbTag + '\\]', 'ig'), "<$1" + tag + ">"); 2368 } 2369 2370 // Link 2371 sContent = sContent.replace(/\[url\]((?:\s|\S)*?)\[\/url\]/ig, "<a href=\"$1\">$1</a>"); 2372 sContent = sContent.replace(/\[url\s*=\s*((?:[^\[\]]*?(?:\[[^\]]+?\])*[^\[\]]*?)*)\s*\]((?:\s|\S)*?)\[\/url\]/ig, "<a href=\"$1\">$2</a>"); 2373 2374 // Img 2375 var _this = this; 2376 sContent = sContent.replace(/\[img(?:\s*?width=(\d+)\s*?height=(\d+))?\]((?:\s|\S)*?)\[\/img\]/ig, 2377 function(str, w, h, src) 2378 { 2379 var strSize = ""; 2380 w = parseInt(w); 2381 h = parseInt(h); 2382 2383 if (w && h && _this.bBBParseImageSize) 2384 strSize = ' width="' + w + '" height="' + h + '"'; 2385 2386 return '<img src="' + src + '"' + strSize + '/>'; 2387 } 2388 ); 2389 2390 // Font color 2391 i = 0; 2392 while (sContent.toLowerCase().indexOf('[color=') != -1 && sContent.toLowerCase().indexOf('[/color]') != -1 && i++ < 20) 2393 sContent = sContent.replace(/\[color=((?:\s|\S)*?)\]((?:\s|\S)*?)\[\/color\]/ig, "<font color=\"$1\">$2</font>"); 2394 2395 // List 2396 i = 0; 2397 while (sContent.toLowerCase().indexOf('[list=') != -1 && sContent.toLowerCase().indexOf('[/list]') != -1 && i++ < 20) 2398 sContent = sContent.replace(/\[list=1\]((?:\s|\S)*?)\[\/list\]/ig, "<ol>$1</ol>"); 2399 2400 i = 0; 2401 while (sContent.toLowerCase().indexOf('[list') != -1 && sContent.toLowerCase().indexOf('[/list]') != -1 && i++ < 20) 2402 sContent = sContent.replace(/\[list\]((?:\s|\S)*?)\[\/list\]/ig, "<ul>$1</ul>"); 2403 2404 sContent = sContent.replace(/\[\*\]/ig, "<li>"); 2405 2406 // Font 2407 i = 0; 2408 while (sContent.toLowerCase().indexOf('[font=') != -1 && sContent.toLowerCase().indexOf('[/font]') != -1 && i++ < 20) 2409 sContent = sContent.replace(/\[font=((?:\s|\S)*?)\]((?:\s|\S)*?)\[\/font\]/ig, "<font face=\"$1\">$2</font>"); 2410 2411 // Font size 2412 i = 0; 2413 while (sContent.toLowerCase().indexOf('[size=') != -1 && sContent.toLowerCase().indexOf('[/size]') != -1 && i++ < 20) 2414 sContent = sContent.replace(/\[size=((?:\s|\S)*?)\]((?:\s|\S)*?)\[\/size\]/ig, "<font size=\"$1\">$2</font>"); 2415 2416 // Replace \n => <br/> 2417 sContent = sContent.replace(/\n/ig, "<br />"); 2418 2419 return sContent; 2420}, 2421 2422UnParseNodeBB: function (pNode) // WYSIWYG -> BBCode 2423{ 2424 if (pNode.text == "br") 2425 return "#BR#"; 2426 2427 if (pNode.type == 'text') 2428 return false;
2429 2430 //[CODE] Handle code tag 2431 if (pNode.text == "pre" && pNode.arAttributes['class'] == 'lhe-code') 2432 return "[CODE]" + this.RecGetCodeContent(pNode) + "[/CODE]"; 2433 2434 pNode.bbHide = true; 2435 if (pNode.text == 'font' && pNode.arAttributes.color) 2436 { 2437 pNode.bbHide = false; 2438 pNode.text = 'color'; 2439 pNode.bbValue = pNode.arAttributes.color; 2440 } 2441 else if (pNode.text == 'font' && pNode.arAttributes.size) 2442 { 2443 pNode.bbHide = false; 2444 pNode.text = 'size'; 2445 pNode.bbValue = pNode.arAttributes.size; 2446 } 2447 else if (pNode.text == 'font' && pNode.arAttributes.face) 2448 { 2449 pNode.bbHide = false; 2450 pNode.text = 'font'; 2451 pNode.bbValue = pNode.arAttributes.face; 2452 } 2453 else if(pNode.text == 'del') 2454 { 2455 pNode.bbHide = false; 2456 pNode.text = 's'; 2457 } 2458 else if(pNode.text == 'strong' || pNode.text == 'b') 2459 { 2460 pNode.bbHide = false; 2461 pNode.text = 'b'; 2462 } 2463 else if(pNode.text == 'em' || pNode.text == 'i') 2464 { 2465 pNode.bbHide = false; 2466 pNode.text = 'i'; 2467 } 2468 else if(pNode.text == 'blockquote') 2469 { 2470 pNode.bbHide = false; 2471 pNode.text = 'quote'; 2472 } 2473 else if(pNode.text == 'ol') 2474 { 2475 pNode.bbHide = false;
2476 pNode.text = 'list'; 2477 pNode.bbBreakLineRight = true; 2478 pNode.bbValue = '1'; 2479 } 2480 else if(pNode.text == 'ul') 2481 { 2482 pNode.bbHide = false; 2483 pNode.text = 'list'; 2484 pNode.bbBreakLineRight = true; 2485 } 2486 else if(pNode.text == 'li') 2487 { 2488 pNode.bbHide = false; 2489 pNode.text = '*'; 2490 pNode.bbBreakLine = true; 2491 pNode.bbHideRight = true; 2492 } 2493 else if(pNode.text == 'a') 2494 { 2495 pNode.bbHide = false; 2496 pNode.text = 'url'; 2497 pNode.bbValue = pNode.arAttributes.href; 2498 } 2499 else if(this.parseAlign 2500 && 2501 (pNode.arAttributes.align || pNode.arStyle.textAlign) 2502 && 2503 !(BX.util.in_array(pNode.text.toLowerCase(), ['table', 'tr', 'td', 'th'])) 2504 ) 2505 { 2506 var align = pNode.arStyle.textAlign || pNode.arAttributes.align; 2507 if (BX.util.in_array(align, ['left', 'right', 'center', 'justify'])) 2508 { 2509 pNode.bbHide = false; 2510 pNode.text = align; 2511 } 2512 else 2513 { 2514 pNode.bbHide = !BX.util.in_array(pNode.text, this.arBBTags); 2515 } 2516 } 2517 else if(BX.util.in_array(pNode.text, this.arBBTags)) //'p', 'u', 'div', 'table', 'tr', 'img', 'td', 'a' 2518 { 2519 pNode.bbHide = false;
2520 } 2521 2522 return false; 2523}, 2524 2525RecGetCodeContent: function(pNode) // WYSIWYG -> BBCode 2526{ 2527 if (!pNode || !pNode.arNodes || !pNode.arNodes.length) 2528 return ''; 2529 2530 var res = ''; 2531 for (var i = 0; i < pNode.arNodes.length; i++) 2532 { 2533 if (pNode.arNodes[i].type == 'text') 2534 res += pNode.arNodes[i].text; 2535 else if (pNode.arNodes[i].type == 'element' && pNode.arNodes[i].text == "br") 2536 res += (this.bBBCode ? "#BR#" : "\n"); 2537 else if (pNode.arNodes[i].arNodes) 2538 res += this.RecGetCodeContent(pNode.arNodes[i]); 2539 } 2540 2541 if (this.bBBCode) 2542 { 2543 if (BX.browser.IsIE()) 2544 res = res.replace(/\r/ig, "#BR#"); 2545 else 2546 res = res.replace(/\n/ig, "#BR#"); 2547 } 2548 else if (BX.browser.IsIE()) 2549 { 2550 res = res.replace(/\n/ig, "\r\n"); 2551 } 2552 2553 return res; 2554}, 2555 2556GetNodeHTMLLeftBB: function (pNode) 2557{ 2558 if(pNode.type == 'text') 2559 { 2560 var text = BX.util.htmlspecialchars(pNode.text); 2561 text = text.replace(/\[/ig, "["); 2562 text = text.replace(/\]/ig, "]"); 2563 return text; 2564 } 2565 2566 var res = ""; 2567 if (pNode.bbBreakLine) 2568 res += "\n"; 2569 2570 if(pNode.type == 'element' && !pNode.bbHide) 2571 { 2572 res += "[" + pNode.text.toUpperCase(); 2573 if (pNode.bbValue) 2574 res += '=' + pNode.bbValue; 2575 res += "]"; 2576 } 2577 2578 return res; 2579}, 2580 2581GetNodeHTMLRightBB: function (pNode) 2582{ 2583 var res = ""; 2584 if (pNode.bbBreakLineRight) 2585 res += "\n"; 2586 2587 if(pNode.type == 'element' && (pNode.arNodes.length > 0 || this.IsPairNode(pNode.text)) && !pNode.bbHide && !pNode.bbHideRight) 2588 res += "[/" + pNode.text.toUpperCase() + "]"; 2589 2590 return res; 2591}, 2592 2593OptimizeBB: function (str) 2594{ 2595 // TODO: kill links without text and names 2596 // TODO: Kill multiple line ends 2597 var 2598 iter = 0, 2599 bReplasing = true, 2600 arTags = ['b', 'i', 'u', 's', 'color', 'font', 'size', 'quote'], 2601 replaceEmptyTags = function(){i--; bReplasing = true; return ' ';}, 2602 re, tagName, i, l; 2603 2604 while(iter++ < 20 && bReplasing) 2605 { 2606 bReplasing = false; 2607 for (i = 0, l = arTags.length; i < l; i++) 2608 { 2609 tagName = arTags[i]; 2610 // Replace empties: [b][/b] ==> "" 2611 re = new RegExp('\\[' + tagName + '[^\\]]*?\\]\\s*?\\[/' + tagName + '\\]', 'ig'); 2612 str = str.replace(re, replaceEmptyTags); 2613 2614 if (tagName !== 'quote') 2615 { 2616 re = new RegExp('\\[((' + tagName + '+?)(?:\\s+?[^\\]]*?)?)\\]([\\s\\S]+?)\\[\\/\\2\\](\\s*?)\\[\\1\\]([\\s\\S]+?)\\[\\/\\2\\]', 'ig'); 2617 str = str.replace(re, function(str, b1, b2, b3, spacer, b4) 2618 { 2619 if (spacer.indexOf("\n") != -1) 2620 return str; 2621 bReplasing = true; 2622 return '[' + b1 + ']' + b3 + ' ' + b4 + '[/' + b2 + ']'; 2623 } 2624 ); 2625 2626 //Replace [b]1 [b]2[/b] 3[/b] ===>> [b]1 2 3[/b] 2627 // re = new RegExp('(\\[' + tagName + '(?:\\s+?[^\\]]*?)?\\])([\\s\\S]+?)\\1([\\s\\S]+?)(\\[\\/' + tagName + '\\])([\\s\\S]+?)\\4', 'ig'); 2628 // str = str.replace(re, function(str, b1, b2, b3, b4, b5) 2629 // { 2630 // bReplasing = true; 2631 // return b1 + b2 + b3 + b5 + b4; 2632 // } 2633 // ); 2634 } 2635 } 2636 } 2637 // 2638 str = str.replace(/[\r\n\s\t]*?\[\/list\]/ig, "\n[/LIST]"); 2639 str = str.replace(/[\r\n\s\t]*?\[\/list\]/ig, "\n[/LIST]"); 2640 2641 // Cut "\n" in the end of the message (only for BB) 2642 str = str.replace(/\n*$/ig, ''); 2643 2644 return str; 2645}, 2646 2647RemoveFormatBB: function() 2648{ 2649 var str = this.GetTextSelection(); 2650 if (str) 2651 { 2652 var 2653 it = 0, 2654 arTags = ['b', 'i', 'u', 's', 'color', 'font', 'size'], 2655 i, l = arTags.length; 2656 2657 //[b]123[/b] ==> 123 2658 while (it < 30) 2659 { 2660 str1 = str; 2661 for (i = 0; i < l; i++) 2662 str = str.replace(new RegExp('\\[(' + arTags[i] + ')[^\\]]*?\\]([\\s\\S]*?)\\[/\\1\\]', 'ig'), "$2"); 2663 2664 if (str == str1) 2665 break; 2666 it++; 2667 } 2668 2669 this.WrapWith('', '', str); 2670 } 2671}, 2672 2673OnKeyDownBB: function(e) 2674{ 2675 if(!e) e = window.event; 2676 2677 var key = e.which || e.keyCode; 2678 if (e.ctrlKey && !e.shiftKey && !e.altKey) 2679 { 2680 switch (key) 2681 { 2682 case 66 : // B 2683 case 98 : // b 2684 this.FormatBB({tag: 'B'}); 2685 return BX.PreventDefault(e); 2686 case 105 : // i 2687 case 73 : // I 2688 this.FormatBB({tag: 'I'}); 2689 return BX.PreventDefault(e); 2690 case 117 : // u 2691 case 85 : // U 2692 this.FormatBB({tag: 'U'}); 2693 return BX.PreventDefault(e); 2694 case 81 : // Q - quote 2695 this.FormatBB({tag: 'QUOTE'}); 2696 return BX.PreventDefault(e); 2697 } 2698 } 2699 2700 // Tab 2701 if (key == 9) 2702 { 2703 this.WrapWith('', '', "\t"); 2704 return BX.PreventDefault(e); 2705 } 2706 2707 // Ctrl + Enter 2708 if ((e.keyCode == 13 || e.keyCode == 10) && e.ctrlKey && this.ctrlEnterHandler) 2709 { 2710 this.SaveContent(); 2711 this.ctrlEnterHandler(); 2712 } 2713}, 2714 2715GetCutHTML: function(e) 2716{ 2717 if (this.curCutId) 2718 { 2719 var pCut = this.pEditorDocument.getElementById(this.curCutId); 2720 if (pCut) 2721 { 2722 pCut.parentNode.insertBefore(BX.create("BR", {}, this.pEditorDocument), pCut); 2723 pCut.parentNode.removeChild(pCut); 2724 } 2725 } 2726 2727 this.curCutId = this.SetBxTag(false, {tag: "cut"}); 2728 return '<img src="' + this.oneGif+ '" class="bxed-cut" id="' + this.curCutId + '" title="' + BX.message.CutTitle + '"/>'; 2729}, 2730 2731OnPaste: function() 2732{ 2733 if (this.bOnPasteProcessing) 2734 return; 2735 2736 this.bOnPasteProcessing = true; 2737 var _this = this; 2738 var scrollTop = this.pEditorDocument.body.scrollTop; 2739 setTimeout(function(){ 2740 _this.bOnPasteProcessing = false;
2741 _this.InsertHTML('<span style="visibility: hidden;" id="' + _this.SetBxTag(false, {tag: "cursor"}) + '" ></span>'); 2742 2743 _this.SaveContent(); 2744 setTimeout(function() 2745 { 2746 var content = _this.GetContent(); 2747 2748 if (/<\w[^>]*(( class="?MsoNormal"?)|(="mso-))/gi.test(content)) 2749 content = _this.CleanWordText(content); 2750 2751 _this.SetEditorContent(content); 2752 2753 setTimeout(function() 2754 { 2755 try{ 2756 var pCursor = _this.pEditorDocument.getElementById(_this.lastCursorId); 2757 if (pCursor && pCursor.parentNode) 2758 { 2759 var newScrollTop = pCursor.offsetTop - 30; 2760 if (newScrollTop > 0) 2761 { 2762 if (scrollTop > 0 && scrollTop + parseInt(_this.pFrame.offsetHeight) > newScrollTop) 2763 _this.pEditorDocument.body.scrollTop = scrollTop; 2764 else 2765 _this.pEditorDocument.body.scrollTop = newScrollTop; 2766 } 2767 2768 _this.SelectElement(pCursor); 2769 pCursor.parentNode.removeChild(pCursor); 2770 _this.SetFocus(); 2771 } 2772 }catch(e){} 2773 }, 100); 2774 2775 }, 100); 2776 }, 100); 2777}, 2778 2779CleanWordText: function(text) 2780{ 2781 text = text.replace(/<(P|B|U|I|STRIKE)> <\/\1>/g, ' '); 2782 text = text.replace(/<o:p>([\s\S]*?)<\/o:p>/ig, "$1"); 2783 //text = text.replace(/<o:p>[\s\S]*?<\/o:p>/ig, " "); 2784 2785 text = text.replace(/<span[^>]*display:\s*?none[^>]*>([\s\S]*?)<\/span>/gi, ''); // Hide spans with display none 2786 2787 text = text.replace(/<!--\[[\s\S]*?\]-->/ig, ""); //<!--[.....]--> <!--[if gte mso 9]>...<![endif]--> 2788 text = text.replace(/<!\[[\s\S]*?\]>/ig, ""); // <! [if !vml]> 2789 text = text.replace(/<\\?\?xml[^>]*>/ig, ""); //<xml...>, </xml...> 2790 2791 text = text.replace(/<o:p>\s*<\/o:p>/ig, ""); 2792 2793 text = text.replace(/<\/?[a-z1-9]+:[^>]*>/gi, ""); //<o:p...>, </o:p> 2794 text = text.replace(/<([a-z1-9]+[^>]*) class=([^ |>]*)(.*?>)/gi, "<$1$3"); 2795 text = text.replace(/<([a-z1-9]+[^>]*) [a-z]+:[a-z]+=([^ |>]*)(.*?>)/gi, "<$1$3"); // xmlns:v="urn:schemas-microsoft-com:vml" 2796 2797 text = text.replace(/ /ig, ' '); 2798 text = text.replace(/\s+?/gi, ' '); 2799 2800 // Remove mso-xxx styles. 2801 text = text.replace(/\s*mso-[^:]+:[^;"]+;?/gi, ""); 2802 2803 // Remove margin styles. 2804 text = text.replace(/\s*margin: 0cm 0cm 0pt\s*;/gi, ""); 2805 text = text.replace(/\s*margin: 0cm 0cm 0pt\s*"/gi, "\""); 2806 2807 text = text.replace(/\s*TEXT-INDENT: 0cm\s*;/gi, ""); 2808 text = text.replace(/\s*TEXT-INDENT: 0cm\s*"/gi, "\""); 2809 2810 2811 text = text.replace(/\s*TEXT-ALIGN: [^\s;]+;?"/gi, "\""); 2812 text = text.replace(/\s*PAGE-BREAK-BEFORE: [^\s;]+;?"/gi, "\""); 2813 text = text.replace(/\s*FONT-VARIANT: [^\s;]+;?"/gi, "\""); 2814 text = text.replace(/\s*tab-stops:[^;"]*;?/gi, ""); 2815 text = text.replace(/\s*tab-stops:[^"]*/gi, ""); 2816 2817 text = text.replace(/<FONT[^>]*>([\s\S]*?)<\/FONT>/gi, '$1'); 2818 text = text.replace(/\s*face="[^"]*"/gi, ""); 2819 text = text.replace(/\s*face=[^ >]*/gi, ""); 2820 text = text.replace(/\s*FONT-FAMILY:[^;"]*;?/gi, ""); 2821 2822 // Remove Class attributes 2823 text = text.replace(/<(\w[^>]*) class=([^ |>]*)([^>]*)/gi, "<$1$3"); 2824 2825 // Remove styles. 2826 text = text.replace(/<(\w[^>]*) style="([^\"]*)"([^>]*)/gi, "<$1$3"); 2827 2828 // Remove empty styles. 2829 text = text.replace(/\s*style="\s*"/gi, ''); 2830 2831 // Remove Lang attributes 2832 text = text.replace(/<(\w[^>]*) lang=([^ |>]*)([^>]*)/gi, "<$1$3"); 2833 2834 var iter = 0; 2835 while (text.toLowerCase().indexOf('<span') != -1 && text.toLowerCase().indexOf('</span>') != -1 && iter++ < 20) 2836 text = text.replace(/<span[^>]*?>([\s\S]*?)<\/span>/gi, '$1'); 2837 2838 var 2839 _text, 2840 i, tag, arFormatTags = ['b', 'strong', 'i', 'u', 'font', 'span', 'strike']; 2841 2842 while (true) 2843 { 2844 _text = text; 2845 for (i in arFormatTags) 2846 { 2847 tag = arFormatTags[i]; 2848 text = text.replace(new RegExp('<' + tag + '[^>]*?>(\\s*?)<\\/' + tag + '>', 'gi'), '$1'); 2849 text = text.replace(new RegExp('<\\/' + tag + '[^>]*?>(\\s*?)<' + tag + '>', 'gi'), '$1'); 2850 } 2851 2852 if (_text == text) 2853 break; 2854 } 2855 2856 // Remove empty tags 2857 text = text.replace(/<(?:[^\s>]+)[^>]*>([\s\n\t\r]*)<\/\1>/g, "$1"); 2858 text = text.replace(/<(?:[^\s>]+)[^>]*>(\s*)<\/\1>/g, "$1"); 2859 text = text.replace(/<(?:[^\s>]+)[^>]*>(\s*)<\/\1>/g, "$1"); 2860 2861 //text = text.replace(/<\/?xml[^>]*>/gi, ""); //<xml...>, </xml...> 2862 text = text.replace(/<xml[^>]*?(?:>\s*?<\/xml)?(?:\/?)?>/ig, ''); 2863 text = text.replace(/<meta[^>]*?(?:>\s*?<\/meta)?(?:\/?)?>/ig, ''); 2864 text = text.replace(/<link[^>
2864]*?(?:>\s*?<\/link)?(?:\/?)?>/ig, ''); 2865 text = text.replace(/<style[\s\S]*?<\/style>/ig, ''); 2866 2867 text = text.replace(/<table([\s\S]*?)>/gi, "<table>"); 2868 text = text.replace(/<tr([\s\S]*?)>/gi, "<tr>"); 2869 text = text.replace(/(<td[\s\S]*?)width=("|')[\s\S]*?\2([\s\S]*?>)/gi, "$1$3"); 2870 text = text.replace(/(<td[\s\S]*?)height=("|')[\s\S]*?\2([\s\S]*?>)/gi, "$1$3"); 2871 text = text.replace(/(<td[\s\S]*?)style=("|')[\s\S]*?\2([\s\S]*?>)/gi, "$1$3"); 2872 text = text.replace(/(<td[\s\S]*?)valign=("|')[\s\S]*?\2([\s\S]*?>)/gi, "$1$3"); 2873 text = text.replace(/(<td[\s\S]*?)nowrap=("|')[\s\S]*?\2([\s\S]*?>)/gi, "$1$3"); 2874 text = text.replace(/(<td[\s\S]*?)nowrap([\s\S]*?>)/gi, "$1$3"); 2875 2876 text = text.replace(/(<col[\s\S]*?)width=("|')[\s\S]*?\2([\s\S]*?>)/gi, "$1$3"); 2877 text = text.replace(/(<col[\s\S]*?)style=("|')[\s\S]*?\2([\s\S]*?>)/gi, "$1$3"); 2878 2879 // For Opera (12.10+) only when in text we have reference links. 2880 if (BX.browser.IsOpera()) 2881 text = text.replace(/REF\s+?_Ref\d+?[\s\S]*?MERGEFORMAT\s([\s\S]*?)\s[\s\S]*?<\/xml>/gi, " $1 "); 2882 2883 return text; 2884} 2885}; 2886 2887BXLEditorUtils = function() 2888{ 2889 this.oTune = {}; 2890 this.setCurrentEditorId('default'); 2891}; 2892BXLEditorUtils.prototype = { 2893 setCurrentEditorId: function(id) 2894 { 2895 this.curId = id; 2896 }, 2897 2898 prepare : function() 2899 { 2900 if (!this.oTune[this.curId]) 2901 this.oTune[this.curId] = 2902 { 2903 buttons: [], 2904 ripButtons: {} 2905 }; 2906 }, 2907 2908 addButton : function(pBut, ind) 2909 { 2910 if (!pBut || !pBut.id) 2911 return false; 2912 if (typeof ind == 'undefined') 2913 ind = -1; 2914 2915 this.prepare(); 2916 this.oTune[this.curId].buttons.push({but: pBut, ind: ind}); 2917 2918 return true; 2919 }, 2920 2921 removeButton: function(id) 2922 { 2923 this.prepare(); 2924 this.oTune[this.curId].ripButtons[id] = true; 2925 } 2926}; 2927oBXLEditorUtils = new BXLEditorUtils(); 2928 2929function BXFindParentElement(pElement1, pElement2) 2930{ 2931 var p, arr1 = [], arr2 = []; 2932 while((pElement1 = pElement1.parentNode) != null) 2933 arr1[arr1.length] = pElement1; 2934 while((pElement2 = pElement2.parentNode) != null) 2935 arr2[arr2.length] = pElement2; 2936 2937 var min, diff1 = 0, diff2 = 0; 2938 if(arr1.length<arr2.length) 2939 { 2940 min = arr1.length; 2941 diff2 = arr2.length - min; 2942 } 2943 else 2944 { 2945 min = arr2.length; 2946 diff1 = arr1.length - min; 2947 } 2948 2949 for(var i=0; i<min-1; i++) 2950 { 2951 if(BXElementEqual(arr1[i+diff1], arr2[i+diff2])) 2952 return arr1[i+diff1]; 2953 } 2954 return arr1[0]; 2955} 2956 2957window.BXFindParentByTagName = function (pElement, tagName) 2958{ 2959 tagName = tagName.toUpperCase(); 2960 while(pElement && (pElement.nodeType !=1 || pElement.tagName.toUpperCase() != tagName)) 2961 pElement = pElement.parentNode; 2962 return pElement; 2963} 2964 2965 2966function SetAttr(pEl, attr, val) 2967{ 2968 if(attr=='className' && !BX.browser.IsIE()) 2969 attr = 'class'; 2970 2971 if(val.length <= 0) 2972 pEl.removeAttribute(attr); 2973 else 2974 pEl.setAttribute(attr, val); 2975} 2976 2977function BXCutNode(pNode) 2978{ 2979 while(pNode.childNodes.length > 0) 2980 pNode.parentNode.insertBefore(pNode.childNodes[0], pNode); 2981 2982 pNode.parentNode.removeChild(pNode); 2983}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.