]*>)\s*(<\/td>)/ig, "$1 $2");
if (this.arConfig.bReplaceTabToNbsp)
sContent = sContent.replace(/\t/ig, this.tabNbsp);
if (!BX.browser.IsIE())
{
sContent = sContent.replace(/]*>/ig, function(sContent)
{
return '';
}
);
}
for (var p in this.oSpecialParsers)
{
if (this.oSpecialParsers[p] && this.oSpecialParsers[p].Parse)
sContent = this.oSpecialParsers[p].Parse(p, sContent, this);
}
if (!bJustParse)
setTimeout(function(){
_this.AppendCSS(_this.systemCSS);
// Hack for chrome: we have to unset font family
// because than user paste text - chrome wraps it with [FONT=.....
setTimeout(function(){
_this.pEditorDocument.body.style.fontFamily = '';
_this.pEditorDocument.body.style.fontSize = '';
}, 1);
}, 300);
if (arCodes.length > 0) // Replace back CODE content without modifications
sContent = sContent.replace(/#BX_CODE(\d+)#/ig, function(s, num){return arCodes[num] || s;});
if (this.bBBCode)
{
sContent = sContent.replace(/[/ig, "[");
sContent = sContent.replace(/]/ig, "]");
}
sContent = BX.util.trim(sContent);
// Add in the end of the message if text not ends with
if (this.arConfig.bBBCode && !sContent.match(/( ]*>)$/ig))
sContent += ' ';
return sContent;
},
UnParseContent: function() // WYSIWYG - > html
{
BX.onCustomEvent(this, 'OnUnParseContent');
var sContent = this._RecursiveGetHTML(this._RecursiveDomWalker(this.pEditorDocument.body, false));
if (this.bBBCode)
{
if (!BX.browser.IsIE())
sContent = sContent.replace(/\r/ig, '');
sContent = sContent.replace(/\n/ig, '');
}
var arDivRules = [
['#BR#(#TAG_BEGIN#)', "$1"], // 111
... => 111<>
['(#TAG_BEGIN#)(?:#BR#)*?(#TAG_END#)', "$1$2"], // [DIV]#BR#[/DIV] ==> [DIV][/DIV]
['(#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], //
['^#TAG_BEGIN#', ""], //kill [DIV] in the begining of the text
['((?:\\s|\\S)*?(\\[\\/\\w+\\])*?)#TAG_BEGIN#((?:\\s|\\S)*?)#TAG_END#((?:\\s|\\S)*?)', function(str, s1, s2,s3,s4)
{
if (s2 && s2.toLowerCase && s2.toLowerCase() == '[/list]')
return s1 + s3 + '#BR#' + s4;
return s1 + '#BR#' + s3 + '#BR#' + s4;
}, true], // [/list][DIV]wwww[/div]wwww => [/list]wwww#BR#wwwww, text[DIV]wwww[/div]wwww => text#BR#www#BR#
['#TAG_END#', "#BR#"] // [/DIV] ==> \n
];
var re, i, l = arDivRules.length, str;
if (this.bBBCode)
{
//
if (BX.browser.IsOpera())
sContent = sContent.replace(/(?:#BR#)*?\[\/P\]/ig, "[/P]"); // #BR#[/P] ==> [/P] for opera
for (i = 0; i < l; i++)
{
re = arDivRules[i][0];
re = re.replace(/#TAG_BEGIN#/g, '\\[P\\]');
re = re.replace(/#TAG_END#/g, '\\[\\/P\\]');
re = re.replace(/\\\\/ig, '\\\\');
if (arDivRules[i][2] === true)
while(true)
{
str = sContent.replace(new RegExp(re, 'igm'), arDivRules[i][1]);
if (str == sContent)
break;
else
sContent = str;
}
else
sContent = sContent.replace(new RegExp(re, 'igm'), arDivRules[i][1]);
}
sContent = sContent.replace(/^((?:\s|\S)*?)(?:\n|\r|\s)+$/ig, "$1\n\n"); //kill multiple \n in the end
// Handle [DIV] tags from safari, chrome
for (i = 0; i < l; i++)
{
re = arDivRules[i][0];
re = re.replace(/#TAG_BEGIN#/g, '\\[DIV\\]');
re = re.replace(/#TAG_END#/g, '\\[\\/DIV\\]');
re = re.replace(/\\\\/ig, '\\\\');
if (arDivRules[i][2] === true)
while(true)
{
str = sContent.replace(new RegExp(re, 'igm'), arDivRules[i][1]);
if (str == sContent)
break;
else
sContent = str;
}
else
sContent = sContent.replace(new RegExp(re, 'igm'), arDivRules[i][1]);
}
sContent = sContent.replace(/#BR#/ig, "\n");
sContent = sContent.replace(/\[DIV]/ig, "");
sContent = BX.util.htmlspecialcharsback(sContent);
}
this.__sContent = sContent;
BX.onCustomEvent(this, 'OnUnParseContentAfter');
sContent = this.__sContent;
return sContent;
},
InitResizer: function()
{
this.oTransOverlay.Show();
var
_this = this,
coreContPos = BX.pos(this.pFrame),
newHeight = false;
var MouseMove = function(e)
{
e = e || window.event;
BX.fixEventPageY(e);
newHeight = e.pageY - coreContPos.top;
// New height
if (newHeight < _this.arConfig.minHeight)
{
newHeight = _this.arConfig.minHeight;
document.body.style.cursor = "not-allowed";
}
else if (newHeight > _this.arConfig.maxHeight)
{
newHeight = _this.arConfig.maxHeight;
document.body.style.cursor = "not-allowed";
}
else
{
document.body.style.cursor = "n-resize";
}
_this.pFrame.style.height = newHeight + "px";
_this.ResizeFrame(newHeight);
};
var MouseUp = function(e)
{
if (_this.arConfig.autoResizeSaveSize)
BX.userOptions.save('fileman', 'LHESize_' + _this.id, 'height', newHeight);
_this.arConfig.height = newHeight;
document.body.style.cursor = "";
if (_this.oTransOverlay && _this.oTransOverlay.bShowed)
_this.oTransOverlay.Hide();
BX.unbind(document, "mousemove", MouseMove);
BX.unbind(document, "mouseup", MouseUp);
};
BX.bind(document, "mousemove", MouseMove);
BX.bind(document, "mouseup", MouseUp);
},
AutoResize: function()
{
var
heightOffset = parseInt(this.arConfig.autoResizeOffset || 80),
maxHeight = parseInt(this.arConfig.autoResizeMaxHeight || 0),
minHeight = parseInt(this.arConfig.autoResizeMinHeight || 50),
newHeight,
_this = this;
if (this.autoResizeTimeout)
clearTimeout(this.autoResizeTimeout);
this.autoResizeTimeout = setTimeout(function()
{
if (_this.sEditorMode == 'html')
{
//newHeight = _this.pEditorDocument.body.offsetHeight + heightOffset;
newHeight = _this.pEditorDocument.body.offsetHeight;
var
body = _this.pEditorDocument.body,
node = body.lastChild,
offsetTop = false, i;
while (true)
{
if (!node)
break;
if (node.offsetTop)
{
offsetTop = node.offsetTop + (node.offsetHeight || 0);
newHeight = offsetTop + heightOffset;
break;
}
else
{
node = node.previousSibling;
}
}
var oEdSize = BX.GetWindowSize(_this.pEditorDocument);
if (oEdSize.scrollHeight - oEdSize.innerHeight > 5)
newHeight = Math.max(oEdSize.scrollHeight + heightOffset, newHeight);
}
else
{
newHeight = (_this.pTextarea.value.split("\n").length /* rows count*/ + 5) * 17;
}
if (newHeight > parseInt(_this.arConfig.height))
{
if (BX.browser.IsIOS())
maxHeight = Infinity;
else if (!maxHeight || maxHeight < 10)
maxHeight = Math.round(BX.GetWindowInnerSize().innerHeight * 0.9); // 90% from screen height
newHeight = Math.min(newHeight, maxHeight);
newHeight = Math.max(newHeight, minHeight);
_this.SmoothResizeFrame(newHeight);
}
}, 300);
},
MousePos: function (e)
{
if(window.event)
e = window.event;
if(e.pageX || e.pageY)
{
e.realX = e.pageX;
e.realY = e.pageY;
}
else if(e.clientX || e.clientY)
{
e.realX = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) - document.documentElement.clientLeft;
e.realY = e.clientY + (document.documentElement.scrollTop || document.body.scrollTop) - document.documentElement.clientTop;
}
return e;
},
SmoothResizeFrame: function(height)
{
var
_this = this,
curHeight = parseInt(this.pFrame.offsetHeight),
count = 0,
bRise = height > curHeight,
timeInt = BX.browser.IsIE() ? 50 : 50,
dy = 5;
if (!bRise)
return;
if (this.smoothResizeInterval)
clearInterval(this.smoothResizeInterval);
this.smoothResizeInterval = setInterval(function()
{
if (bRise)
{
curHeight += Math.round(dy * count);
if (curHeight > height)
{
clearInterval(_this.smoothResizeInterval);
if (curHeight > height)
curHeight = height;
}
}
else
{
curHeight -= Math.round(dy * count);
if (curHeight < height)
{
curHeight = height;
clearInterval(_this.smoothResizeInterval);
}
}
_this.pFrame.style.height = curHeight + "px";
_this.ResizeFrame(curHeight);
count++;
},
timeInt
);
},
ResizeFrame: function(newHeight)
{
var
deltaWidth = 7,
resizeHeight = this.arConfig.bManualResize ? 3 : 0, // resize row
height = newHeight || parseInt(this.pFrame.offsetHeight),
width = this.pFrame.offsetWidth;
this.pFrameTable.style.height = height + 'px';
var contHeight = height - this.buttonsHeight - resizeHeight;
if (contHeight > 0)
{
this.pEditCont.style.height = contHeight + 'px';
this.pTextarea.style.height = contHeight + 'px';
}
this.pTextarea.style.width = (width > deltaWidth) ? (width - deltaWidth) + 'px' : 'auto';
this.pButtonsCell.style.height = this.buttonsHeight + 'px';
/*if (this.arConfig.bResizable)
this.pResizer.parentNode.style.height = resizeHeight + 'px';*/
},
AddButtons: function()
{
var
i, l, butId, grInd, arButtons,
toolbarConfig = this.arConfig.toolbarConfig;
this.buttonsCount = 0;
if(!toolbarConfig)
toolbarConfig = [
//'Source',
'Bold', 'Italic', 'Underline', 'Strike', 'RemoveFormat', 'InsertHR',
'Anchor',
'CreateLink', 'DeleteLink', 'Image', //'SpecialChar',
'Justify',
'InsertOrderedList', 'InsertUnorderedList', 'Outdent', 'Indent',
'BackColor', 'ForeColor',
'Video',
'StyleList', 'HeaderList',
'FontList', 'FontSizeList',
'Table'
//smiles:['SmileList']
];
if (oBXLEditorUtils.oTune && oBXLEditorUtils.oTune[this.id])
{
var
ripButtons = oBXLEditorUtils.oTune[this.id].ripButtons,
addButtons = oBXLEditorUtils.oTune[this.id].buttons;
if (ripButtons)
{
i = 0;
while(i < toolbarConfig.length)
{
if (ripButtons[toolbarConfig[i]])
toolbarConfig = BX.util.deleteFromArray(toolbarConfig, i);
else
i++;
}
}
if (addButtons)
{
for (var j = 0, n = addButtons.length; j < n; j++)
{
if (addButtons[j].ind == -1 || addButtons[j].ind >= toolbarConfig.length)
toolbarConfig.push(addButtons[j].but.id);
else
toolbarConfig = BX.util.insertIntoArray(toolbarConfig, addButtons[j].ind, addButtons[j].but.id);
}
}
}
var
begWidth = 0,
endWidth = 0, // 4
curLineWidth = begWidth, pCont,
butContWidth = parseInt(this.pButtonsCont.offsetWidth);
this.ToolbarStartLine(true);
for(i in toolbarConfig)
{
butId = toolbarConfig[i];
if (typeof butId != 'string')
continue;
if (butId == '=|=')
{
this.ToolbarNewLine();
curLineWidth = begWidth;
}
else if (LHEButtons[butId])
{
this.buttonsIndex[butId] = i;
pCont = this.AddButton(LHEButtons[butId], butId);
if (pCont)
{
curLineWidth += parseInt(pCont.style.width) || 23;
if (curLineWidth + endWidth > butContWidth && butContWidth > 0)
{
butContWidth = parseInt(this.pButtonsCont.offsetWidth); // Doublecheck
if (curLineWidth + endWidth > butContWidth && butContWidth > 0)
{
this.ToolbarNewLine();
this.pButtonsCont.appendChild(pCont);
curLineWidth = begWidth;
}
}
}
}
}
this.ToolbarEndLine();
if (typeof this.arConfig.controlButtonsHeight == 'undefined')
this.buttonsHeight = this.toolbarLineCount * 27;
else
this.buttonsHeight = parseInt(this.arConfig.controlButtonsHeight || 0);
this.arConfig.minHeight += this.buttonsHeight;
this.arConfig.maxHeight += this.buttonsHeight;
BX.addCustomEvent(this, 'onShow', BX.proxy(this.ResizeFrame, this));
},
AddButton: function(oBut, buttonId)
{
if (oBut.parser && oBut.parser.obj)
this.oSpecialParsers[oBut.parser.name] = oBut.parser.obj;
this.buttonsCount++;
var result;
if (!oBut.type || !oBut.type == 'button')
{
if (buttonId == 'Code')
this.bCodeBut = true;
var pButton = new window.LHEButton(oBut, this);
if (pButton && pButton.oBut)
{
if (buttonId == 'Source')
this.sourseBut = pButton;
else if(buttonId == 'Quote')
this.quoteBut = pButton;
result = this.pButtonsCont.appendChild(pButton.pCont);
}
}
else if (oBut.type == 'Colorpicker')
{
var pColorpicker = new window.LHEColorPicker(oBut, this);
result = this.pButtonsCont.appendChild(pColorpicker.pCont);
}
else if (oBut.type == 'List')
{
var pList = new window.LHEList(oBut, this);
result = this.pButtonsCont.appendChild(pList.pCont);
}
if (oBut.parsers)
{
for(var i = 0, cnt = oBut.parsers.length; i < cnt; i++)
if (oBut.parsers[i] && oBut.parsers[i].obj)
this.oSpecialParsers[oBut.parsers[i].name] = oBut.parsers[i].obj;
}
return result;
},
AddParser: function(parser)
{
if (parser && parser.name && typeof parser.obj == 'object')
this.oSpecialParsers[parser.name] = parser.obj;
},
ToolbarStartLine: function(bFirst)
{
// Hack for IE 7
if (!bFirst && BX.browser.IsIE())
this.pButtonsCont.appendChild(BX.create("IMG", {props: {src: this.oneGif, className: "lhe-line-ie"}}));
this.pButtonsCont.appendChild(BX.create("DIV", {props: {className: 'lhe-line-begin'}}));
},
ToolbarEndLine: function()
{
this.pButtonsCont.appendChild(BX.create("DIV", {props: {className: 'lhe-line-end'}}));
},
ToolbarNewLine: function()
{
this.toolbarLineCount++;
this.ToolbarEndLine();
this.ToolbarStartLine();
},
OpenDialog: function(arParams)
{
var oDialog = new window.LHEDialog(arParams, this);
},
GetSelectionObject: function()
{
var oSelection, oRange, root;
if(this.pEditorDocument.selection) // IE
{
oSelection = this.pEditorDocument.selection;
oRange = oSelection.createRange();
if(oSelection.type=="Control")
return oRange.commonParentElement();
return oRange.parentElement();
}
else // FF
{
oSelection = this.pEditorWindow.getSelection();
if(!oSelection)
return false;
var container, i, rangeCount = oSelection.rangeCount, obj;
for(var i = 0; i < rangeCount; i++)
{
oRange = oSelection.getRangeAt(i);
container = oRange.startContainer;
if(container.nodeType != 3)
{
if(container.nodeType == 1 && container.childNodes.length <= 0)
obj = container;
else
obj = container.childNodes[oRange.startOffset];
}
else
{
temp = oRange.commonAncestorContainer;
while(temp && temp.nodeType == 3)
temp = temp.parentNode;
obj = temp;
}
root = (i == 0) ? obj : BXFindParentElement(root, obj);
}
return root;
}
},
GetSelectionObjects: function()
{
var oSelection;
if(this.pEditorDocument.selection) // IE
{
oSelection = this.pEditorDocument.selection;
var s = oSelection.createRange();
if(oSelection.type=="Control")
return s.commonParentElement();
return s.parentElement();
}
else // FF
{
oSelection = this.pEditorWindow.getSelection();
if(!oSelection)
return false;
var oRange;
var container, temp;
var res = [];
for(var i = 0; i < oSelection.rangeCount; i++)
{
oRange = oSelection.getRangeAt(i);
container = oRange.startContainer;
if(container.nodeType != 3)
{
if(container.nodeType == 1 && container.childNodes.length <= 0)
res[res.length] = container;
else
res[res.length] = container.childNodes[oRange.startOffset];
}
else
{
temp = oRange.commonAncestorContainer;
while(temp && temp.nodeType == 3)
temp = temp.parentNode;
res[res.length] = temp;
}
}
if(res.length > 1)
return res;
return res[0];
}
},
GetSelectionRange: function(doc, win)
{
try{
var
oDoc = doc || this.pEditorDocument,
oWin = win || this.pEditorWindow,
oRange,
oSel = this.GetSelection(oDoc, oWin);
if (oSel)
{
if (oDoc.createRange)
{
if (oSel.getRangeAt)
oRange = oSel.getRangeAt(0);
else
{
oRange = document.createRange();
oRange.setStart(oSel.anchorNode, oSel.anchorOffset);
oRange.setEnd(oSel.focusNode, oSel.focusOffset);
}
}
else
oRange = oSel.createRange();
}
else
{
oRange = false;
}
} catch(e) {oRange = false;}
return oRange;
},
SelectRange: function(oRange, doc, win)
{
try{ // IE9 sometimes generete JS error
if (!oRange)
return;
var
oDoc = doc || this.pEditorDocument,
oWin = win || this.pEditorWindow;
this.ClearSelection(oDoc, oWin);
if (oDoc.createRange) // FF
{
var oSel = oWin.getSelection();
oSel.removeAllRanges();
oSel.addRange(oRange);
}
else //IE
{
oRange.select();
}
}catch(e){}
},
SelectElement: function(pElement)
{
try{
var
oRange,
oDoc = this.pEditorDocument,
oWin = this.pEditorWindow;
if(oWin.getSelection)
{
var oSel = oWin.getSelection();
oSel.selectAllChildren(pElement);
oRange = oSel.getRangeAt(0);
if (oRange.selectNode)
oRange.selectNode(pElement);
}
else
{
oDoc.selection.empty();
oRange = oDoc.selection.createRange();
oRange.moveToElementText(pElement);
oRange.select();
}
return oRange;
}catch(e){}
},
GetSelectedText: function(oRange)
{
// Get selected text
var selectedText = '';
if (oRange.startContainer && oRange.endContainer) // DOM Model
{
if (oRange.startContainer == oRange.endContainer && (oRange.endContainer.nodeType == 3 || oRange.endContainer.nodeType == 1))
selectedText = oRange.startContainer.textContent.substring(oRange.startOffset, oRange.endOffset);
}
else // IE
{
if (oRange.text == oRange.htmlText)
selectedText = oRange.text;
}
return selectedText || '';
},
ClearSelection: function(doc, win)
{
var
oDoc = doc || this.pEditorDocument,
oWin = win || this.pEditorWindow;
if (oWin.getSelection)
oWin.getSelection().removeAllRanges();
else
oDoc.selection.empty();
},
GetSelection: function(oDoc, oWin)
{
if (!oDoc)
oDoc = document;
if (!oWin)
oWin = window;
var oSel = false;
if (oWin.getSelection)
oSel = oWin.getSelection();
else if (oDoc.getSelection)
oSel = oDoc.getSelection();
else if (oDoc.selection)
oSel = oDoc.selection;
return oSel;
},
InsertHTML: function(sContent)
{
try{ // Don't clear try... Some times browsers generetes failures
this.SetFocus();
if(BX.browser.IsIE())
{
var oRng = this.pEditorDocument.selection.createRange();
if (oRng.pasteHTML)
{
oRng.pasteHTML(sContent);
oRng.collapse(false);
oRng.select();
}
}
else
{
this.pEditorWindow.document.execCommand('insertHTML', false, sContent);
}
}catch(e){}
if (this.arConfig.bAutoResize && this.arConfig.bResizable)
this.AutoResize();
},
AppendCSS: function(styles)
{
styles = BX.util.trim(styles);
if (styles.length <= 0)
return false;
var
pDoc = this.pEditorDocument,
pHeads = pDoc.getElementsByTagName("HEAD");
if(pHeads.length != 1)
return false;
if(BX.browser.IsIE())
{
setTimeout(function()
{
try{
if (pDoc.styleSheets.length == 0)
pHeads[0].appendChild(pDoc.createElement("STYLE"));
pDoc.styleSheets[0].cssText += styles;
}catch(e){}
}, 100);
}
else
{
try{
var xStyle = pDoc.createElement("STYLE");
pHeads[0].appendChild(xStyle);
xStyle.appendChild(pDoc.createTextNode(styles));
}catch(e){}
}
return true;
},
SetBxTag: function(pElement, params)
{
var id;
if (params.id || pElement && pElement.id)
id = params.id || pElement.id;
if (!id)
id = 'bxid_' + Math.round(Math.random() * 1000000);
else if (this.bxTags[id] && !params.tag)
params.tag = this.bxTags[id].tag;
params.id = id;
if (pElement)
pElement.id = params.id;
this.bxTags[params.id] = params;
return params.id;
},
GetBxTag: function(id)
{
if (id)
{
if (typeof id != "string" && id.id)
id = id.id;
if (id && id.length > 0 && this.bxTags[id] && this.bxTags[id].tag)
{
this.bxTags[id].tag = this.bxTags[id].tag.toLowerCase();
return this.bxTags[id];
}
}
return {tag: false};
},
GetAttributesList: function(str)
{
str = str + " ";
var arParams = {}, arPHP = [], bPhp = false, _this = this;
// 1. Replace PHP by #BXPHP#
str = str.replace(/<\?.*?\?>/ig, function(s)
{
arPHP.push(s);
return "#BXPHP" + (arPHP.length - 1) + "#";
});
// 2.0 Parse params - without quotes
str = str.replace(/([^\w]??)(\w+?)=([^\s\'"]+?)(\s)/ig, function(s, b0, b1, b2, b3)
{
b2 = b2.replace(/#BXPHP(\d+)#/ig, function(s, num){return arPHP[num] || s;});
arParams[b1.toLowerCase()] = BX.util.htmlspecialcharsback(b2);
return b0;
});
// 2.1 Parse params
str = str.replace(/([^\w]??)(\w+?)\s*=\s*("|\')([^\3]*?)\3/ig, function(s, b0, b1, b2, b3)
{
// 3. Replace PHP back
b3 = b3.replace(/#BXPHP(\d+)#/ig, function(s, num){return arPHP[num] || s;});
arParams[b1.toLowerCase()] = BX.util.htmlspecialcharsback(b3);
return b0;
});
return arParams;
},
RidOfNode: function (pNode, bHard)
{
if (!pNode || pNode.nodeType != 1)
return;
var i, nodeName = pNode.tagName.toLowerCase(),
nodes = ['span', 'strike', 'del', 'font', 'code', 'div'];
if (BX.util.in_array(nodeName, nodes)) // Check node names
{
if (bHard !== true)
{
for (i = pNode.attributes.length - 1; i >= 0; i--)
{
if (BX.util.trim(pNode.getAttribute(pNode.attributes[i].nodeName.toLowerCase())) != "")
return false; // Node have attributes, so we cant get rid of it without loosing info
}
}
var arNodes = pNode.childNodes;
while(arNodes.length > 0)
pNode.parentNode.insertBefore(arNodes[0], pNode);
pNode.parentNode.removeChild(pNode);
//this.OnEvent("OnSelectionChange");
return true;
}
return false;
},
WrapSelectionWith: function (tagName, arAttributes)
{
this.SetFocus();
var oRange, oSelection;
if (!tagName)
tagName = 'SPAN';
var sTag = 'FONT', i, pEl, arTags, arRes = [];
try{this.pEditorDocument.execCommand("styleWithCSS", false, false);}catch(e){}
this.executeCommand("FontName", "bitrixtemp");
arTags = this.pEditorDocument.getElementsByTagName(sTag);
for(i = arTags.length - 1; i >= 0; i--)
{
if (arTags[i].getAttribute('face') != 'bitrixtemp')
continue;
pEl = BX.create(tagName, arAttributes, this.pEditorDocument);
arRes.push(pEl);
while(arTags[i].firstChild)
pEl.appendChild(arTags[i].firstChild);
arTags[i].parentNode.insertBefore(pEl, arTags[i]);
arTags[i].parentNode.removeChild(arTags[i]);
}
if (this.arConfig.bAutoResize && this.arConfig.bResizable)
this.AutoResize();
return arRes;
},
SaveSelectionRange: function()
{
if (this.sEditorMode == 'code')
this.oPrevRangeText = this.GetSelectionRange(document, window);
else
this.oPrevRange = this.GetSelectionRange();
},
RestoreSelectionRange: function()
{
if (this.sEditorMode == 'code')
this.IESetCarretPos(this.oPrevRangeText);
else if(this.oPrevRange)
this.SelectRange(this.oPrevRange);
},
focus: function(el, bSelect)
{
setTimeout(function()
{
try{
el.focus();
if(bSelect)
el.select();
}catch(e){}
}, 100);
},
// Methods below used in BB-mode
// Earlier was in bb.js
InitBBCode: function()
{
this.stack = [];
var _this = this;
this.pTextarea.onkeydown = BX.proxy(this.OnKeyDownBB, this);
// Backup parser functions
this._GetNodeHTMLLeft = this.GetNodeHTMLLeft;
this._GetNodeHTMLRight = this.GetNodeHTMLRight;
this.GetNodeHTMLLeft = this.GetNodeHTMLLeftBB;
this.GetNodeHTMLRight = this.GetNodeHTMLRightBB;
},
ShutdownBBCode: function()
{
this.bBBCode = false;
this.arConfig.bBBCode = false;
this.pTextarea.onkeydown = null;
// Restore parser functions
this.GetNodeHTMLLeft = this._GetNodeHTMLLeft;
this.GetNodeHTMLRight = this._GetNodeHTMLRight;
this.arConfig.bConvertContentFromBBCodes = false;
},
FormatBB: function(params)
{
var
pBut = params.pBut,
value = params.value,
tag = params.tag.toUpperCase(),
tag_end = tag;
if (tag == 'FONT' || tag == 'COLOR' || tag == 'SIZE')
tag += "=" + value;
if ((!BX.util.in_array(tag, this.stack) || this.GetTextSelection()) && !(tag == 'FONT' && value == 'none'))
{
if (!this.WrapWith("[" + tag + "]", "[/" + tag_end + "]"))
{
this.stack.push(tag);
if (pBut && pBut.Check)
pBut.Check(true);
}
}
else
{
var res = false;
while (res = this.stack.pop())
{
this.WrapWith("[/" + res + "]", "");
if (pBut && pBut.Check)
pBut.Check(false);
if (res == tag)
break;
}
}
},
GetTextSelection: function()
{
var res = false;
if (typeof this.pTextarea.selectionStart != 'undefined')
{
res = this.pTextarea.value.substr(this.pTextarea.selectionStart, this.pTextarea.selectionEnd - this.pTextarea.selectionStart);
}
else if (document.selection && document.selection.createRange)
{
res = document.selection.createRange().text;
}
else if (window.getSelection)
{
res = window.getSelection();
res = res.toString();
}
return res;
},
IESetCarretPos: function(oRange)
{
if (!oRange || !BX.browser.IsIE() || oRange.text.length != 0 /* text selected*/)
return;
oRange.moveStart('character', - this.pTextarea.value.length);
var pos = oRange.text.length;
var range = this.pTextarea.createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
},
WrapWith: function (tagBegin, tagEnd, postText)
{
if (!tagBegin)
tagBegin = "";
if (!tagEnd)
tagEnd = ""
if (!postText)
postText = "";
if (tagBegin.length <= 0 && tagEnd.length <= 0 && postText.length <= 0)
return true;
var bReplaceText = !!postText;
var sSelectionText = this.GetTextSelection();
if (!this.bTextareaFocus)
this.pTextarea.focus(); // BUG IN IE
var isSelect = (sSelectionText ? 'select' : bReplaceText ? 'after' : 'in');
if (bReplaceText)
postText = tagBegin + postText + tagEnd;
else if (sSelectionText)
postText = tagBegin + sSelectionText + tagEnd;
else
postText = tagBegin + tagEnd;
if (typeof this.pTextarea.selectionStart != 'undefined')
{
var
currentScroll = this.pTextarea.scrollTop,
start = this.pTextarea.selectionStart,
end = this.pTextarea.selectionEnd;
this.pTextarea.value = this.pTextarea.value.substr(0, start) + postText + this.pTextarea.value.substr(end);
if (isSelect == 'select')
{
this.pTextarea.selectionStart = start;
this.pTextarea.selectionEnd = start + postText.length;
}
else if (isSelect == 'in')
{
this.pTextarea.selectionStart = this.pTextarea.selectionEnd = start + tagBegin.length;
}
else
{
this.pTextarea.selectionStart = this.pTextarea.selectionEnd = start + postText.length;
}
this.pTextarea.scrollTop = currentScroll;
}
else if (document.selection && document.selection.createRange)
{
var sel = document.selection.createRange();
var selection_copy = sel.duplicate();
postText = postText.replace(/\r?\n/g, '\n');
sel.text = postText;
sel.setEndPoint('StartToStart', selection_copy);
sel.setEndPoint('EndToEnd', selection_copy);
if (isSelect == 'select')
{
sel.collapse(true);
postText = postText.replace(/\r\n/g, '1');
sel.moveEnd('character', postText.length);
}
else if (isSelect == 'in')
{
sel.collapse(false);
sel.moveEnd('character', tagBegin.length);
sel.collapse(false);
}
else
{
sel.collapse(false);
sel.moveEnd('character', postText.length);
sel.collapse(false);
}
sel.select();
}
else
{
// failed - just stuff it at the end of the message
this.pTextarea.value += postText;
}
return true;
},
ParseBB: function (sContent) // BBCode -> WYSIWYG
{
sContent = BX.util.htmlspecialchars(sContent);
// Table
sContent = sContent.replace(/[\r\n\s\t]?\[table\][\r\n\s\t]*?\[tr\]/ig, '[TABLE][TR]');
sContent = sContent.replace(/\[tr\][\r\n\s\t]*?\[td\]/ig, '[TR][TD]');
sContent = sContent.replace(/\[tr\][\r\n\s\t]*?\[th\]/ig, '[TR][TH]');
sContent = sContent.replace(/\[\/td\][\r\n\s\t]*?\[td\]/ig, '[/TD][TD]');
sContent = sContent.replace(/\[\/tr\][\r\n\s\t]*?\[tr\]/ig, '[/TR][TR]');
sContent = sContent.replace(/\[\/td\][\r\n\s\t]*?\[\/tr\]/ig, '[/TD][/TR]');
sContent = sContent.replace(/\[\/th\][\r\n\s\t]*?\[\/tr\]/ig, '[/TH][/TR]');
sContent = sContent.replace(/\[\/tr\][\r\n\s\t]*?\[\/table\][\r\n\s\t]?/ig, '[/TR][/TABLE]');
// List
sContent = sContent.replace(/[\r\n\s\t]*?\[\/list\]/ig, '[/LIST]');
sContent = sContent.replace(/[\r\n\s\t]*?\[\*\]?/ig, '[*]');
var
arSimpleTags = [
'b','u', 'i', ['s', 'del'], // B, U, I, S
'table', 'tr', 'td', 'th'//, // Table
],
bbTag, tag, i, l = arSimpleTags.length, re;
for (i = 0; i < l; i++)
{
if (typeof arSimpleTags[i] == 'object')
{
bbTag = arSimpleTags[i][0];
tag = arSimpleTags[i][1];
}
else
{
bbTag = tag = arSimpleTags[i];
}
sContent = sContent.replace(new RegExp('\\[(\\/?)' + bbTag + '\\]', 'ig'), "<$1" + tag + ">");
}
// Link
sContent = sContent.replace(/\[url\]((?:\s|\S)*?)\[\/url\]/ig, "$1");
sContent = sContent.replace(/\[url\s*=\s*((?:[^\[\]]*?(?:\[[^\]]+?\])*[^\[\]]*?)*)\s*\]((?:\s|\S)*?)\[\/url\]/ig, "$2");
// Img
var _this = this;
sContent = sContent.replace(/\[img(?:\s*?width=(\d+)\s*?height=(\d+))?\]((?:\s|\S)*?)\[\/img\]/ig,
function(str, w, h, src)
{
var strSize = "";
w = parseInt(w);
h = parseInt(h);
if (w && h && _this.bBBParseImageSize)
strSize = ' width="' + w + '" height="' + h + '"';
return '';
}
);
// Font color
i = 0;
while (sContent.toLowerCase().indexOf('[color=') != -1 && sContent.toLowerCase().indexOf('[/color]') != -1 && i++ < 20)
sContent = sContent.replace(/\[color=((?:\s|\S)*?)\]((?:\s|\S)*?)\[\/color\]/ig, "$2");
// List
i = 0;
while (sContent.toLowerCase().indexOf('[list=') != -1 && sContent.toLowerCase().indexOf('[/list]') != -1 && i++ < 20)
sContent = sContent.replace(/\[list=1\]((?:\s|\S)*?)\[\/list\]/ig, "$1");
i = 0;
while (sContent.toLowerCase().indexOf('[list') != -1 && sContent.toLowerCase().indexOf('[/list]') != -1 && i++ < 20)
sContent = sContent.replace(/\[list\]((?:\s|\S)*?)\[\/list\]/ig, "
$1
");
sContent = sContent.replace(/\[\*\]/ig, "
");
// Font
i = 0;
while (sContent.toLowerCase().indexOf('[font=') != -1 && sContent.toLowerCase().indexOf('[/font]') != -1 && i++ < 20)
sContent = sContent.replace(/\[font=((?:\s|\S)*?)\]((?:\s|\S)*?)\[\/font\]/ig, "$2");
// Font size
i = 0;
while (sContent.toLowerCase().indexOf('[size=') != -1 && sContent.toLowerCase().indexOf('[/size]') != -1 && i++ < 20)
sContent = sContent.replace(/\[size=((?:\s|\S)*?)\]((?:\s|\S)*?)\[\/size\]/ig, "$2");
// Replace \n =>
sContent = sContent.replace(/\n/ig, " ");
return sContent;
},
UnParseNodeBB: function (pNode) // WYSIWYG -> BBCode
{
if (pNode.text == "br")
return "#BR#";
if (pNode.type == 'text')
return false;
//[CODE] Handle code tag
if (pNode.text == "pre" && pNode.arAttributes['class'] == 'lhe-code')
return "[CODE]" + this.RecGetCodeContent(pNode) + "[/CODE]";
pNode.bbHide = true;
if (pNode.text == 'font' && pNode.arAttributes.color)
{
pNode.bbHide = false;
pNode.text = 'color';
pNode.bbValue = pNode.arAttributes.color;
}
else if (pNode.text == 'font' && pNode.arAttributes.size)
{
pNode.bbHide = false;
pNode.text = 'size';
pNode.bbValue = pNode.arAttributes.size;
}
else if (pNode.text == 'font' && pNode.arAttributes.face)
{
pNode.bbHide = false;
pNode.text = 'font';
pNode.bbValue = pNode.arAttributes.face;
}
else if(pNode.text == 'del')
{
pNode.bbHide = false;
pNode.text = 's';
}
else if(pNode.text == 'strong' || pNode.text == 'b')
{
pNode.bbHide = false;
pNode.text = 'b';
}
else if(pNode.text == 'em' || pNode.text == 'i')
{
pNode.bbHide = false;
pNode.text = 'i';
}
else if(pNode.text == 'blockquote')
{
pNode.bbHide = false;
pNode.text = 'quote';
}
else if(pNode.text == 'ol')
{
pNode.bbHide = false;
pNode.text = 'list';
pNode.bbBreakLineRight = true;
pNode.bbValue = '1';
}
else if(pNode.text == 'ul')
{
pNode.bbHide = false;
pNode.text = 'list';
pNode.bbBreakLineRight = true;
}
else if(pNode.text == 'li')
{
pNode.bbHide = false;
pNode.text = '*';
pNode.bbBreakLine = true;
pNode.bbHideRight = true;
}
else if(pNode.text == 'a')
{
pNode.bbHide = false;
pNode.text = 'url';
pNode.bbValue = pNode.arAttributes.href;
}
else if(this.parseAlign
&&
(pNode.arAttributes.align || pNode.arStyle.textAlign)
&&
!(BX.util.in_array(pNode.text.toLowerCase(), ['table', 'tr', 'td', 'th']))
)
{
var align = pNode.arStyle.textAlign || pNode.arAttributes.align;
if (BX.util.in_array(align, ['left', 'right', 'center', 'justify']))
{
pNode.bbHide = false;
pNode.text = align;
}
else
{
pNode.bbHide = !BX.util.in_array(pNode.text, this.arBBTags);
}
}
else if(BX.util.in_array(pNode.text, this.arBBTags)) //'p', 'u', 'div', 'table', 'tr', 'img', 'td', 'a'
{
pNode.bbHide = false;
}
return false;
},
RecGetCodeContent: function(pNode) // WYSIWYG -> BBCode
{
if (!pNode || !pNode.arNodes || !pNode.arNodes.length)
return '';
var res = '';
for (var i = 0; i < pNode.arNodes.length; i++)
{
if (pNode.arNodes[i].type == 'text')
res += pNode.arNodes[i].text;
else if (pNode.arNodes[i].type == 'element' && pNode.arNodes[i].text == "br")
res += (this.bBBCode ? "#BR#" : "\n");
else if (pNode.arNodes[i].arNodes)
res += this.RecGetCodeContent(pNode.arNodes[i]);
}
if (this.bBBCode)
{
if (BX.browser.IsIE())
res = res.replace(/\r/ig, "#BR#");
else
res = res.replace(/\n/ig, "#BR#");
}
else if (BX.browser.IsIE())
{
res = res.replace(/\n/ig, "\r\n");
}
return res;
},
GetNodeHTMLLeftBB: function (pNode)
{
if(pNode.type == 'text')
{
var text = BX.util.htmlspecialchars(pNode.text);
text = text.replace(/\[/ig, "[");
text = text.replace(/\]/ig, "]");
return text;
}
var res = "";
if (pNode.bbBreakLine)
res += "\n";
if(pNode.type == 'element' && !pNode.bbHide)
{
res += "[" + pNode.text.toUpperCase();
if (pNode.bbValue)
res += '=' + pNode.bbValue;
res += "]";
}
return res;
},
GetNodeHTMLRightBB: function (pNode)
{
var res = "";
if (pNode.bbBreakLineRight)
res += "\n";
if(pNode.type == 'element' && (pNode.arNodes.length > 0 || this.IsPairNode(pNode.text)) && !pNode.bbHide && !pNode.bbHideRight)
res += "[/" + pNode.text.toUpperCase() + "]";
return res;
},
OptimizeBB: function (str)
{
// TODO: kill links without text and names
// TODO: Kill multiple line ends
var
iter = 0,
bReplasing = true,
arTags = ['b', 'i', 'u', 's', 'color', 'font', 'size', 'quote'],
replaceEmptyTags = function(){i--; bReplasing = true; return ' ';},
re, tagName, i, l;
while(iter++ < 20 && bReplasing)
{
bReplasing = false;
for (i = 0, l = arTags.length; i < l; i++)
{
tagName = arTags[i];
// Replace empties: [b][/b] ==> ""
re = new RegExp('\\[' + tagName + '[^\\]]*?\\]\\s*?\\[/' + tagName + '\\]', 'ig');
str = str.replace(re, replaceEmptyTags);
if (tagName !== 'quote')
{
re = new RegExp('\\[((' + tagName + '+?)(?:\\s+?[^\\]]*?)?)\\]([\\s\\S]+?)\\[\\/\\2\\](\\s*?)\\[\\1\\]([\\s\\S]+?)\\[\\/\\2\\]', 'ig');
str = str.replace(re, function(str, b1, b2, b3, spacer, b4)
{
if (spacer.indexOf("\n") != -1)
return str;
bReplasing = true;
return '[' + b1 + ']' + b3 + ' ' + b4 + '[/' + b2 + ']';
}
);
//Replace [b]1 [b]2[/b] 3[/b] ===>> [b]1 2 3[/b]
// re = new RegExp('(\\[' + tagName + '(?:\\s+?[^\\]]*?)?\\])([\\s\\S]+?)\\1([\\s\\S]+?)(\\[\\/' + tagName + '\\])([\\s\\S]+?)\\4', 'ig');
// str = str.replace(re, function(str, b1, b2, b3, b4, b5)
// {
// bReplasing = true;
// return b1 + b2 + b3 + b5 + b4;
// }
// );
}
}
}
//
str = str.replace(/[\r\n\s\t]*?\[\/list\]/ig, "\n[/LIST]");
str = str.replace(/[\r\n\s\t]*?\[\/list\]/ig, "\n[/LIST]");
// Cut "\n" in the end of the message (only for BB)
str = str.replace(/\n*$/ig, '');
return str;
},
RemoveFormatBB: function()
{
var str = this.GetTextSelection();
if (str)
{
var
it = 0,
arTags = ['b', 'i', 'u', 's', 'color', 'font', 'size'],
i, l = arTags.length;
//[b]123[/b] ==> 123
while (it < 30)
{
str1 = str;
for (i = 0; i < l; i++)
str = str.replace(new RegExp('\\[(' + arTags[i] + ')[^\\]]*?\\]([\\s\\S]*?)\\[/\\1\\]', 'ig'), "$2");
if (str == str1)
break;
it++;
}
this.WrapWith('', '', str);
}
},
OnKeyDownBB: function(e)
{
if(!e) e = window.event;
var key = e.which || e.keyCode;
if (e.ctrlKey && !e.shiftKey && !e.altKey)
{
switch (key)
{
case 66 : // B
case 98 : // b
this.FormatBB({tag: 'B'});
return BX.PreventDefault(e);
case 105 : // i
case 73 : // I
this.FormatBB({tag: 'I'});
return BX.PreventDefault(e);
case 117 : // u
case 85 : // U
this.FormatBB({tag: 'U'});
return BX.PreventDefault(e);
case 81 : // Q - quote
this.FormatBB({tag: 'QUOTE'});
return BX.PreventDefault(e);
}
}
// Tab
if (key == 9)
{
this.WrapWith('', '', "\t");
return BX.PreventDefault(e);
}
// Ctrl + Enter
if ((e.keyCode == 13 || e.keyCode == 10) && e.ctrlKey && this.ctrlEnterHandler)
{
this.SaveContent();
this.ctrlEnterHandler();
}
},
GetCutHTML: function(e)
{
if (this.curCutId)
{
var pCut = this.pEditorDocument.getElementById(this.curCutId);
if (pCut)
{
pCut.parentNode.insertBefore(BX.create("BR", {}, this.pEditorDocument), pCut);
pCut.parentNode.removeChild(pCut);
}
}
this.curCutId = this.SetBxTag(false, {tag: "cut"});
return '';
},
OnPaste: function()
{
if (this.bOnPasteProcessing)
return;
this.bOnPasteProcessing = true;
var _this = this;
var scrollTop = this.pEditorDocument.body.scrollTop;
setTimeout(function(){
_this.bOnPasteProcessing = false;
_this.InsertHTML('');
_this.SaveContent();
setTimeout(function()
{
var content = _this.GetContent();
if (/<\w[^>]*(( class="?MsoNormal"?)|(="mso-))/gi.test(content))
content = _this.CleanWordText(content);
_this.SetEditorContent(content);
setTimeout(function()
{
try{
var pCursor = _this.pEditorDocument.getElementById(_this.lastCursorId);
if (pCursor && pCursor.parentNode)
{
var newScrollTop = pCursor.offsetTop - 30;
if (newScrollTop > 0)
{
if (scrollTop > 0 && scrollTop + parseInt(_this.pFrame.offsetHeight) > newScrollTop)
_this.pEditorDocument.body.scrollTop = scrollTop;
else
_this.pEditorDocument.body.scrollTop = newScrollTop;
}
_this.SelectElement(pCursor);
pCursor.parentNode.removeChild(pCursor);
_this.SetFocus();
}
}catch(e){}
}, 100);
}, 100);
}, 100);
},
CleanWordText: function(text)
{
text = text.replace(/<(P|B|U|I|STRIKE)> <\/\1>/g, ' ');
text = text.replace(/([\s\S]*?)<\/o:p>/ig, "$1");
//text = text.replace(/[\s\S]*?<\/o:p>/ig, " ");
text = text.replace(/]*display:\s*?none[^>]*>([\s\S]*?)<\/span>/gi, ''); // Hide spans with display none
text = text.replace(//ig, ""); //
text = text.replace(//ig, ""); //
text = text.replace(/<\\?\?xml[^>]*>/ig, ""); //,
text = text.replace(/\s*<\/o:p>/ig, "");
text = text.replace(/<\/?[a-z1-9]+:[^>]*>/gi, ""); //,
text = text.replace(/<([a-z1-9]+[^>]*) class=([^ |>]*)(.*?>)/gi, "<$1$3");
text = text.replace(/<([a-z1-9]+[^>]*) [a-z]+:[a-z]+=([^ |>]*)(.*?>)/gi, "<$1$3"); // xmlns:v="urn:schemas-microsoft-com:vml"
text = text.replace(/ /ig, ' ');
text = text.replace(/\s+?/gi, ' ');
// Remove mso-xxx styles.
text = text.replace(/\s*mso-[^:]+:[^;"]+;?/gi, "");
// Remove margin styles.
text = text.replace(/\s*margin: 0cm 0cm 0pt\s*;/gi, "");
text = text.replace(/\s*margin: 0cm 0cm 0pt\s*"/gi, "\"");
text = text.replace(/\s*TEXT-INDENT: 0cm\s*;/gi, "");
text = text.replace(/\s*TEXT-INDENT: 0cm\s*"/gi, "\"");
text = text.replace(/\s*TEXT-ALIGN: [^\s;]+;?"/gi, "\"");
text = text.replace(/\s*PAGE-BREAK-BEFORE: [^\s;]+;?"/gi, "\"");
text = text.replace(/\s*FONT-VARIANT: [^\s;]+;?"/gi, "\"");
text = text.replace(/\s*tab-stops:[^;"]*;?/gi, "");
text = text.replace(/\s*tab-stops:[^"]*/gi, "");
text = text.replace(/]*>([\s\S]*?)<\/FONT>/gi, '$1');
text = text.replace(/\s*face="[^"]*"/gi, "");
text = text.replace(/\s*face=[^ >]*/gi, "");
text = text.replace(/\s*FONT-FAMILY:[^;"]*;?/gi, "");
// Remove Class attributes
text = text.replace(/<(\w[^>]*) class=([^ |>]*)([^>]*)/gi, "<$1$3");
// Remove styles.
text = text.replace(/<(\w[^>]*) style="([^\"]*)"([^>]*)/gi, "<$1$3");
// Remove empty styles.
text = text.replace(/\s*style="\s*"/gi, '');
// Remove Lang attributes
text = text.replace(/<(\w[^>]*) lang=([^ |>]*)([^>]*)/gi, "<$1$3");
var iter = 0;
while (text.toLowerCase().indexOf('') != -1 && iter++ < 20)
text = text.replace(/]*?>([\s\S]*?)<\/span>/gi, '$1');
var
_text,
i, tag, arFormatTags = ['b', 'strong', 'i', 'u', 'font', 'span', 'strike'];
while (true)
{
_text = text;
for (i in arFormatTags)
{
tag = arFormatTags[i];
text = text.replace(new RegExp('<' + tag + '[^>]*?>(\\s*?)<\\/' + tag + '>', 'gi'), '$1');
text = text.replace(new RegExp('<\\/' + tag + '[^>]*?>(\\s*?)<' + tag + '>', 'gi'), '$1');
}
if (_text == text)
break;
}
// Remove empty tags
text = text.replace(/<(?:[^\s>]+)[^>]*>([\s\n\t\r]*)<\/\1>/g, "$1");
text = text.replace(/<(?:[^\s>]+)[^>]*>(\s*)<\/\1>/g, "$1");
text = text.replace(/<(?:[^\s>]+)[^>]*>(\s*)<\/\1>/g, "$1");
//text = text.replace(/<\/?xml[^>]*>/gi, ""); //,
text = text.replace(/]*?(?:>\s*?<\/xml)?(?:\/?)?>/ig, '');
text = text.replace(/]*?(?:>\s*?<\/meta)?(?:\/?)?>/ig, '');
text = text.replace(/]*?(?:>\s*?<\/link)?(?:\/?)?>/ig, '');
text = text.replace(/