Your IP : 3.145.45.174
/**
* Bitrix HTML Editor 3.0
* Date: 24.04.13
* Time: 4:23
*
* Parser class
*/
/**
* HTML Sanitizer
* Rewrites the HTML based on given rules
*/
(function()
{
function BXEditorParser(editor)
{
this.editor = editor;
this.specialParsers = {};
// Rename unknown tags to this
this.DEFAULT_NODE_NAME = "span",
this.WHITE_SPACE_REG_EXP = /\s+/,
this.defaultRules = {
tags: {},
classes: {}
};
this.convertedBxNodes = [];
this.rules = {};
if (!this.editor.util.FirstLetterSupported())
{
this.firstNodeCheck = false;
this.FIRST_LETTER_CLASS = 'bxe-first-letter';
this.FIRST_LETTER_CLASS_CHROME = 'bxe-first-letter-chrome';
this.FIRST_LETTER_SPAN = 'bxe-first-letter-s';
}
}
BXEditorParser.prototype = {
/**
* Iterates over all childs of the element, recreates them, appends them into a document fragment
* which later replaces the entire body content
*/
Parse: function(content, rules, doc, cleanUp, parseBx)
{
if (!doc)
{
doc = document;
}
this.convertedBxNodes = [];
this.firstNodeCheck = false;
var
frag = doc.createDocumentFragment(),
el = this.GetAsDomElement(content, doc),
newNode, addInvisibleNodes,
firstChild;
this.SetParseBxMode(parseBx);
this.pasteNodeIndexTmp = BX.clone(this.editor.pasteNodeIndex);
while (el.firstChild)
{
firstChild = el.firstChild;
el.removeChild(firstChild);
newNode = this.Convert(firstChild, cleanUp, parseBx, newNode);
if (newNode)
{
addInvisibleNodes = !parseBx && this.CheckBlockNode(newNode);
// mantis: 101249
if (BX.browser.IsFirefox() && newNode.nodeName == 'DIV')
{
addInvisibleNodes = false;
}
frag.appendChild(newNode);
if (addInvisibleNodes)
{
frag.appendChild(this.editor.util.GetInvisibleTextNode());
}
}
}
// Clear element contents
el.innerHTML = "";
// Insert new DOM tree
el.appendChild(frag);
content = this.RegexpContentParse(this.editor.GetInnerHtml(el), parseBx);
return content;
},
SetParseBxMode: function(bParseBx)
{
this.bParseBx = !!bParseBx;
},
// here we can parse content as string, not as DOM
CodeParse: function(content)
{
return content;
},
GetAsDomElement: function(html, doc)
{
if (!doc)
doc = document;
var el = doc.createElement("DIV");
if (typeof(html) === "object" && html.nodeType)
{
el.appendChild(html);
}
else if (this.editor.util.CheckHTML5Support())
{
el.innerHTML = html;
}
else if (this.editor.util.CheckHTML5FullSupport())
{
el.style.display = "none";
doc.body.appendChild(el);
try {
el.innerHTML = html;
} catch(e) {}
doc.body.removeChild(el);
}
return el;
},
Convert: function(oldNode, cleanUp, parseBx, prevNode)
{
var
bCleanNodeAfterPaste = false,
oldNodeType = oldNode.nodeType,
oldChilds = oldNode.childNodes,
newNode,
newChild,
i, bxTag;
if (oldNodeType == 1)
{
if (oldNode.nodeName == 'IMG')
{
if (!oldNode.getAttribute("data-bx-orig-src"))
oldNode.setAttribute("data-bx-orig-src", oldNode.getAttribute('src'));
else
oldNode.setAttribute("src", oldNode.getAttribute('data-bx-orig-src'));
}
if (this.editor.pasteHandleMode && (parseBx || this.editor.bbParseContentMode))
{
if (oldNode.id == 'bx-cursor-node')
{
return oldNode.ownerDocument.createTextNode(this.editor.INVISIBLE_CURSOR);
}
var bxPasteFlag = oldNode.getAttribute('data-bx-paste-flag');
bCleanNodeAfterPaste = bxPasteFlag !== 'Y' && !this.pasteNodeIndexTmp[bxPasteFlag];
if (oldNode && oldNode.id)
{
bxTag = this.editor.GetBxTag(oldNode.id);
if (bxTag.tag)
{
bCleanNodeAfterPaste = false;
}
}
if (bCleanNodeAfterPaste)
{
oldNode = this.CleanNodeAfterPaste(oldNode, prevNode);
if (!oldNode)
{
return null;
}
oldChilds = oldNode.childNodes;
oldNodeType = oldNode.nodeType;
}
oldNode.removeAttribute('data-bx-paste-flag');
if (this.pasteNodeIndexTmp[bxPasteFlag])
delete this.pasteNodeIndexTmp[bxPasteFlag];
}
else
{
if (oldNode.id == 'bx-cursor-node')
{
return oldNode.cloneNode(true);
}
}
// Doublecheck nodetype
if (oldNodeType == 1)
{
if (!oldNode.__bxparsed)
{
if (this.IsAnchor(oldNode) && !oldNode.getAttribute('data-bx-replace_with_children'))
{
newNode = oldNode.cloneNode(true);
newNode.innerHTML = '';
newChild = null;
for (i = 0; i < oldChilds.length; i++)
{
newChild = this.Convert(oldChilds[i], cleanUp, parseBx, newChild);
if (newChild)
{
newNode.appendChild(newChild);
}
}
var attr = {};
for (i = 0; i < newNode.attributes.length; i++)
{
if (newNode.attributes[i].name !== 'name')
attr[newNode.attributes[i].name] = newNode.attributes[i].value;
}
oldNode = this.editor.phpParser.GetSurrogateNode("anchor", BX.message('BXEdAnchor') + ": #" + newNode.name, null, {
html: newNode.innerHTML,
name: newNode.name,
attributes: attr
});
}
else if(this.IsPrintBreak(oldNode))
{
oldNode = this.GetPrintBreakSurrogate(oldNode);
}
if (oldNode && oldNode.id)
{
bxTag = this.editor.GetBxTag(oldNode.id);
if(bxTag.tag)
{
oldNode.__bxparsed = 1;
// We've found bitrix-made node
if (this.bParseBx)
{
newNode = oldNode.ownerDocument.createTextNode('~' + bxTag.id + '~');
this.convertedBxNodes.push(bxTag);
}
else
{
newNode = oldNode.cloneNode(true);
}
return newNode;
}
}
if (!newNode && oldNode.nodeType)
{
newNode = this.ConvertElement(oldNode, parseBx);
}
}
}
}
else if (oldNodeType == 3)
{
newNode = this.HandleText(oldNode);
}
if (!newNode)
{
return null;
}
for (i = 0; i < oldChilds.length; i++)
{
newChild = this.Convert(oldChilds[i], cleanUp, parseBx);
if (newChild)
{
newNode.appendChild(newChild);
}
}
if (newNode.nodeType == 1)
{
// Cleanup style="" attribute for elements
if (newNode.style && BX.util.trim(newNode.style.cssText) == '' && newNode.removeAttribute)
{
newNode.removeAttribute('style');
}
// Cleanup senseless <span> elements
if (this.editor.config.cleanEmptySpans && cleanUp && newNode.childNodes.length <= 1 && newNode.nodeName.toLowerCase() === this.DEFAULT_NODE_NAME && !newNode.attributes.length)
{
return newNode.firstChild;
}
}
return newNode;
},
ConvertElement: function(oldNode, parseBx)
{
var
rule, i, value,
newNode,
new_rule,
tagRules = this.editor.GetParseRules().tags,
nodeName = oldNode.nodeName.toLowerCase(),
scopeName = oldNode.scopeName;
// We already parsed this element ignore it!
if (oldNode.__bxparsed)
{
return null;
}
oldNode.__bxparsed = 1;
if (oldNode.className === "bx-editor-temp")
{
return null;
}
if (scopeName && scopeName != "HTML")
{
nodeName = scopeName + ":" + nodeName;
}
/**
* Repair node
* IE is a bit bitchy when it comes to invalid nested markup which includes unclosed tags
* A <p> doesn't need to be closed according HTML4-5 spec, we simply replace it with a <div> to preserve its content and layout
*/
if (
"outerHTML" in oldNode &&
!this.editor.util.AutoCloseTagSupported() &&
oldNode.nodeName === "P" &&
oldNode.outerHTML.slice(-4).toLowerCase() !== "</p>")
{
nodeName = "div";
}
// chrome bug, mantis: #61981
if (!this.editor.util.FirstLetterSupported() && oldNode.className)
{
if (oldNode.className == this.FIRST_LETTER_CLASS && !this.bParseBx)
{
this.HandleFirstLetterNode(oldNode);
}
else if (oldNode.className == this.FIRST_LETTER_CLASS_CHROME && this.bParseBx)
{
this.HandleFirstLetterNodeBack(oldNode);
}
}
// Add "data-bx-no-border"="Y" for tables without borders
if (nodeName == "table" && !this.bParseBx)
{
var border = parseInt(oldNode.getAttribute('border'), 10);
if (!border)
{
oldNode.removeAttribute("border");
oldNode.setAttribute("data-bx-no-border", "Y");
}
}
if (nodeName in tagRules)
{
rule = tagRules[nodeName];
if (!rule || rule.remove)
{
return null;
}
if (rule.clean_empty &&
// Only empty node
(oldNode.innerHTML === "" || oldNode.innerHTML === this.editor.INVISIBLE_SPACE)
&&
(!oldNode.className || oldNode.className == "")
&&
// We check lastCreatedId to prevent cleaning elements which just were created
(!this.editor.lastCreatedId || this.editor.lastCreatedId != oldNode.getAttribute('data-bx-last-created-id'))
)
{
return null;
}
rule = typeof(rule) === "string" ? {rename_tag: rule} : rule;
// New rule can be applied throw the attribute 'data-bx-new-rule'
new_rule = oldNode.getAttribute('data-bx-new-rule');
if (new_rule)
{
rule[new_rule] = oldNode.getAttribute('data-bx-' + new_rule);
}
}
else if (oldNode.firstChild)
{
rule = {rename_tag: this.DEFAULT_NODE_NAME};
}
else
{
// Remove empty unknown elements
return null;
}
if (rule.convert_attributes && parseBx == false)
{
for (i in rule.convert_attributes)
{
if (rule.convert_attributes.hasOwnProperty(i) && oldNode.getAttribute(i))
{
value = this.ConvertAttributeValueToCss(i,rule.convert_attributes[i], oldNode.getAttribute(i));
if (value !== false)
{
rule.replace_with_children = false;
oldNode.style[rule.convert_attributes[i]] = value;
}
oldNode.removeAttribute(i);
}
}
}
if (rule.replace_with_children)
{
newNode = oldNode.ownerDocument.createDocumentFragment();
}
else
{
newNode = oldNode.ownerDocument.createElement(rule.rename_tag || nodeName);
this.HandleAttributes(oldNode, newNode, rule, parseBx);
}
if (new_rule)
{
rule[new_rule] = null;
delete rule[new_rule];
}
if ((!newNode.className || newNode.className == '') && newNode.removeAttribute)
{
newNode.removeAttribute('class');
}
oldNode = null;
return newNode;
},
CleanNodeAfterPaste: function(oldNode, prevNode)
{
var
name, i,
nodeName = oldNode.nodeName,
innerHtml = oldNode.innerHTML,
innerHtmlTrimed = BX.util.trim(innerHtml),
whiteAttributes = {align: 1, alt: 1, bgcolor: 1, border: 1, cellpadding: 1, cellspacing: 1, color:1, colspan:1, height: 1, href: 1, rowspan: 1, size: 1, span: 1, src: 1, style: 1, target: 1, title: 1, type: 1, value: 1, width: 1},
decorNodes = {"B": 1, "STRONG": 1, "I": 1, "EM": 1, "U": 1, "DEL": 1, "S": 1, "STRIKE": 1},
cleanEmpty = {"A": 1, "SPAN": 1, "B": 1, "STRONG": 1, "I": 1, "EM": 1, "U": 1, "DEL": 1, "S": 1, "STRIKE": 1, "H1": 1, "H2": 1, "H3": 1, "H4": 1, "H5": 1, "H6": 1, "ABBR": 1, "TIME": 1, "FIGURE": 1, "FIGCAPTION": 1};
// Clean iframes
if (nodeName == 'IFRAME')
{
return null;
}
// Clean items with display: none
if (oldNode.style.display == 'none' || oldNode.style.visibility == 'hidden')
{
return null;
}
// Clean empty nodes
if (cleanEmpty[nodeName] && innerHtml == '')
{
return null;
}
var cleanAttribute = oldNode.getAttribute('data-bx-clean-attribute');
if (cleanAttribute)
{
oldNode.removeAttribute(cleanAttribute);
oldNode.removeAttribute('data-bx-clean-attribute');
}
// Drag & Drop of the images
if (nodeName == 'IMG')
{
var alt = oldNode.getAttribute('alt');
if(alt === '')
{
oldNode.removeAttribute('alt');
}
else if(typeof alt == 'string' && alt !== '' && alt.indexOf('://') !== -1)
{
this.CheckAltImage(oldNode);
}
oldNode.removeAttribute('class');
this.CleanNodeCss(oldNode);
return oldNode;
}
// Clean anchors
if (nodeName == 'A' && (innerHtmlTrimed == '' || innerHtmlTrimed == ' '))
{
return null;
}
if (nodeName == 'A')
{
// Todo: clean block nodes from link
}
// Clean class
oldNode.removeAttribute('class');
oldNode.removeAttribute('id');
// Clean attributes corresponding to white list from above
i = 0;
while (i < oldNode.attributes.length)
{
name = oldNode.attributes[i].name;
if (!whiteAttributes[name] || oldNode.attributes[i].value == '')
{
oldNode.removeAttribute(name);
}
else
{
i++;
}
}
//mantis:74639
if (nodeName == 'THEAD')
{
var trs = oldNode.getElementsByTagName('TR'), st;
for (i = 0; i < trs.length; i++)
{
if (trs[i] && trs[i].getAttribute)
{
st = trs[i].getAttribute('style');
if (st
&& st.indexOf('mso-yfti-irow') !== -1
&& st.indexOf('mso-yfti-irow:0') === -1
&& st.indexOf('mso-yfti-irow:-1') === -1
&& st.indexOf('mso-yfti-firstrow:yes') === -1
)
{
oldNode.setAttribute('data-bx-new-rule', 'rename_tag');
oldNode.setAttribute('data-bx-rename_tag', 'TBODY');
break;
}
}
}
}
// Clean pasted div's
if (nodeName == 'DIV' || oldNode.style.display == 'block' || nodeName == 'FORM')
{
if (!oldNode.lastChild || (oldNode.lastChild && oldNode.lastChild.nodeName != 'BR'))
{
oldNode.appendChild(oldNode.ownerDocument.createElement("BR")).setAttribute('data-bx-paste-flag', 'Y');
}
// mantis #54501
if (prevNode && typeof prevNode == 'object' && prevNode.nodeType == 3 && oldNode.firstChild)
{
oldNode.insertBefore(oldNode.ownerDocument.createElement("BR"), oldNode.firstChild).setAttribute('data-bx-paste-flag', 'Y');
}
oldNode.setAttribute('data-bx-new-rule', 'replace_with_children');
oldNode.setAttribute('data-bx-replace_with_children', '1');
}
// Content pasted from google docs sometimes comes with unused <b style="font-weight: normal"> wrapping
if (nodeName == 'B' && oldNode.style.fontWeight == 'normal')
{
oldNode.setAttribute('data-bx-new-rule', 'replace_with_children');
oldNode.setAttribute('data-bx-replace_with_children', '1');
}
if (decorNodes[nodeName] && this.editor.config.pasteSetDecor)
{
oldNode.setAttribute('data-bx-new-rule', 'replace_with_children');
oldNode.setAttribute('data-bx-replace_with_children', '1');
}
if (decorNodes[nodeName] && this.editor.config.pasteSetDecor)
{
oldNode.setAttribute('data-bx-new-rule', 'replace_with_children');
oldNode.setAttribute('data-bx-replace_with_children', '1');
}
if (this.IsAnchor(oldNode) && (oldNode.name == '' || BX.util.trim(oldNode.name == '')))
{
oldNode.setAttribute('data-bx-new-rule', 'replace_with_children');
oldNode.setAttribute('data-bx-replace_with_children', '1');
}
if (BX.util.in_array(nodeName, this.editor.TABLE_TAGS) && this.editor.config.pasteClearTableDimen)
{
oldNode.removeAttribute('width');
oldNode.removeAttribute('height');
}
this.CleanNodeCss(oldNode);
// Clear useless spans
if (nodeName == 'SPAN' && oldNode.style.cssText == '')
{
oldNode.setAttribute('data-bx-new-rule', 'replace_with_children');
oldNode.setAttribute('data-bx-replace_with_children', '1');
}
// Replace <p> </p> ==> <p> </p>, <span> </span> ==> <span> </span>
if ((nodeName == 'P' || nodeName == 'SPAN' || nodeName == 'FONT') && BX.util.trim(oldNode.innerHTML) == " ")
{
oldNode.innerHTML = ' ';
}
return oldNode;
},
CleanNodeCss: function(node)
{
var
styles, j, styleName, styleValue, i,
nodeName = node.nodeName,
whiteCssList = {
'width': ['auto'],
'height': ['auto']
};
if (BX.util.in_array(nodeName, this.editor.TABLE_TAGS) && this.editor.config.pasteClearTableDimen)
{
whiteCssList = {};
}
if (!this.editor.config.pasteSetColors)
{
whiteCssList['color'] = ['#000000', '#000', 'black'];
whiteCssList['background-color'] = ['transparent', '#fff', '#ffffff', 'white'];
whiteCssList['background'] = 1;
}
if (!this.editor.config.pasteSetBorders)
{
whiteCssList['border-collapse'] = 1;
whiteCssList['border-color'] = ['transparent', '#fff', '#ffffff', 'white'];
whiteCssList['border-style'] = ['none', 'hidden'];
whiteCssList['border-top'] = ['0px', '0'];
whiteCssList['border-right'] = ['0px', '0'];
whiteCssList['border-bottom'] = ['0px', '0'];
whiteCssList['border-left'] = ['0px', '0'];
whiteCssList['border-top-color'] = ['transparent', '#fff', '#ffffff', 'white'];
whiteCssList['border-right-color'] = ['transparent', '#fff', '#ffffff', 'white'];
whiteCssList['border-bottom-color'] = ['transparent', '#fff', '#ffffff', 'white'];
whiteCssList['border-left-color'] = ['transparent', '#fff', '#ffffff', 'white'];
whiteCssList['border-top-style'] = ['none', 'hidden'];
whiteCssList['border-right-style'] = ['none', 'hidden'];
whiteCssList['border-bottom-style'] = ['none', 'hidden'];
whiteCssList['border-left-style'] = ['none', 'hidden'];
whiteCssList['border-top-width'] = ['0px', '0'];
whiteCssList['border-right-width'] = ['0px', '0'];
whiteCssList['border-bottom-width'] = ['0px', '0'];
whiteCssList['border-left-width'] = ['0px', '0'];
whiteCssList['border-width'] = ['0px', '0'];
whiteCssList['border'] = ['0px', '0'];
}
if (!this.editor.config.pasteSetDecor)
{
whiteCssList['font-style'] = ['normal'];
whiteCssList['font-weight'] = ['normal'];
whiteCssList['text-decoration'] = ['none'];
}
// Clean style
if (node.style && BX.util.trim(node.style.cssText) != '' && nodeName !== 'BR')
{
styles = [];
for (i in node.style)
{
if (node.style.hasOwnProperty(i))
{
if (parseInt(i).toString() === i)
{
styleName = node.style[i];
styleValue = node.style.getPropertyValue(styleName);
}
else
{
styleName = i;
styleValue = node.style.getPropertyValue(styleName);
}
if (styleValue === null)
continue;
if (!whiteCssList[styleName] ||
styleValue.match(/^-(moz|webkit|ms|o)/ig) ||
styleValue == 'inherit' ||
styleValue == 'initial' ||
(styleName == 'color' && nodeName == 'A') || // Color for links
((nodeName == 'SPAN' || nodeName == 'P') && (styleName == 'width' || styleName == 'height')) || // Sizes for SPAN and P
(typeof whiteCssList[styleName] == 'object' && BX.util.in_array(styleValue.toLowerCase(), whiteCssList[styleName])))
{
continue;
}
// Clean colors like rgb(0,0,0)
if (styleName.indexOf('color') !== -1)
{
styleValue = this.editor.util.RgbToHex(styleValue);
if ((typeof whiteCssList[styleName] == 'object' && BX.util.in_array(styleValue.toLowerCase(), whiteCssList[styleName])) ||
styleValue == 'transparent')
{
continue;
}
}
// Clean hidden borders, for example: border-top: medium none;
if (styleName.indexOf('border') !== -1 && styleValue.indexOf('none') !== -1)
{
continue;
}
styles.push({name: styleName, value: styleValue});
}
}
node.removeAttribute('style');
if (styles.length > 0)
{
for (j = 0; j < styles.length; j++)
{
node.style[styles[j].name] = styles[j].value;
}
}
}
else
{
node.removeAttribute('style');
}
},
CheckAltImage: function(img)
{
var doc = this.editor.GetIframeDoc();
function getImageBySrc(src)
{
var
i,
imgs = doc.getElementsByTagName('IMG');
for (i = 0; i < imgs.length; i++)
{
if (imgs[i].src === src)
{
return imgs[i];
}
}
}
function onload()
{
if (img.src === img.alt && img.getAttribute('data-bx-orig-src') !== img.src)
{
img.setAttribute("data-bx-orig-src", img.getAttribute('src'));
}
BX.unbind(img, 'load', onload);
BX.unbind(img, 'error', onerror);
}
function onerror()
{
var
alt = img.getAttribute('alt'),
imgNode = getImageBySrc(img.src);
if (!imgNode)
{
BX.unbind(img, 'load', onload);
BX.unbind(img, 'error', onerror);
return;
}
if (img.getAttribute('src') !== img.alt)
{
imgNode.setAttribute("src", alt);
}
else
{
imgNode.setAttribute("src", img.getAttribute('data-bx-orig-src'));
BX.unbind(img, 'load', onload);
BX.unbind(img, 'error', onerror);
}
}
BX.bind(img, 'load', onload);
BX.bind(img, 'error', onerror);
},
HandleText: function(node)
{
var data = node.data;
if (this.editor.pasteHandleMode && data.indexOf('EndFragment:') !== -1)
{
// Clean content inserted from OpenOffice in MacOs
data = data.replace(/Version:\d\.\d(?:\s|\S)*?StartHTML:\d+(?:\s|\S)*?EndHTML:\d+(?:\s|\S)*?StartFragment:\d+(?:\s|\S)*?EndFragment:\d+(?:\s|\n|\t|\r)*/g, '');
}
return node.ownerDocument.createTextNode(data);
},
HandleAttributes: function(oldNode, newNode, rule, parseBx)
{
var
attributes = {}, // fresh new set of attributes to set on newNode
setClass = rule.set_class, // classes to set
addClass = rule.add_class, // add classes based on existing attributes
addCss = rule.add_css, // add classes based on existing attributes
setAttributes = rule.set_attributes, // attributes to set on the current node
checkAttributes = rule.check_attributes, // check/convert values of attributes
clearAttributes = rule.clear_attributes, // clean all unknown attributes
allowedClasses = this.editor.GetParseRules().classes,
i = 0, newName, skipAttributes = {},
st,
classes = [],
newClasses = [],
newUniqueClasses = [],
oldClasses = [],
classesLength,
newClassesLength,
currentClass,
newClass,
attribute,
attributeName,
newAttributeValue,
handler;
if (checkAttributes)
{
for (attributeName in checkAttributes)
{
handler = this.GetCheckAttributeHandler(checkAttributes[attributeName]);
if (!handler)
continue;
newAttributeValue = handler(this.GetAttributeEx(oldNode, attributeName));
if (typeof(newAttributeValue) === "string" && newAttributeValue !== '')
attributes[attributeName] = newAttributeValue;
}
}
var cleanAttribute = oldNode.getAttribute('data-bx-clean-attribute');
if (cleanAttribute)
{
oldNode.removeAttribute(cleanAttribute);
oldNode.removeAttribute('data-bx-clean-attribute');
}
if (!clearAttributes)
{
for (i = 0; i < oldNode.attributes.length; i++)
{
attribute = oldNode.attributes[i];
if (parseBx)
{
if (attribute.name.substr(0, 15) == 'data-bx-app-ex-')
{
newName = attribute.name.substr(15);
attributes[newName] = oldNode.getAttribute(attribute.name);
skipAttributes[newName] = true;
}
if (skipAttributes[attribute.name])
{
continue;
}
}
// clear bitrix attributes
if (attribute.name.substr(0, 8) == 'data-bx-'
&& attribute.name != 'data-bx-noindex'
&& this.bParseBx)
{
continue;
}
attributes[attribute.name] = this.GetAttributeEx(oldNode, attribute.name);
}
}
if (setClass)
classes.push(setClass);
if (addCss)
{
for (st in addCss)
{
if (addCss.hasOwnProperty(st))
newNode.style[st] = addCss[st];
}
}
/*
// TODO:
if (addClass)
{
var addClassMethods = {
align_img: (function() {
var mapping = {
left: "wysiwyg-float-left",
right: "wysiwyg-float-right"
};
return function(attributeValue) {
return mapping[String(attributeValue).toLowerCase()];
};
})(),
align_text: (function() {
var mapping = {
left: "wysiwyg-text-align-left",
right: "wysiwyg-text-align-right",
center: "wysiwyg-text-align-center",
justify: "wysiwyg-text-align-justify"
};
return function(attributeValue) {
return mapping[String(attributeValue).toLowerCase()];
};
})(),
clear_br: (function() {
var mapping = {
left: "wysiwyg-clear-left",
right: "wysiwyg-clear-right",
both: "wysiwyg-clear-both",
all: "wysiwyg-clear-both"
};
return function(attributeValue) {
return mapping[String(attributeValue).toLowerCase()];
};
})(),
size_font: (function() {
var mapping = {
"1": "wysiwyg-font-size-xx-small",
"2": "wysiwyg-font-size-small",
"3": "wysiwyg-font-size-medium",
"4": "wysiwyg-font-size-large",
"5": "wysiwyg-font-size-x-large",
"6": "wysiwyg-font-size-xx-large",
"7": "wysiwyg-font-size-xx-large",
"-": "wysiwyg-font-size-smaller",
"+": "wysiwyg-font-size-larger"
};
return function(attributeValue) {
return mapping[String(attributeValue).charAt(0)];
};
})()
};
for (attributeName in addClass)
{
handler = addClassMethods[addClass[attributeName]];
if (!handler)
continue;
newClass = handler(this.GetAttributeEx(oldNode, attributeName));
if (typeof(newClass) === "string")
classes.push(newClass);
}
}
*/
// add old classes last
oldClasses = oldNode.getAttribute("class");
if (oldClasses)
classes = classes.concat(oldClasses.split(this.WHITE_SPACE_REG_EXP));
classesLength = classes.length;
for (; i<classesLength; i++)
{
currentClass = classes[i];
if (allowedClasses[currentClass])
newClasses.push(currentClass);
}
if (newUniqueClasses.length)
attributes["class"] = newUniqueClasses.join(" ");
// set attributes on newNode
for (attributeName in attributes)
{
// Setting attributes can cause a js error in IE under certain circumstances
// eg. on a <img> under https when it's new attribute value is non-https
// TODO: Investigate this further and check for smarter handling
try {
newNode.setAttribute(attributeName, attributes[attributeName]);
} catch(e) {}
}
// IE8 sometimes loses the width/height attributes when those are set before the "src"
// so we make sure to set them again
if (attributes.src)
{
if (typeof(attributes.width) !== "undefined")
newNode.setAttribute("width", attributes.width);
if (typeof(attributes.height) !== "undefined")
newNode.setAttribute("height", attributes.height);
}
},
ConvertAttributeValueToCss: function(attribute, css, value)
{
if (attribute == 'size' && css == 'fontSize') // fontsize
{
var fontSizeMap = {
1: '9px',
2: '13px',
3: '16px',
4: '18px',
5: '24px',
6: '32px',
7: '48px'
};
if (fontSizeMap[value])
{
value = fontSizeMap[value];
}
else if (value < 1)
{
value = false;
}
else if (value > 7)
{
value = fontSizeMap[7];
}
}
return value;
},
GetAttributeEx: function(node, attributeName)
{
attributeName = attributeName.toLowerCase();
var
res,
nodeName = node.nodeName;
if (nodeName == "IMG" && attributeName == "src" && this.IsLoadedImage(node) === true)
{
res = node.getAttribute('src');
}
else if (!this.editor.util.CheckGetAttributeTruth() && "outerHTML" in node)
{
var
outerHTML = node.outerHTML.toLowerCase(),
hasAttribute = outerHTML.indexOf(" " + attributeName + "=") != -1;
res = hasAttribute ? node.getAttribute(attributeName) : null;
}
else
{
res = node.getAttribute(attributeName);
}
return res;
},
IsLoadedImage: function(node)
{
try
{
return node.complete && !node.mozMatchesSelector(":-moz-broken");
}
catch(e)
{
if (node.complete && node.readyState === "complete")
return true;
}
return false;
},
GetCheckAttributeHandler: function(attrName)
{
var methods = this.GetCheckAttributeHandlers();
return methods[attrName];
},
GetCheckAttributeHandlers: function()
{
return {
url: function(attributeValue)
{
return attributeValue;
// if (!attributeValue || !attributeValue.match(/^https?:\/\//i))
// return null;
// return attributeValue.replace(/^https?:\/\//i, function(match){return match.toLowerCase();});
},
alt: function(attributeValue)
{
if (!attributeValue)
{
return "";
}
return attributeValue.replace(/[^ a-z0-9_\-]/gi, "");
},
numbers: function(attributeValue)
{
attributeValue = (attributeValue || "").replace(/\D/g, "");
return attributeValue || null;
}
};
},
HandleBitrixNode: function(node)
{
return node;
},
RegexpContentParse: function(content, parseBx)
{
// parse color inside style attributes RGB ==> HEX
// TODO: it will cause wrong replace if rgba will be not inside style attribute...
if (content.indexOf('rgb') !== -1)
{
content = content.replace(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+))?\)/ig, function(str, h1, h2, h3, h4)
{
function hex(x)
{
return ("0" + parseInt(x).toString(16)).slice(-2);
}
return "#" + hex(h1) + hex(h2) + hex(h3);
});
}
if (parseBx && content.indexOf('data-bx-noindex') !== -1)
{
content = content.replace(/(<a[^<]*?)data\-bx\-noindex="Y"([\s\S]*?>[\s\S]*?\/a>)/ig, function(s, s1, s2)
{
return '<!--noindex-->' + s1 + s2 + '<!--\/noindex-->';
});
}
if (parseBx)
{
content = content.replace(/\uFEFF/ig, '');
}
else
{
content = content.replace(/\uFEFF+/ig, this.editor.INVISIBLE_SPACE);
}
if (parseBx && content.indexOf('#BXAPP') !== -1)
{
var _this = this;
content = content.replace(/#BXAPP(\d+)#/g, function(str, ind)
{
ind = parseInt(ind, 10);
return _this.editor.phpParser.AdvancedPhpGetFragmentByIndex(ind, true);
});
}
return content;
},
IsAnchor: function(n)
{
return n.nodeName == 'A' && !n.href;
},
IsPrintBreak: function(n)
{
return n.style.pageBreakAfter == 'always';
},
GetPrintBreakSurrogate: function(node)
{
var
doc = this.editor.GetIframeDoc(),
id = this.editor.SetBxTag(false, {tag: 'printbreak', params: {innerHTML: BX.util.trim(node.innerHTML)}, name: BX.message('BXEdPrintBreakName'), title: BX.message('BXEdPrintBreakTitle')});
return BX.create('IMG', {props: {src: this.editor.EMPTY_IMAGE_SRC, id: id,className: "bxhtmled-printbreak", title: BX.message('BXEdPrintBreakTitle')}}, doc);
},
CheckBlockNode: function(node)
{
return this.editor.phpParser.IsSurrogate(node) ||
(node.nodeType == 1 &&
(
node.style.display == 'block' || node.style.display == 'inline-block' ||
node.nodeName == 'BLOCKQUOTE' || node.nodeName == 'DIV'
)
);
},
// For chrome only
HandleFirstLetterNode: function(node)
{
this.firstNodeCheck = true;
node.className = this.FIRST_LETTER_CLASS_CHROME;
var
createSpan = true,
doc = this.editor.GetIframeDoc(),
textContent, firstSpanContent,
flTextNode = this._GetFlTextNode(node),
flSpan = this._GetFlSpan(node);
if (flTextNode)
{
textContent = BX.util.trim(this.editor.util.GetTextContent(flTextNode));
if (flSpan)
{
this._FLCleanNodesBeforeFirstSpan(flSpan);
firstSpanContent = BX.util.trim(this.editor.util.GetTextContent(flSpan));
if (textContent.substr(0, 1) == firstSpanContent && firstSpanContent.length == 1)
{
createSpan = false;
}
else if (textContent == firstSpanContent && firstSpanContent.length > 1)
{
createSpan = false;
this.editor.SetCursorNode();
this.editor.util.InsertAfter(doc.createTextNode(textContent.substr(1)), flSpan);
this.editor.RestoreCursor();
flSpan.innerHTML = textContent.substr(0, 1);
}
this._FLCleanNodesBeforeFirstSpan(flSpan);
}
if (createSpan)
{
if (flSpan)
{
this.editor.SetCursorNode();
this.editor.util.ReplaceWithOwnChildren(flSpan);
this.editor.RestoreCursor();
}
flSpan = BX.create('SPAN', {props: {className: this.FIRST_LETTER_SPAN}, text: textContent.substr(0, 1)}, node.ownerDocument);
this.editor.util.SetTextContent(flTextNode, textContent.substr(1));
flTextNode.parentNode.insertBefore(flSpan, flTextNode);
this._FLCleanNodesBeforeFirstSpan(flSpan);
}
this._FLCleanBogusSpans(node);
}
},
HandleFirstLetterNodeBack: function(node)
{
this.firstNodeCheck = true;
node.className = this.FIRST_LETTER_CLASS;
var flSpan = this._GetFlSpan(node);
if (flSpan)
{
this.editor.util.ReplaceWithOwnChildren(flSpan);
}
},
_GetFlSpan: function(node)
{
return BX.findChild(node, {className: this.FIRST_LETTER_SPAN}, 1);
},
_GetFlTextNode: function(node)
{
if (node.innerHTML == '' || !node.firstChild)
return null;
if (node.firstChild && node.firstChild.nodeType == 3 && node.firstChild.nodeValue && BX.util.trim(node.firstChild.nodeValue) !== '')
return node.firstChild;
var
iter = 0,
_this = this,
nodeI = node;
while(iter++ <= 100)
{
nodeI = BX.findChild(nodeI, function(n){return (BX.util.trim(_this.editor.util.GetTextContent(n)) !== '');}, false);
if (nodeI.nodeType == 3 && nodeI.nodeValue && BX.util.trim(nodeI.nodeValue) !== '')
{
return nodeI;
}
}
return null;
},
FirstLetterCheckNodes: function(content, contentTextarea, hardCheck)
{
var doc = this.editor.GetIframeDoc(), i;
if (this.firstNodeCheck || content.indexOf(this.FIRST_LETTER_CLASS) !== -1 || hardCheck === true)
{
var
html,
nodes1 = doc.querySelectorAll('.' + this.FIRST_LETTER_CLASS),
nodes2 = doc.querySelectorAll('.' + this.FIRST_LETTER_CLASS_CHROME);
for (i = 0; i < nodes2.length; i++)
{
html = BX.util.trim(nodes2[i].innerHTML);
if (html == '' || html == '<br>')
{
BX.remove(nodes2[i]);
continue;
}
this.HandleFirstLetterNode(nodes2[i]);
}
for (i = 0; i < nodes1.length; i++)
{
this.HandleFirstLetterNode(nodes1[i]);
}
this.firstNodeCheck = !!(nodes1.length || nodes2.length);
}
if (!this.firstNodeCheck && content.indexOf(this.FIRST_LETTER_SPAN) !== -1)
{
var spans = doc.querySelectorAll('.' + this.FIRST_LETTER_SPAN);
for (i = 0; i < spans.length; i++)
{
this.editor.util.ReplaceWithOwnChildren(spans[i]);
}
}
},
_FLCleanNodesBeforeFirstSpan: function(span)
{
while (span.previousSibling)
{
BX.remove(span.previousSibling);
}
},
_FLCleanBogusSpans: function(node)
{
var i, spans = node.getElementsByTagName('SPAN');
for (i = spans.length - 1; i >= 0; i--)
{
if (!spans[i].className && spans[i].style.lineHeight && spans[i].style.fontSize)
this.editor.util.ReplaceWithOwnChildren(spans[i]);
}
},
FirstLetterBackspaceHandler: function(range)
{
if (range.collapsed && range.startOffset == 0)
{
var flSpan = range.startContainer.previousSibling;
if (flSpan && flSpan.className.indexOf(this.FIRST_LETTER_SPAN) !== -1)
{
this.editor.selection.SetAfter(flSpan.lastChild);
}
}
}
};
function BXEditorPhpParser(editor)
{
this.PHP_PATTERN = '#BXPHP_IND#';
this.editor = editor;
this.allowed = {
php: this.editor.allowPhp || this.editor.lpa,
javascript: true,
style: true,
htmlcomment: true,
iframe: true,
video: true,
audio: true,
'object': true
};
this.bUseAPP = true; // APP - AdvancedPHPParser
this.APPConfig =
{
arTags_before : ['tbody','thead','tfoot','tr','td','th'],
arTags_after : ['tbody','thead','tfoot','tr','td','th'],
arTags :
{
'a' : ['href','title','class','style'],
'img' : ['src','alt','class','style','width','height'],
'input' : ['id','name','value']
}
};
this.customParsers = [];
this.arScripts = {}; // object which contains all php codes with indexes
this.arJavascripts = {}; // object which contains all javascripts codes with indexes
this.arHtmlComments = {}; // object which contains all html comments with indexes
this.arIframes = {}; // object which contains all iframes with indexes
this.arVideos = {}; // object which contains all iframes with emeded videos
this.arAudio = {};
this.arStyles = {}; // object which contains all <style> tags with indexes
this.arObjects = {}; // object which contains all <object> tags with indexes
this.surrClass = 'bxhtmled-surrogate';
this.surrogateTags = {
component: 1,
php: 1,
javascript: 1,
style: 1,
htmlcomment: 1,
anchor: 1,
iframe: 1,
video: 1,
audio: 1,
'object': 1
};
BX.addCustomEvent(this.editor, "OnIframeMouseDown", BX.proxy(this.OnSurrogateMousedown, this));
//BX.addCustomEvent(this.editor, "OnIframeClick", BX.proxy(this.OnSurrogateClick, this));
BX.addCustomEvent(this.editor, "OnIframeDblClick", BX.proxy(this.OnSurrogateDblClick, this));
BX.addCustomEvent(this.editor, "OnIframeKeydown", BX.proxy(this.OnSurrogateKeydown, this));
//BX.addCustomEvent(this.editor, "OnIframeKeyup", BX.proxy(this.OnSurrogateKeyup, this));
BX.addCustomEvent(this.editor, "OnAfterCommandExec", BX.proxy(this.RenewSurrogates, this));
}
//BX.extend(BXEditorPhpParser, BXEditorParser);
BXEditorPhpParser.prototype = {
ParsePhp: function(content)
{
var _this = this;
//1. All fragments of the php code we replace by special str - #BXPHP_IND#
if (this.IsAllowed('php'))
{
content = this.ReplacePhpBySymCode(content);
}
else
{
content = this.CleanPhp(content);
}
// Custom parse
content = this.CustomContentParse(content);
// Javascript
content = this.ReplaceJavascriptBySymCode(content);
// Html comments
content = this.ReplaceHtmlCommentsBySymCode(content);
// Iframe & Video
content = this.ReplaceIframeBySymCode(content);
// Audio
content = this.ReplaceAudioBySymCode(content);
// Style
content = this.ReplaceStyleBySymCode(content);
// Object && embed
content = this.ReplaceObjectBySymCode(content);
// <Break>
content = this.ParseBreak(content);
//2. We trying to resolve html tags with PHP code inside
content = this.AdvancedPhpParse(content);
//3. We replace all #BXPHP_IND# and other sym codes by visual custom elements
content = this.ParseSymCode(content);
// 4. LPA
if (this.editor.lpa)
{
content = content.replace(/#PHP(\d+)#/g, function(str)
{
return _this.GetSurrogateHTML("php_protected", BX.message('BXEdPhpCode') + " *", BX.message('BXEdPhpCodeProtected'), {value : str});
});
content = content.replace(/#BXAPP(\d+)#/g, function(str, appInd)
{
appInd = parseInt(appInd);
return _this.editor.phpParser.AdvancedPhpGetFragmentByIndex(appInd, false);
});
}
return content;
},
// Example:
// <?...?> => #BXPHP0#
ReplacePhpBySymCode: function(content, cleanPhp)
{
var
arScripts = [],
p = 0, i,
bSlashed,
bInString, ch, posnext, ti, quote_ch, mm = 0;
cleanPhp = cleanPhp === true;
while((p = content.indexOf("<?", p)) >= 0)
{
mm = 0;
i = p + 1;
bSlashed = false;
bInString = false;
while(i < content.length - 1)
{
i++;
ch = content.substr(i, 1);
if(!bInString)
{
//if it's not comment
if(ch == "/" && i + 1 < content.length)
{
//find end of php fragment php
posnext = content.indexOf("?>", i);
if(posnext == -1)
{
//if it's no close tag - so script is unfinished
p = content.length;
break;
}
posnext += 2;
ti = 0;
if(content.substr(i + 1, 1)=="*" && (ti = content.indexOf("*/", i + 2))>=0)
{
ti += 2;
}
else if(content.substr(i + 1, 1)=="/" && (ti = content.indexOf("\n", i + 2))>=0)
{
ti += 1;
}
if(ti>0)
{
//find begin - "i" and end - "ti" of comment
// check: what is coming sooner: "END of COMMENT" or "END of SCRIPT"
if(ti > posnext && content.substr(i + 1, 1) != "*")
{
//if script is finished - CUT THE SCRIPT
arScripts.push([p, posnext, content.substr(p, posnext - p)]);
p = posnext;
break;
}
else
{
i = ti - 1; //End of comment come sooner
}
}
continue;
}
if(ch == "?" && i + 1 < content.length && content.substr(i + 1, 1) == ">")
{
i = i + 2;
arScripts.push([p, i, content.substr(p, i - p)]);
p = i + 1;
break;
}
}
if(bInString && ch == "\\")
{
bSlashed = true;
continue;
}
if(ch == "\"" || ch == "'")
{
if(bInString)
{
if(!bSlashed && quote_ch == ch)
bInString = false;
}
else
{
bInString = true;
quote_ch = ch;
}
}
bSlashed = false;
}
if(i >= content.length)
break;
p = i;
}
this.arScripts = {};
if(arScripts.length > 0)
{
var
newstr = "",
plast = 0,
arScript;
if (cleanPhp)
{
for(i = 0; i < arScripts.length; i++)
{
arScript = arScripts[i];
newstr += content.substr(plast, arScript[0] - plast);
plast = arScript[1];
}
}
else
{
for(i = 0; i < arScripts.length; i++)
{
arScript = arScripts[i];
newstr += content.substr(plast, arScript[0] - plast) + this.SavePhpCode(arScript[2], i);
plast = arScript[1];
}
}
content = newstr + content.substr(plast);
}
return content;
},
CleanPhp: function(content)
{
return this.ReplacePhpBySymCode(content, true);
},
// Example: <script>...</script> => #BXJAVASCRIPT_1#
ReplaceJavascriptBySymCode: function(content)
{
this.arJavascripts = {};
var
_this = this,
index = 0;
content = content.replace(/<script[\s\S]*?\/script>/gi, function(s)
{
_this.arJavascripts[index] = s;
var code = _this.GetPattern(index, false, 'javascript');
index++;
return code;
}
);
return content;
},
// Example: <!-- --> => #BXHTMLCOMMENT_1#
ReplaceHtmlCommentsBySymCode: function(content)
{
this.arHtmlComments = {};
var
_this = this,
index = 0;
content = content.replace(/(<!--noindex-->)(?:[\s|\n|\r|\t]*?)<a([\s\S]*?)\/a>(?:[\s|\n|\r|\t]*?)(<!--\/noindex-->)/ig, function(s, s1, s2, s3)
{
return '<a data-bx-noindex="Y"' + s2 + '/a>';
}
);
content = content.replace(/<!--[\s\S]*?-->/ig, function(s)
{
_this.arHtmlComments[index] = s;
return _this.GetPattern(index++, false, 'html_comment');
}
);
return content;
},
// Example: <iframe src="...."></iframe> => #BXIFRAME_0#
// Also looking for embeded video
ReplaceIframeBySymCode: function(content)
{
this.arIframes = {};
var
_this = this,
index = 0;
content = content.replace(/<iframe([\s\S]*?)\/iframe>/gi, function(s, s1)
{
var video = _this.CheckForVideo(s1);
if (video)
{
_this.arVideos[index] = {
html: s,
provider: video.provider || false,
src: video.src || false
};
return _this.GetPattern(index++, false, 'video');
}
else
{
_this.arIframes[index] = s;
return _this.GetPattern(index++, false, 'iframe');
}
}
);
return content;
},
// Example: <style type="css/text"></style> => #BXSTYLE_0#
ReplaceStyleBySymCode: function(content)
{
this.arStyles = {};
var
_this = this,
index = 0;
content = content.replace(/<style[\s\S]*?\/style>/gi, function(s)
{
_this.arStyles[index] = s;
return _this.GetPattern(index++, false, 'style');
}
);
return content;
},
// Example: <audio controls=""><source src="/sound.mp3" type="audio/mpeg"> => #BXAUDIO_0#
ReplaceAudioBySymCode: function(content)
{
this.arAudio = {};
var
_this = this,
index = 0;
content = content.replace(/<audio[\s\S]*?\/audio>/gi, function(s)
{
_this.arAudio[index] = s;
return _this.GetPattern(index++, false, 'audio');
}
);
return content;
},
ReplaceObjectBySymCode: function(content)
{
this.arObjects = {};
var
_this = this,
index = 0;
content = content.replace(/<object[\s\S]*?\/object>/gi, function(s)
{
_this.arObjects[index] = s;
return _this.GetPattern(index++, false, 'object');
}
);
content = content.replace(/<embed[\s\S]*?(?:\/embed)?>/gi, function(s)
{
_this.arObjects[index] = s;
return _this.GetPattern(index++, false, 'object');
}
);
return content;
},
CheckForVideo: function(str)
{
var videoRe = new RegExp('(?:src)\\s*=\\s*("|\')([\\s\\S]*?((?:youtube.com)|(?:youtu.be)|(?:rutube.ru)|(?:vimeo.com)|(?:vk.com)|(?:' + location.host + '))[\\s\\S]*?)(\\1)', 'ig');
var res = videoRe.exec(str);
if (res)
{
return {
src: res[2],
provider: this.GetVideoProviderName(res[3], str)
};
}
else
{
return false;
}
},
GetVideoProviderName: function(host, url)
{
var name = '';
if(!BX.type.isNotEmptyString(url))
{
url = '';
}
switch (host)
{
case 'youtube.com':
case 'youtu.be':
name = 'YouTube';
break;
case 'rutube.ru':
name = 'Rutube';
break;
case 'vimeo.com':
name = 'Vimeo';
break;
case 'vk.com':
name = 'Vk';
break;
case location.host:
var providerRe = /((?:provider))=([\S]+)(?:&*)/ig;
res = providerRe.exec(url);
if(res)
{
name = res[2];
}
break;
}
return name;
},
SavePhpCode: function(code, index)
{
this.arScripts[index] = code;
return this.GetPhpPattern(index, false);
},
GetPhpPattern: function(ind, bRegexp)
{
if (bRegexp)
return new RegExp('#BXPHP_' + ind + '#', 'ig');
else
return '#BXPHP_' + ind + '#';
},
GetPattern: function(ind, bRegexp, entity)
{
var code;
switch (entity)
{
case 'php':
code = '#BXPHP_';
break;
case 'javascript':
code = '#BXJAVASCRIPT_';
break;
case 'html_comment':
code = '#BXHTMLCOMMENT_';
break;
case 'iframe':
code = '#BXIFRAME_';
break;
case 'style':
code = '#BXSTYLE_';
break;
case 'video':
code = '#BXVIDEO_';
break;
case 'audio':
code = '#BXAUDIO_';
break;
case 'object':
code = '#BXOBJECT_';
break;
default:
return '';
}
return bRegexp ? new RegExp(code + ind + '#', 'ig') : code + ind + '#';
},
// Example:
// #BXPHP0# => <img ... />
ParseSymCode: function(content)
{
var _this = this;
content = content.replace(/#BX(PHP|JAVASCRIPT|HTMLCOMMENT|IFRAME|STYLE|VIDEO|AUDIO|OBJECT)_(\d+)#/g, function(str, type, ind)
{
var res = '';
if (_this.IsAllowed(type.toLowerCase()))
{
switch (type)
{
case 'PHP':
res = _this.GetPhpCodeHTML(_this.arScripts[ind]);
break;
case 'JAVASCRIPT':
res = _this.GetJavascriptCodeHTML(_this.arJavascripts[ind]);
break;
case 'HTMLCOMMENT':
res = _this.GetHtmlCommentHTML(_this.arHtmlComments[ind]);
break;
case 'IFRAME':
res = _this.GetIframeHTML(_this.arIframes[ind]);
break;
case 'STYLE':
res = _this.GetStyleHTML(_this.arStyles[ind]);
break;
case 'VIDEO':
res = _this.GetVideoHTML(_this.arVideos[ind]);
break;
case 'AUDIO':
res = _this.GetAudioHTML(_this.arAudio[ind]);
break;
case 'OBJECT':
res = _this.GetObjectHTML(_this.arObjects[ind]);
break;
}
}
return res || str;
});
return content;
},
GetPhpCodeHTML: function(code)
{
if (typeof code !== 'string')
return null;
var
result = '',
component = this.editor.components.IsComponent(code);
if (component !== false) // It's Bitrix Component
{
var
cData = this.editor.components.GetComponentData(component.name),
name = cData.title || component.name,
title = (cData.params && cData.params.DESCRIPTION) ? cData.params.DESCRIPTION : title;
if (cData.className)
{
component.className = cData.className || '';
}
result = this.GetSurrogateHTML('component', name, title, component);
}
else // ordinary PHP code
{
if (this.editor.allowPhp)
{
result = this.GetSurrogateHTML("php", BX.message('BXEdPhpCode'), BX.message('BXEdPhpCode') + ": " + this.GetShortTitle(code, 200), {value : code});
}
else
{
// TODO: add warning for here (access denied or smth )
result = '';
}
}
return result;
},
GetJavascriptCodeHTML: function(code)
{
if (typeof code !== 'string')
return null;
return this.GetSurrogateHTML("javascript", "Javascript", "Javascript: " + this.GetShortTitle(code, 200), {value : code});
},
GetHtmlCommentHTML: function(code)
{
if (typeof code !== 'string')
return null;
return this.GetSurrogateHTML("htmlcomment", BX.message('BXEdHtmlComment'), BX.message('BXEdHtmlComment') + ": " + this.GetShortTitle(code), {value : code});
},
GetIframeHTML: function(code)
{
if (typeof code !== 'string')
return null;
return this.GetSurrogateHTML("iframe", BX.message('BXEdIframe'), BX.message('BXEdIframe') + ": " + this.GetShortTitle(code), {value : code});
},
GetStyleHTML: function(code)
{
if (typeof code !== 'string')
return null;
return this.GetSurrogateHTML("style", BX.message('BXEdStyle'), BX.message('BXEdStyle') + ": " + this.GetShortTitle(code), {value : code});
},
GetVideoHTML: function(videoParams)
{
var
tag = "video",
params = videoParams.params || this.FetchVideoIframeParams(videoParams.html, videoParams.provider);
params.value = videoParams.html;
var
id = this.editor.SetBxTag(false, {tag: tag, name: params.title, params: params}),
surrogateId = this.editor.SetBxTag(false, {tag: "surrogate_dd", params: {origParams: params, origId: id}});
this.editor.SetBxTag({id: id},
{
tag: tag,
name: params.title,
params: params,
title: params.title,
surrogateId: surrogateId
}
);
var result = '<span id="' + id + '" title="' + params.title + '" class="' + this.surrClass + ' bxhtmled-video-surrogate' + '" ' +
'style="min-width:' + params.width + 'px; max-width:' + params.width + 'px; min-height:' + params.height + 'px; max-height:' + params.height + 'px"' +
'>' +
'<img title="' + params.title + '" id="'+ surrogateId +'" class="bxhtmled-surrogate-dd" src="' + this.editor.util.GetEmptyImage() + '"/>' +
'<span class="bxhtmled-surrogate-inner"><span class="bxhtmled-video-icon"></span><span class="bxhtmled-comp-lable" spellcheck=false>' + params.title + '</span></span>' +
'</span>';
return result;
},
GetAudioHTML: function(code)
{
if (typeof code !== 'string')
return null;
var
title = "Audio",
params = this.FetchVideoIframeParams(code);
if (params && params.src)
{
title += ': ' + this.GetShortTitle(BX.util.htmlspecialchars(params.src));
}
return this.GetSurrogateHTML("audio", title, "Audio: " + this.GetShortTitle(code), {value : code});
},
GetObjectHTML: function(code)
{
return this.GetSurrogateHTML("object", BX.message('BXEdObjectEmbed'), BX.message('BXEdObjectEmbed') + ": " + this.GetShortTitle(code), {value : code});
},
FetchVideoIframeParams: function(html, provider)
{
var
attrRe = /((?:src)|(?:title)|(?:width)|(?:height))\s*=\s*("|')([\s\S]*?)(\2)/ig,
res = {
src: '',
width: 180,
height: 100,
title: provider ? BX.message('BXEdVideoTitleProvider').replace('#PROVIDER_NAME#', provider) : BX.message('BXEdVideoTitle'),
origTitle : ''
};
html.replace(attrRe, function(s, attrName, q, attrValue)
{
attrName = attrName.toLowerCase();
if (attrName == 'width' || attrName == 'height')
{
attrValue = parseInt(attrValue, 10);
if (attrValue && !isNaN(attrValue))
{
res[attrName] = attrValue;
}
}
else if (attrName == 'title')// title
{
res.origTitle = BX.util.htmlspecialcharsback(attrValue);
res.title += ': ' + attrValue;
}
else
{
res[attrName] = attrValue;
}
return s;
});
return res;
},
GetSurrogateHTML: function(tag, name, title, params)
{
if (title)
{
title = BX.util.htmlspecialchars(title);
title = title.replace('"', '\"');
}
if (!params)
{
params = {};
}
var
id = this.editor.SetBxTag(false, {tag: tag, name: name, params: params}),
surrogateId = this.editor.SetBxTag(false, {tag: "surrogate_dd", params: {origParams: params, origId: id}});
this.editor.SetBxTag({id: id}, {tag: tag, name: name, params: params, title: title, surrogateId: surrogateId});
if (!this.surrogateTags.tag)
{
this.surrogateTags.tag = 1;
}
var result = '<span id="' + id + '" title="' + (title || name) + '" class="' + this.surrClass + (params.className ? ' ' + params.className : '') + '">' +
this.GetSurrogateInner(surrogateId, title, name) +
'</span>';
return result;
},
GetSurrogateNode: function(tag, name, title, params)
{
var
doc = this.editor.GetIframeDoc(),
id = this.editor.SetBxTag(false, {tag: tag, name: name, params: params, title: title}),
surrogateId = this.editor.SetBxTag(false, {tag: "surrogate_dd", params: {origParams: params, origId: id}});
if (!params)
params = {};
this.editor.SetBxTag({id: id}, {
tag: tag,
name: name,
params: params,
title: title,
surrogateId: surrogateId
});
if (!this.surrogateTags.tag)
{
this.surrogateTags.tag = 1;
}
return BX.create('SPAN', {props: {
id: id,
title: title || name,
className: this.surrClass + (params.className ? ' ' + params.className : '')
},
html: this.GetSurrogateInner(surrogateId, title, name)
}, doc);
},
GetSurrogateInner: function(surrogateId, title, name)
{
return '<img title="' + (title || name) + '" id="'+ surrogateId +'" class="bxhtmled-surrogate-dd" src="' + this.editor.util.GetEmptyImage() + '"/>' +
'<span class="bxhtmled-surrogate-inner"><span class="bxhtmled-right-side-item-icon"></span><span class="bxhtmled-comp-lable" unselectable="on" spellcheck=false>' + BX.util.htmlspecialchars(name) + '</span></span>';
},
GetShortTitle: function(str, trim)
{
if (str.length > 100)
str = str.substr(0, 100) + '...';
return str;
},
_GetUnParsedContent: function(content)
{
var _this = this;
content = content.replace(/#BX(PHP|JAVASCRIPT|HTMLCOMMENT|IFRAME|STYLE|VIDEO|AUDIO|OBJECT)_(\d+)#/g, function(str, type, ind)
{
var res;
switch (type)
{
case 'PHP':
res = _this.arScripts[ind];
break;
case 'JAVASCRIPT':
res = _this.arJavascripts[ind];
break;
case 'HTMLCOMMENT':
res = _this.arHtmlComments[ind];
break;
case 'IFRAME':
res = _this.arIframes[ind];
break;
case 'STYLE':
res = _this.arStyles[ind];
break;
case 'VIDEO':
res = _this.arVideos[ind].html;
break;
case 'AUDIO':
res = _this.arAudio[ind];
break;
case 'OBJECT':
res = _this.arObjects[ind].html;
break;
}
return res;
});
return content;
},
IsSurrogate: function(node)
{
return node && BX.hasClass(node, this.surrClass);
},
TrimPhpBrackets: function(str)
{
if (str.substr(0, 2) != "<?")
return str;
if(str.substr(0, 5).toLowerCase()=="<?php")
str = str.substr(5);
else
str = str.substr(2);
str = str.substr(0, str.length-2);
return str;
},
TrimQuotes: function(str, qoute)
{
var f_ch, l_ch;
str = str.trim();
if (qoute == undefined)
{
f_ch = str.substr(0, 1);
l_ch = str.substr(0, 1);
if ((f_ch == '"' && l_ch == '"') || (f_ch == '\'' && l_ch == '\''))
str = str.substring(1, str.length - 1);
}
else
{
if (!qoute.length)
return str;
f_ch = str.substr(0, 1);
l_ch = str.substr(0, 1);
qoute = qoute.substr(0, 1);
if (f_ch == qoute && l_ch == qoute)
str = str.substring(1, str.length - 1);
}
return str;
},
CleanCode: function(str)
{
var
bSlashed = false,
bInString = false,
new_str = "",
i=-1, ch, ti, quote_ch;
while(i < str.length - 1)
{
i++;
ch = str.substr(i, 1);
if(!bInString)
{
if(ch == "/" && i + 1 < str.length)
{
ti = 0;
if(str.substr(i+1, 1) == "*" && ((ti = str.indexOf("*/", i + 2)) >= 0))
ti += 2;
else if(str.substr(i + 1, 1) == "/" && ((ti = str.indexOf("\n", i + 2)) >= 0))
ti += 1;
if(ti > 0)
{
if(i > ti)
alert('iti=' + i + '=' + ti);
i = ti;
}
continue;
}
if(ch == " " || ch == "\r" || ch == "\n" || ch == "\t")
continue;
}
if(bInString && ch == "\\")
{
bSlashed = true;
new_str += ch;
continue;
}
if(ch == "\"" || ch == "'")
{
if(bInString)
{
if(!bSlashed && quote_ch == ch)
bInString = false;
}
else
{
bInString = true;
quote_ch = ch;
}
}
bSlashed = false;
new_str += ch;
}
return new_str;
},
ParseFunction: function(str)
{
var
pos = str.indexOf("("),
lastPos = str.lastIndexOf(")");
if(pos >= 0 && lastPos >= 0 && pos<lastPos)
return {name:str.substr(0, pos),params:str.substring(pos+1,lastPos)};
return false;
},
ParseParameters: function(str)
{
str = this.CleanCode(str);
var
prevAr = this.GetParams(str),
tq, j, l = prevAr.length;
for (j = 0; j < l; j++)
{
if (prevAr[j].substr(0, 6).toLowerCase()=='array('
|| prevAr[j].substr(0, 1).toLowerCase()=='[')
{
prevAr[j] = this.GetArray(prevAr[j]);
}
else
{
tq = this.TrimQuotes(prevAr[j]);
if (this.IsNum(tq) || prevAr[j] != tq)
prevAr[j] = tq;
else
prevAr[j] = this.WrapPhpBrackets(prevAr[j]);
}
}
return prevAr;
},
GetArray: function(str)
{
var
php7ArrayStyle = str.substr(0, 1).toLowerCase() == '[',
resAr = {};
if (str.substr(0, 6).toLowerCase() != 'array(' && !php7ArrayStyle)
{
return str;
}
str = str.substring(php7ArrayStyle ? 1 : 6, str.length - 1);
var
tempAr = this.GetParams(str),
propKey, propValue, p, trimedPropValue,
y;
for (y = 0; y < tempAr.length; y++)
{
if (tempAr[y].substr(0, 6).toLowerCase() == 'array('
|| tempAr[y].substr(0, 1).toLowerCase() == '[')
{
resAr[y] = this.GetArray(tempAr[y]);
continue;
}
p = tempAr[y].indexOf("=>");
if (p == -1)
{
if (tempAr[y] == this.TrimQuotes(tempAr[y]))
resAr[y] = this.WrapPhpBrackets(tempAr[y]);
else
resAr[y] = this.TrimQuotes(tempAr[y]);
}
else
{
propKey = this.TrimQuotes(tempAr[y].substr(0, p));
propValue = tempAr[y].substr(p + 2);
trimedPropValue = this.TrimQuotes(propValue);
if (propValue == trimedPropValue)
{
propValue = this.WrapPhpBrackets(propValue);
if (propValue.substr(0, 6).toLowerCase()=='array('
|| propValue.substr(0, 1).toLowerCase()=='[')
{
propValue = this.GetArray(propValue);
}
}
else
{
propValue = this.TrimQuotes(propValue);
}
resAr[propKey] = propValue;
}
}
return resAr;
},
WrapPhpBrackets: function(str)
{
str = str.trim();
var
f_ch = str.substr(0, 1),
l_ch = str.substr(0, 1);
if ((f_ch == '"' && l_ch == '"') || (f_ch == '\'' && l_ch == '\''))
return str;
return "={" + str + "}";
},
GetParams: function(params)
{
var
paramsList = [],
bracket = 0,
sk = 0, ch, sl, q1 = 1, q2 = 1, i,
param_tmp = "";
for(i = 0; i < params.length; i++)
{
ch = params.substr(i, 1);
if (ch == "\"" && q2 == 1 && !sl)
{
q1 *= -1;
}
else if (ch == "'" && q1 == 1 && !sl)
{
q2 *=-1;
}
else if(ch == "\\" && !sl)
{
sl = true;
param_tmp += ch;
continue;
}
if (sl)
sl = false;
if (q2 == -1 || q1 == -1)
{
param_tmp += ch;
continue;
}
if(ch == "[")
{
bracket++;
}
else if(ch == "]")
{
bracket--;
}
else if(ch == "(")
{
sk++;
}
else if(ch == ")")
{
sk--;
}
else if(ch == "," && bracket == 0 && sk == 0)
{
paramsList.push(param_tmp);
param_tmp = "";
continue;
}
if(sk < 0 || bracket < 0)
{
break;
}
param_tmp += ch;
}
if(param_tmp != "")
{
paramsList.push(param_tmp);
}
return paramsList;
},
IsNum: function(val)
{
var _val = val;
val = parseFloat(_val);
if (isNaN(val))
val = parseInt(_val);
if (!isNaN(val))
return _val == val;
return false;
},
ParseBxNodes: function(content)
{
var
i,
//skipBxNodeIds = [],
bxNodes = this.editor.parser.convertedBxNodes,
l = bxNodes.length;
for(i = 0; i < l; i++)
{
if (bxNodes[i].tag == 'surrogate_dd')
{
content = content.replace('~' + bxNodes[i].params.origId + '~', '');
}
}
this._skipNodeIndex = {}; //_skipNodeIndex - used in Chrome to prevent double parsing of surrogates
this._skipNodeList = [];
var _this = this;
content = content.replace(/~(bxid\d{1,9})~/ig, function(s, bxid)
{
if (!_this._skipNodeIndex[bxid])
{
var bxTag = _this.editor.GetBxTag(bxid);
if (bxTag && bxTag.tag)
{
var node = _this.GetBxNode(bxTag.tag);
if (node)
{
return node.Parse(bxTag.params, bxid);
}
}
}
return '';
});
return content;
},
// Describe all available surrogates here
GetBxNodeList: function()
{
var _this = this;
this.arBxNodes = {
component: {
Parse: function(params, bxid)
{
return _this.editor.components.GetSource(params, bxid);
}
},
component_icon: {
Parse: function(params)
{
return _this.editor.components.GetOnDropHtml(params);
}
},
surrogate_dd: {
Parse: function(params)
{
if (BX.browser.IsFirefox() || !params || !params.origId)
{
return '';
}
var bxTag = _this.editor.GetBxTag(params.origId);
if (bxTag)
{
_this._skipNodeIndex[params.origId] = true;
_this._skipNodeList.push(params.origId);
var origNode = _this.GetBxNode(bxTag.tag);
if (origNode)
{
return origNode.Parse(bxTag.params);
}
}
return '#parse surrogate_dd#';
}
},
php: {
Parse: function(params)
{
return _this._GetUnParsedContent(params.value);
}
},
php_protected: {
Parse: function(params)
{
return params.value;
}
},
javascript: {
Parse: function(params)
{
return _this._GetUnParsedContent(params.value);
}
},
htmlcomment: {
Parse: function(params)
{
return _this._GetUnParsedContent(params.value);
}
},
iframe: {
Parse: function(params)
{
return _this._GetUnParsedContent(params.value);
}
},
style: {
Parse: function(params)
{
return _this._GetUnParsedContent(params.value);
}
},
video: {
Parse: function(params)
{
return _this._GetUnParsedContent(params.value);
}
},
audio: {
Parse: function(params)
{
return _this._GetUnParsedContent(params.value);
}
},
object: {
Parse: function(params)
{
return _this._GetUnParsedContent(params.value);
}
},
anchor: {
Parse: function(params)
{
var strAtr = '';
if (params.attributes)
{
for (var k in params.attributes)
{
if (params.attributes.hasOwnProperty(k))
{
strAtr += k + '="' + params.attributes[k] + '" ';
}
}
}
return '<a ' + strAtr + (params.name ? 'name="' + params.name + '"' : '') + '>' + params.html + '</a>';
}
},
pagebreak: {
Parse: function(params)
{
return '<BREAK />';
}
},
printbreak: {
Parse: function(params)
{
return '<div style="page-break-after: always">' + params.innerHTML + '</div>';
}
}
};
this.editor.On("OnGetBxNodeList");
return this.arBxNodes;
},
AddBxNode: function(key, node)
{
if (this.arBxNodes == undefined)
{
var _this = this;
BX.addCustomEvent(this.editor, "OnGetBxNodeList", function(){
_this.arBxNodes[key] = node;
});
}
else
{
this.arBxNodes[key] = node;
}
},
GetBxNode: function(tag)
{
if (!this.arBxNodes)
{
this.arBxNodes = this.GetBxNodeList();
}
return this.arBxNodes[tag] || null;
},
OnSurrogateMousedown: function(e, target, bxTag)
{
var _this = this;
// User clicked to surrogate icon
if (bxTag.tag == 'surrogate_dd')
{
BX.bind(target, 'dragstart', function(e){_this.OnSurrogateDragStart(e, this)});
BX.bind(target, 'dragend', function(e){_this.OnSurrogateDragEnd(e, this, bxTag)});
}
else
{
setTimeout(function()
{
var node = _this.CheckParentSurrogate(_this.editor.selection.GetSelectedNode());
if(node)
{
_this.editor.selection.SetAfter(node);
if (!node.nextSibling || node.nextSibling.nodeType != 3)
{
var invisText = _this.editor.util.GetInvisibleTextNode();
_this.editor.selection.InsertNode(invisText);
_this.editor.selection.SetAfter(invisText);
}
}
}, 0);
}
},
OnSurrogateDragEnd: function(e, target, bxTag)
{
if (!document.querySelectorAll)
return;
var
doc = this.editor.GetIframeDoc(),
i, surr, surBxTag,
usedSurrs = {},
surrs = doc.querySelectorAll('.bxhtmled-surrogate'),
surrs_dd = doc.querySelectorAll('.bxhtmled-surrogate-dd'),
l = surrs.length;
for (i = 0; i < surrs_dd.length; i++)
{
if (surrs_dd[i] && surrs_dd[i].id == bxTag.id)
{
BX.remove(surrs_dd[i]);
}
}
for (i = 0; i < l; i++)
{
surr = surrs[i];
if (usedSurrs[surr.id])
{
if (surr.getAttribute('data-bx-paste-flag') == 'Y' || !usedSurrs[surr.id].getAttribute('data-bx-paste-flag'))
BX.remove(surr);
else if (usedSurrs[surr.id].getAttribute('data-bx-paste-flag'))
BX.remove(usedSurrs[surr.id]);
}
else
{
usedSurrs[surr.id] = surr;
surBxTag = this.editor.GetBxTag(surr.id);
surr.innerHTML = this.GetSurrogateInner(surBxTag.surrogateId, surBxTag.title, surBxTag.name);
}
}
},
OnSurrogateDragStart: function(e, target)
{
// We need to append it to body to prevent loading picture in Firefox
if (BX.browser.IsFirefox())
{
this.editor.GetIframeDoc().body.appendChild(target);
}
},
CheckParentSurrogate: function(n)
{
if (!n)
{
return false;
}
if (this.IsSurrogate(n))
{
return n;
}
var
_this = this,
iter = 0,
parentSur = BX.findParent(n, function(node)
{
return (iter++ > 4) || _this.IsSurrogate(node);
}, this.editor.GetIframeDoc().body);
return this.IsSurrogate(parentSur) ? parentSur : false;
},
CheckSurrogateDd: function(n)
{
return n && n.nodeType == 1 && this.editor.GetBxTag(n).tag == 'surrogate_dd';
},
OnSurrogateClick: function(e, target)
{
var bxTag = this.editor.GetBxTag(target);
// User clicked to component icon
if (bxTag && bxTag.tag == 'surrogate_dd')
{
var origTag = this.editor.GetBxTag(bxTag.params.origId);
this.editor.On("OnSurrogateClick", [bxTag, origTag, target, e]);
}
},
OnSurrogateDblClick: function(e, target)
{
var bxTag = this.editor.GetBxTag(target);
// User clicked to component icon
if (bxTag && bxTag.tag == 'surrogate_dd')
{
var origTag = this.editor.GetBxTag(bxTag.params.origId);
this.editor.On("OnSurrogateDblClick", [bxTag, origTag, target, e]);
}
},
OnSurrogateKeyup: function(e, keyCode, command, target)
{
var
sur, bxTag,
range = this.editor.selection.GetRange();
if (range)
{
// Collapsed selection
if (range.collapsed)
{
}
else
{
}
}
},
OnSurrogateKeydown: function(e, keyCode, command, target)
{
var
sur,
codes = this.editor.KEY_CODES,
range = this.editor.selection.GetRange(),
invisText,
bxTag, surNode,
node = target;
if (!range || !range.getNodes)
return;
if (!range.collapsed)
{
if (keyCode === codes['backspace'] || keyCode === codes['delete'])
{
var
i,
nodes = range.getNodes([3]);
for (i = 0; i < nodes.length; i++)
{
sur = this.editor.util.CheckSurrogateNode(nodes[i]);
if (sur)
{
bxTag = this.editor.GetBxTag(sur);
if (this.surrogateTags[bxTag.tag])
{
this.RemoveSurrogate(sur, bxTag);
}
}
}
}
}
if (keyCode === codes['delete'] && range.collapsed)
{
invisText = this.editor.util.GetInvisibleTextNode();
this.editor.selection.InsertNode(invisText);
this.editor.selection.SetAfter(invisText);
var nodeNextToCarret = invisText.nextSibling;
if (nodeNextToCarret)
{
if (nodeNextToCarret && nodeNextToCarret.nodeName == 'BR')
{
nodeNextToCarret = nodeNextToCarret.nextSibling;
}
if (nodeNextToCarret && nodeNextToCarret.nodeType == 3 && (nodeNextToCarret.nodeValue == '\n' || this.editor.util.IsEmptyNode(nodeNextToCarret)))
{
nodeNextToCarret = nodeNextToCarret.nextSibling;
}
if (nodeNextToCarret)
{
BX.remove(invisText);
bxTag = this.editor.GetBxTag(nodeNextToCarret);
if (this.surrogateTags[bxTag.tag])
{
this.RemoveSurrogate(nodeNextToCarret, bxTag);
return BX.PreventDefault(e);
}
}
}
}
else if (keyCode === codes['backspace'] && range.collapsed)
{
invisText = this.editor.util.GetInvisibleTextNode();
this.editor.selection.InsertNode(invisText);
this.editor.selection.SetAfter(invisText);
var nodeBeforeCarret = this.editor.util.GetPreviousNotEmptySibling(invisText);
if (nodeBeforeCarret && this.editor.phpParser.IsSurrogate(nodeBeforeCarret))
{
BX.remove(nodeBeforeCarret);
if (invisText)
BX.remove(invisText);
return BX.PreventDefault(e);
}
else
{
if (invisText)
BX.remove(invisText);
}
}
if (range.startContainer &&
range.startContainer == range.endContainer &&
range.startContainer.nodeName !== 'BODY')
{
node = range.startContainer;
surNode = this.editor.util.CheckSurrogateNode(node);
if (surNode)
{
bxTag = this.editor.GetBxTag(surNode.id);
if (keyCode === codes['backspace'] || keyCode === codes['delete'])
{
this.RemoveSurrogate(surNode, bxTag);
BX.PreventDefault(e);
}
else if (keyCode === codes['left'] || keyCode === codes['up'])
{
var prevToSur = surNode.previousSibling;
if (prevToSur && prevToSur.nodeType == 3 && this.editor.util.IsEmptyNode(prevToSur))
this.editor.selection._MoveCursorBeforeNode(prevToSur);
else
this.editor.selection._MoveCursorBeforeNode(surNode);
return BX.PreventDefault(e);
}
else if (keyCode === codes['right'] || keyCode === codes['down'])
{
var nextToSur = surNode.nextSibling;
if (nextToSur && nextToSur.nodeType == 3 && this.editor.util.IsEmptyNode(nextToSur))
this.editor.selection._MoveCursorAfterNode(nextToSur);
else
this.editor.selection._MoveCursorAfterNode(surNode);
return BX.PreventDefault(e);
}
else if (keyCode === codes.shift || keyCode === codes.ctrl || keyCode === codes.alt || keyCode === codes.cmd || keyCode === codes.cmdRight)
{
return BX.PreventDefault(e);
}
else
{
this.editor.selection._MoveCursorAfterNode(surNode);
}
}
}
},
RemoveSurrogate: function(node, bxTag)
{
this.editor.undoManager.Transact();
BX.remove(node);
this.editor.On("OnSurrogateRemove", [node, bxTag]);
},
CheckHiddenSurrogateDrag: function()
{
var dd, i;
for (i = 0; i < this.hiddenDd.length; i++)
{
dd = this.editor.GetIframeElement(this.hiddenDd[i]);
if (dd)
{
dd.style.visibility = '';
}
}
this.hiddenDd = [];
},
GetAllSurrogates: function(bGetAll)
{
if (!document.querySelectorAll)
return [];
bGetAll = bGetAll === true;
var
doc = this.editor.GetIframeDoc(),
res = [], i, surr, bxTag,
surrs = doc.querySelectorAll(".bxhtmled-surrogate");
for (i = 0; i < surrs.length; i++)
{
surr = surrs[i];
bxTag = this.editor.GetBxTag(surr.id);
if (bxTag.tag || bGetAll)
{
res.push({
node : surr,
bxTag : bxTag
});
}
}
return res;
},
RenewSurrogates: function()
{
var
bCheck = true,
i, idInd = {}, id,
surrs = this.GetAllSurrogates(true);
for (i = 0; i < surrs.length; i++)
{
if (!surrs[i].bxTag.tag)
{
BX.remove(surrs[i].node);
continue;
}
id = surrs[i].bxTag.surrogateId;
if (!idInd[id] || !bCheck)
{
idInd[id] = id;
surrs[i].node.innerHTML = this.GetSurrogateInner(surrs[i].bxTag.surrogateId, surrs[i].bxTag.title, surrs[i].bxTag.name);
}
else
{
BX.remove(surrs[i].node);
}
}
},
RedrawSurrogates: function()
{
var i, surrs = this.GetAllSurrogates();
for (i = 0; i < surrs.length; i++)
{
if (surrs[i].node)
{
BX.addClass(surrs[i].node, 'bxhtmled-surrogate-tmp');
}
}
setTimeout(function(){
for (i = 0; i < surrs.length; i++)
{
if (surrs[i].node)
{
BX.removeClass(surrs[i].node, 'bxhtmled-surrogate-tmp');
}
}
}, 0);
},
IsAllowed: function(id)
{
return this.allowed[id];
},
AdvancedPhpParse: function(content)
{
if (this.bUseAPP)
{
this.arAPPFragments = [];
//content = this.AdvancedPhpParseBetweenTableTags(content);
content = this.AdvancedPhpParseInAttributes(content);
}
return content;
},
AdvancedPhpParseBetweenTableTags: function(str)
{
var _this = this;
function replacePHP_before(str, b1, b2, b3, b4)
{
_this.arAPPFragments.push(JS_addslashes(b1));
return b2 + b3 + ' data-bx-php-before=\"#BXAPP' + (_this.arAPPFragments.length - 1) + '#\" ' + b4;
};
function replacePHP_after(str, b1, b2, b3, b4)
{
_this.arAPPFragments.push(JS_addslashes(b4));
return b1+'>'+b3+'<'+b2+' style="display:none;" data-bx-php-after=\"#BXAPP'+(_this.arAPPFragments.length-1)+'#\"></'+b2+'>';
};
var
arTags_before = _this.APPConfig.arTags_before,
arTags_after = _this.APPConfig.arTags_after,
tagName,
i,
re;
// PHP fragments before tags
for (i = 0; i < arTags_before.length; i++)
{
tagName = arTags_before[i];
if (_this.limit_php_access)
re = new RegExp('#(PHP(?:\\d{4}))#(\\s*)(<'+tagName+'[^>]*?)(>)',"ig");
else
re = new RegExp('<\\?(.*?)\\?>(\\s*)(<'+tagName+'[^>]*?)(>)',"ig");
str = str.replace(re, replacePHP_before);
}
// PHP fragments after tags
for (i = 0,l = arTags_after.length; i<l; i++)
{
tagName = arTags_after[i];
if (_this.limit_php_access)
re = new RegExp('(</('+tagName+')[^>]*?)>(\\s*)#(PHP(?:\\d{4}))#',"ig");
else
re = new RegExp('(</('+tagName+')[^>]*?)>(\\s*)<\\?(.*?)\\?>',"ig");
str = str.replace(re, replacePHP_after);
}
return str;
},
AdvancedPhpParseInAttributes: function(str)
{
var
_this = this,
arTags = this.APPConfig.arTags,
tagName, atrName, i, re;
function replacePhpInAttributes(str, b1, b2, b3, b4, b5, b6)
{
var appInd, atrValue;
if (b4.match(/#PHP\d+#/g))
{
_this.arAPPFragments.push(b4);
appInd = _this.arAPPFragments.length - 1;
atrValue = '#BXAPP' + appInd + '#';
return b1 + b2 + '="' + atrValue + '"' + b5;
}
if (b4.indexOf('#BXPHP_') === -1)
{
return str;
}
_this.arAPPFragments.push(b4);
appInd = _this.arAPPFragments.length - 1;
atrValue = _this.AdvancedPhpGetFragmentByIndex(appInd, true);
return b1 + b2 + '="' + atrValue + '"' + ' data-bx-app-ex-' + b2 + '=\"#BXAPP' + appInd + '#\"' + b5;
}
for (tagName in arTags)
{
if (arTags.hasOwnProperty(tagName))
{
for (i = 0; i < arTags[tagName].length; i++)
{
atrName = arTags[tagName][i];
re = new RegExp('(<' + tagName + '(?:[^>](?:\\?>)*?)*?)(' + atrName + ')\\s*=\\s*((?:"|\')?)([\\s\\S]*?)\\3((?:[^>](?:\\?>)*?)*?>)', "ig");
str = str.replace(re, replacePhpInAttributes);
}
}
}
return str;
},
AdvancedPhpUnParse: function(content)
{
return content;
},
AdvancedPhpGetFragmentByCode: function(code, handleSiteTemplate)
{
var appInd = code.substr(6); // #BXAPP***#
appInd = parseInt(appInd.substr(0, appInd.length - 1), 10);
return this.AdvancedPhpGetFragmentByIndex(appInd, handleSiteTemplate);
},
AdvancedPhpGetFragmentByIndex: function(appInd, handleSiteTemplate)
{
var
_this = this,
appStr = this.arAPPFragments[appInd];
appStr = appStr.replace(/#BXPHP_(\d+)#/g, function(str, ind)
{
var res = _this.arScripts[parseInt(ind, 10)];
if (handleSiteTemplate)
{
var stp = _this.GetSiteTemplatePath();
if(stp)
{
res = res.replace(/<\?=\s*SITE_TEMPLATE_PATH;?\s*\?>/i, stp);
res = res.replace(/<\?\s*echo\s*SITE_TEMPLATE_PATH;?\s*\?>/i, stp);
}
}
return res;
});
return appStr;
},
ParseBreak: function(content)
{
var _this = this;
content = content.replace(/<break\s*\/*>/gi, function(s)
{
return _this.GetSurrogateHTML("pagebreak", BX.message('BXEdPageBreakSur'), BX.message('BXEdPageBreakSurTitle'));
}
);
return content;
},
GetSiteTemplatePath: function()
{
return this.editor.GetTemplateParams().SITE_TEMPLATE_PATH;
},
CustomContentParse: function(content)
{
for (var i = 0; i < this.customParsers.length; i++)
{
if (typeof this.customParsers[i] == 'function')
{
content = this.customParsers[i](content);
}
}
return content;
},
AddCustomParser: function(parser)
{
if (typeof parser == 'function')
this.customParsers.push(parser);
}
};
function BXEditorBbCodeParser(editor)
{
this.editor = editor;
this.parseAlign = true;
}
BXEditorBbCodeParser.prototype = {
Unparse: function(content) // HTML - > Bbcode
{
var el = this.editor.parser.GetAsDomElement(content, this.editor.GetIframeDoc());
el.setAttribute('data-bx-parent-node', 'Y');
content = this.GetNodeHtml(el, true);
content = content.replace(/#BR#/ig, "\n");
content = content.replace(/ /ig, " ");
content = content.replace(/\uFEFF/ig, '');
return content;
},
Parse: function(content) // // BBCode -> HTML
{
var _this = this, i, l;
content = content.replace(/</ig, "<");
content = content.replace(/>/ig, ">");
function secureAtr(str)
{
if(!str.replace)
return str;
return str.replace(/("|<|>)/g, '');
}
// [CODE] == > #BX_CODE1#
var arCodes = [];
content = content.replace(/\[code\]((?:\s|\S)*?)\[\/code\]/ig, function(str, code)
{
arCodes.push('<pre class="bxhtmled-code">' + code + '</pre>');
return '#BX_CODE' + (arCodes.length - 1) + '#';
});
var parserName, specialParser;
for (parserName in this.editor.parser.specialParsers)
{
if (this.editor.parser.specialParsers.hasOwnProperty(parserName))
{
specialParser = this.editor.parser.specialParsers[parserName];
if (specialParser && specialParser.Parse)
{
content = specialParser.Parse(parserName, content, this.editor);
}
}
}
// * * * Handle Smiles * * *
if (this.editor.sortedSmiles)
{
var
arUrls = [],
arTags = [],
smile;
content = content.replace(/\[(?:\s|\S)*?\]/ig, function(str)
{
arTags.push(str);
return '#BX_TMP_TAG' + (arTags.length - 1) + '#';
});
content = content.replace(/(?:https?|ftp):\/\//gi, function(str)
{
arUrls.push(str);
return '#BX_TMP_URL' + (arUrls.length - 1) + '#';
});
l = this.editor.sortedSmiles.length;
var smHtml, symRe = "\\s.,;:!?\\#\\-\\*\\|\\[\\]\\(\\)\\{\\}<>&\\n\\t\\r", css;
for (i = 0; i < l; i++)
{
smile = this.editor.sortedSmiles[i];
if (smile.path && smile.code)
{
css = '';
if (smile.width)
css += 'width:' + parseInt(smile.width) + 'px;';
if (smile.height)
css += 'height:' + parseInt(smile.height) + 'px;';
if (css !== '')
css = 'style="' + css + '"';
smHtml = '<img id="' + _this.editor.SetBxTag(false, {tag: "smile", params: smile}) + '" src="' + smile.path + '" title="' + (smile.name || smile.code) + '" ' + css + '/>';
content = content.replace(
new RegExp('([' + symRe + '])' + BX.util.preg_quote(smile.code) + '([' + symRe + '])', 'ig'),
"$1" + smHtml + "$2"
);
content = content.replace(
new RegExp('([' + symRe + '])' + BX.util.preg_quote(smile.code) + '$', 'ig'),
"$1" + smHtml
);
content = content.replace(
new RegExp('^' + BX.util.preg_quote(smile.code) + '([' + symRe + '])', 'ig'),
smHtml + "$1"
);
content = content.replace(
new RegExp('^' + BX.util.preg_quote(smile.code) + '$', 'ig'),
smHtml
);
}
}
// Set urls back
if (arUrls.length > 0)
{
content = content.replace(/#BX_TMP_URL(\d+)#/ig, function(s, num){return arUrls[num] || s;});
}
// Set tags back
if (arTags.length > 0)
{
content = content.replace(/#BX_TMP_TAG(\d+)#/ig, function(s, num){return arTags[num] || s;});
}
}
// * * * Handle Smiles END * * *
// Quote
//content = content.replace(/\n?\[quote\]/ig, '<blockquote class="bxhtmled-quote">');
content = content.replace(/\[quote\]/ig, '<blockquote class="bxhtmled-quote">');
content = content.replace(/\[\/quote\]\n?/ig, '</blockquote>');
// Table
content = content.replace(/[\r\n\s\t]?\[table\][\r\n\s\t]*?\[tr\]/ig, '<table border="1">[TR]');
content = content.replace(/\[tr\][\r\n\s\t]*?\[td\]/ig, '[TR][TD]');
content = content.replace(/\[tr\][\r\n\s\t]*?\[th\]/ig, '[TR][TH]');
content = content.replace(/\[\/td\][\r\n\s\t]*?\[td\]/ig, '[/TD][TD]');
content = content.replace(/\[\/tr\][\r\n\s\t]*?\[tr\]/ig, '[/TR][TR]');
content = content.replace(/\[\/td\][\r\n\s\t]*?\[\/tr\]/ig, '[/TD][/TR]');
content = content.replace(/\[\/th\][\r\n\s\t]*?\[\/tr\]/ig, '[/TH][/TR]');
content = content.replace(/\[\/tr\][\r\n\s\t]*?\[\/table\][\r\n\s\t]?/ig, '[/TR][/TABLE]');
// List
content = content.replace(/[\r\n\s\t]*?\[\/list\]/ig, '[/LIST]');
content = content.replace(/[\r\n\s\t]*?\[\*\]?/ig, '[*]');
// Paragraph
content = content.replace(/\[p\]/ig, '<p>');
content = content.replace(/\[\/p\]\n?/ig, '</p>');
var
arSimpleTags = [
'b','u', 'i', ['s', 'del'], // B, U, I, S
'table', 'tr', 'td', 'th'//, // Table
],
bbTag, tag;
l = arSimpleTags.length;
for (i = 0; i < l; i++)
{
if (typeof arSimpleTags[i] == 'object')
{
bbTag = arSimpleTags[i][0];
tag = arSimpleTags[i][1];
}
else
{
bbTag = tag = arSimpleTags[i];
}
content = content.replace(new RegExp('\\[(\\/?)' + bbTag + '\\]', 'ig'), "<$1" + tag + ">");
}
// Link
content = content.replace(/\[url\]((?:\s|\S)*?)\[\/url\]/ig, function(str, href)
{
return '<a href="' + secureAtr(href) + '">' + href + '</a>';
});
content = content.replace(/\[url\s*=\s*((?:\s|\S)*?)\]((?:\s|\S)*?)\[\/url\]/ig, function(str, href, html)
{
return '<a href="' + secureAtr(href) + '">' + html + '</a>';
});
// Img
content = content.replace(/\[img((?:\s|\S)*?)\]((?:\s|\S)*?)\[\/img\]/ig,
function(str, params, src)
{
params = _this.FetchImageParams(params);
src = secureAtr(src);
var size = "";
if (params.width)
size += 'width:' + parseInt(params.width) + 'px;';
if (params.height)
size += 'height:' + parseInt(params.height) + 'px;';
if (size !== '')
size = 'style="' + size + '"';
return '<img src="' + src + '"' + size + '/>';
}
);
// Font color
i = 0;
while (content.toLowerCase().indexOf('[color=') != -1 && content.toLowerCase().indexOf('[/color]') != -1 && i++ < 20)
{
content = content.replace(/\[color=((?:\s|\S)*?)\]((?:\s|\S)*?)\[\/color\]/ig, function(s, value, cont){ return '<span style="color:' + secureAtr(value) + '">' + cont + '</span>' });
}
// List
i = 0;
while (content.toLowerCase().indexOf('[list=') != -1 && content.toLowerCase().indexOf('[/list]') != -1 && i++ < 20)
{
content = content.replace(/\[list=1\]((?:\s|\S)*?)\[\/list\]/ig, "<ol>$1</ol>");
}
i = 0;
while (content.toLowerCase().indexOf('[list') != -1 && content.toLowerCase().indexOf('[/list]') != -1 && i++ < 20)
{
content = content.replace(/\[list\]((?:\s|\S)*?)\[\/list\]/ig, "<ul>$1</ul>");
}
content = content.replace(/\[\*\]/ig, "<li>");
// Font
i = 0;
while (content.toLowerCase().indexOf('[font=') != -1 && content.toLowerCase().indexOf('[/font]') != -1 && i++ < 20)
{
content = content.replace(/\[font=((?:\s|\S)*?)\]((?:\s|\S)*?)\[\/font\]/ig, function(s, value, cont){ return '<span style="font-family:' + secureAtr(value) + '">' + cont + '</span>' });
}
// Font size
i = 0;
while (content.toLowerCase().indexOf('[size=') != -1 && content.toLowerCase().indexOf('[/size]') != -1 && i++ < 20)
{
content = content.replace(/\[size=((?:\s|\S)*?)\]((?:\s|\S)*?)\[\/size\]/ig, function(s, value, cont){ return '<span style="font-size:' + secureAtr(value) + '">' + cont + '</span>' });
}
if (this.parseAlign)
{
content = content.replace(/\[(center|left|right|justify)\]/ig, function(s, value){return '<div style="text-align:' + secureAtr(value) + '">';});
content = content.replace(/\[\/(center|left|right|justify)\]/ig, "</div>");
}
// VIDEO
if (content.toLowerCase().indexOf('[/video]') != -1)
{
content = content.replace(/\[video((?:\s|\S)*?)\]((?:\s|\S)*?)\[\/video\]/ig, function(s, params, src)
{
return _this.GetVideoSourse(src, _this.FetchVideoParams(params.trim(params)), s);
});
}
// Replace \n => <br/>
content = content.replace(/\n/ig, "<br />");
// Replace encoded "[", "]" by [ and ]
content = content.replace(/[/ig, "[");
content = content.replace(/]/ig, "]");
// Replace back CODE content without modifications
// #BX_CODE1# ==> <pre>...</pre>
if (arCodes.length > 0)
{
content = content.replace(/#BX_CODE(\d+)#/ig, function(s, num){return arCodes[num] || s;});
}
return content;
},
GetNodeHtml: function(node, onlyChild)
{
var
oNode = {
node: node
},
res = '';
if (!onlyChild)
{
if(node.nodeType == 3)
{
var text = BX.util.htmlspecialchars(node.nodeValue);
if (!text.match(/[^\n]+/ig) && node.previousSibling && node.nextSibling
&& this.editor.util.IsBlockNode(node.previousSibling)
&& this.editor.util.IsBlockNode(node.nextSibling))
{
return "\n";
}
// Mantis: 54329
if (BX.browser.IsChrome() && this.editor.pasteHandleMode && node.nextSibling && node.nextSibling.nodeName == 'P')
{
text = text.replace(/\n+/ig, "\n");
}
// List of tags inside of which \n will be cleaned in textNodes
if (node.parentNode && !node.parentNode.getAttribute('data-bx-parent-node') &&
BX.util.in_array(node.parentNode.nodeName, ['P', 'DIV', 'SPAN', 'TD', 'TH', 'B', 'STRONG', 'I', 'EM', 'U', 'DEL', 'S','STRIKE', 'BLOCKQUOTE']))
{
text = text.replace(/\n/ig, " ");
}
if (BX.browser.IsMac() || BX.browser.IsFirefox())
{
text = text.replace(/\n/ig, " ");
}
text = text.replace(/\[/ig, "[");
text = text.replace(/\]/ig, "]");
return text;
}
if (node.nodeType == 1 && node.nodeName == 'P')
{
var html = BX.util.trim(node.innerHTML);
html = html.replace(/[\n\r\s]/ig, "").toLowerCase();
if(html == '<br>')
{
node.innerHTML = '';
}
}
var bbRes = this.UnParseNodeBB(oNode);
if (bbRes !== false)
{
return bbRes;
}
if (oNode.bbOnlyChild)
onlyChild = true;
// Left part
if (!onlyChild)
{
if (oNode.breakLineBefore)
{
res += "\n";
}
if(node.nodeType == 1 && !oNode.hide)
{
res += "[" + oNode.bbTag;
if (oNode.bbValue)
{
res += '=' + oNode.bbValue;
}
res += "]";
}
}
}
if (oNode.checkNodeAgain)
{
res += this.GetNodeHtml(node);
}
else
{
var
i, child,
innerContent = '';
// Handle childs
for (i = 0; i < node.childNodes.length; i++)
{
child = node.childNodes[i];
innerContent += this.GetNodeHtml(child);
}
res += innerContent;
}
// Right part
if (!onlyChild)
{
if (oNode.breakLineAfter)
res += "\n";
if (innerContent == '' && this.IsPairNode(oNode.bbTag)
&& node.nodeName !== 'P'
&& node.nodeName !== 'TD'
&& node.nodeName !== 'TR'
&& node.nodeName !== 'TH')
{
return '';
}
if(node.nodeType == 1 && (node.childNodes.length > 0 || this.IsPairNode(oNode.bbTag)) && !oNode.hide && !oNode.hideRight)
{
res += "[/" + oNode.bbTag + "]";
}
if (BX.browser.IsFirefox() && this.editor.util.IsBlockNode(node)
&& BX.util.trim(node.innerHTML.replace(/\uFEFF/ig, '')).toLowerCase() == '<br>')
{
return '\n';
}
// mantis: #54244 & #100442
if (oNode.breakLineAfterEnd || node.nodeType == 1 && this.editor.util.IsBlockNode(node) && this.editor.util.IsBlockNode(this.editor.util.GetNextSibling(node)))
{
res += "\n";
}
}
return res;
},
UnParseNodeBB: function (oNode) // WYSIWYG -> BBCode
{
var
bxTag,
isTableTag, isAlign,
nodeName = oNode.node.nodeName.toUpperCase();
oNode.checkNodeAgain = false;
if (nodeName == "BR")
{
return "#BR#";
}
if (oNode.node && oNode.node.id)
{
bxTag = this.editor.GetBxTag(oNode.node.id);
if (bxTag.tag)
{
var parser = this.editor.parser.specialParsers[bxTag.tag];
if (parser && parser.UnParse)
{
return parser.UnParse(bxTag, oNode, this.editor);
}
else if (bxTag.tag == 'video')
{
return bxTag.params.value;
}
else if (bxTag.tag == 'smile')
{
return bxTag.params.code;
}
else
{
return '';
}
}
}
if (nodeName == "SCRIPT")
{
return '';
}
if (nodeName == "IFRAME" && oNode.node.src)
{
var
src = oNode.node.src.replace(/https?:\/\//ig, '//'),
video = this.editor.phpParser.CheckForVideo('src="' + src + '"');
if (video)
{
var
width = parseInt(oNode.node.width),
height = parseInt(oNode.node.height);
return '[VIDEO TYPE=' + video.provider.toUpperCase() +
' WIDTH=' + width +
' HEIGHT=' + height + ']' +
src +
'[/VIDEO]';
}
}
//[CODE] Handle code tag
if (nodeName == "PRE" && BX.hasClass(oNode.node, 'bxhtmled-code'))
{
return "[CODE]" + this.GetCodeContent(oNode.node) + "[/CODE]";
}
// Image
if (nodeName == "IMG")
{
var size = '';
if (oNode.node.style.width)
size += ' WIDTH=' + parseInt(oNode.node.style.width);
else if (oNode.node.width)
size += ' WIDTH=' + parseInt(oNode.node.width);
if (oNode.node.style.height)
size += ' HEIGHT=' + parseInt(oNode.node.style.height);
else if (oNode.node.height)
size += ' HEIGHT=' + parseInt(oNode.node.height);
return "[IMG" + size + "]" + oNode.node.src + "[/IMG]";
}
oNode.hide = false;
oNode.bbTag = nodeName;
isTableTag = BX.util.in_array(nodeName, this.editor.TABLE_TAGS);
isAlign = this.parseAlign && (oNode.node.style.textAlign || oNode.node.align) && !isTableTag;
if(nodeName == 'STRONG' || nodeName == 'B')
{
oNode.bbTag = 'B';
}
else if(nodeName == 'EM' || nodeName == 'I')
{
oNode.bbTag = 'I';
}
else if(nodeName == 'DEL' || nodeName == 'S')
{
oNode.bbTag = 'S';
}
// List
else if((nodeName == 'OL' || nodeName == 'UL'))
{
oNode.bbTag = 'LIST';
oNode.breakLineAfter = true;
oNode.bbValue = nodeName == 'OL' ? '1' : '';
}
else if(nodeName == 'LI')
{
if (oNode.node.lastChild && oNode.node.lastChild.nodeName == 'BR')
{
oNode.node.removeChild(oNode.node.lastChild);
}
oNode.bbTag = '*';
oNode.breakLineBefore = true;
oNode.hideRight = true;
}
else if(nodeName == 'A')
{
oNode.bbTag = 'URL';
oNode.bbValue = this.editor.parser.GetAttributeEx(oNode.node, 'href');
oNode.bbValue = oNode.bbValue.replace(/\[/ig, "[").replace(/\]/ig, "]");
if (oNode.bbValue === '')
{
oNode.bbOnlyChild = true;
}
}
// Color
else if(oNode.node.style.color && !isTableTag)
{
oNode.bbTag = 'COLOR';
oNode.bbValue = this.editor.util.RgbToHex(oNode.node.style.color);
oNode.node.style.color = '';
if (oNode.node.style.cssText != '')
{
oNode.checkNodeAgain = true;
}
}
// Font family
else if(oNode.node.style.fontFamily && !isTableTag)
{
oNode.bbTag = 'FONT';
oNode.bbValue = oNode.node.style.fontFamily;
oNode.node.style.fontFamily = '';
if (oNode.node.style.cssText != '')
{
oNode.checkNodeAgain = true;
}
}
// Font size
else if(oNode.node.style.fontSize && !isTableTag)
{
oNode.bbTag = 'SIZE';
oNode.bbValue = oNode.node.style.fontSize;
oNode.node.style.fontSize = '';
if (oNode.node.style.cssText != '')
{
oNode.checkNodeAgain = true;
}
}
else if(nodeName == 'BLOCKQUOTE' && oNode.node.className == 'bxhtmled-quote' && !oNode.node.getAttribute('data-bx-skip-check'))
{
oNode.bbTag = 'QUOTE';
//oNode.breakLineBefore = true;
oNode.breakLineAfterEnd = true;
if (isAlign)
{
oNode.checkNodeAgain = true;
oNode.node.setAttribute('data-bx-skip-check', 'Y');
}
}
else if(isAlign)
{
var align = oNode.node.style.textAlign || oNode.node.align;
if (BX.util.in_array(align, ['left', 'right', 'center', 'justify']))
{
oNode.hide = false;
oNode.bbTag = align.toUpperCase();
}
else
{
oNode.hide = !BX.util.in_array(nodeName, this.editor.BBCODE_TAGS);
}
}
else if(!BX.util.in_array(nodeName, this.editor.BBCODE_TAGS)) //'p', 'u', 'div', 'table', 'tr', 'img', 'td', 'a'
{
oNode.hide = true;
}
return false;
},
IsPairNode: function(text)
{
text = text.toUpperCase();
return !(text.substr(0, 1) == 'H' || text == 'BR' || text == 'IMG' || text == 'INPUT');
},
GetCodeContent: function(node) // WYSIWYG -> BBCode
{
if (!node || this.editor.util.IsEmptyNode(node))
return '';
var
i,
res = '';
for (i = 0; i < node.childNodes.length; i++)
{
if (node.childNodes[i].nodeType == 3)
res += node.childNodes[i].data;
else if (node.childNodes[i].nodeType == 1 && node.childNodes[i].nodeName == "BR")
res += "#BR#";
else
res += this.GetCodeContent(node.childNodes[i]);
}
if (BX.browser.IsIE())
res = res.replace(/\r/ig, "#BR#");
else
res = res.replace(/\n/ig, "#BR#");
res = res.replace(/\[/ig, "[");
res = res.replace(/\]/ig, "]");
return res;
},
GetVideoSourse: function(src, params, source, title)
{
title = title || BX.message.BXEdVideoTitle;
return this.editor.phpParser.GetVideoHTML({
params: {
width: params.width,
height: params.height,
title: title,
origTitle: '',
provider: params.type
},
html: source
});
},
FetchVideoParams: function(str)
{
str = BX.util.trim(str);
var
atr = str.split(' '),
i, name, val, atr_,
res = {
width: 180,
height: 100,
type: false
};
for (i = 0; i < atr.length; i++)
{
atr_ = atr[i].split('=');
name = atr_[0].toLowerCase();
val = atr_[1];
if (name == 'width' || name == 'height')
{
val = parseInt(val, 10);
if (val && !isNaN(val))
{
res[name] = Math.max(val, 100);
}
}
else if (name == 'type')
{
val = val.toUpperCase();
if (val == 'YOUTUBE' || val == 'RUTUBE' || val == 'VIMEO')
{
res[name] = val;
}
}
}
return res;
},
FetchImageParams: function(str)
{
str = BX.util.trim(str);
var
atr = str.split(' '),
i, name, val, atr_,
res = {};
for (i = 0; i < atr.length; i++)
{
atr_ = atr[i].split('=');
name = atr_[0].toLowerCase();
val = atr_[1];
if (name == 'width' || name == 'height')
{
val = parseInt(val, 10);
if (val && !isNaN(val))
{
res[name] = val;
}
}
}
return res;
}
};
function BXCodeFormatter(editor)
{
this.editor = editor;
var
ownLine = ['area', 'hr', 'i?frame', 'link', 'meta', 'noscript', 'style', 'table', 'tbody', 'thead', 'tfoot'],
contOwnLine = ['li', 'dt', 'dd', 'h[1-6]', 'option', 'script'];
this.reBefore = new RegExp('^<(/?' + ownLine.join('|/?') + '|' + contOwnLine.join('|') + ')[ >]', 'i');
this.reAfter = new RegExp('^<(br|/?' + ownLine.join('|/?') + '|/' + contOwnLine.join('|/') + ')[ >]');
var newLevel = ['blockquote', 'div', 'dl', 'fieldset', 'form', 'frameset', 'map', 'ol', 'p', 'pre', 'select', 'td', 'th', 'tr', 'ul'];
this.reLevel = new RegExp('^</?(' + newLevel.join('|') + ')[ >]');
this.lastCode = null;
this.lastResult = null;
}
BXCodeFormatter.prototype = {
Format: function(code)
{
if (code != this.lastCode)
{
this.lastCode = code;
this.lastResult = this.DoFormat(code);
}
return this.lastResult;
},
DoFormat: function(code)
{
code += ' ';
this.level = 0;
var
_this = this,
i, t,
point = 0,
start = null,
end = null,
tag = '',
result = '',
index = 0,
cont = '';
this.pieces = {};
code = code.replace(/<pre[\s\S]*?\/pre>/gi, function(s)
{
_this.pieces[index] = s;
var str = '#BX_CODE_PIECE_' + index + '#';
index++;
return str;
}
);
for (i = 0; i < code.length; i++)
{
point = i;
//if no more tags ==> exit
if (code.substr(i).indexOf('<') == -1)
{
result += code.substr(i);
result = result.replace(/\n\s*\n/g, '\n'); //blank lines
result = result.replace(/^[\s\n]*/, ''); //leading space
result = result.replace(/[\s\n]*$/, ''); //trailing space
if (result.indexOf('<!--noindex-->') !== -1)
{
result = result.replace(/(<!--noindex-->)(?:[\s|\n|\r|\t]*?)(<a[\s\S]*?\/a>)(?:[\s|\n|\r|\t]*?)(<!--\/noindex-->)(?:[\n|\r|\t]*)/ig, "$1$2$3");
}
result = result.replace(/#BX_CODE_PIECE_(\d+)#/g, function(s, ind){return (ind && _this.pieces[ind]) ? _this.pieces[ind] : s;});
return result;
}
while (point < code.length && code.charAt(point) !== '<')
{
point++;
}
if (i != point)
{
cont = code.substr(i, point - i);
if (cont.match(/^\s+$/))
{
cont = cont.replace(/\s+/g, ' ');
result += cont;
}
else
{
if (result.charAt(result.length - 1) == '\n')
{
result += this.GetTabs();
}
else if (cont.charAt(0) == '\n')
{
result += '\n' + this.GetTabs();
cont = cont.replace(/^\s+/, '');
}
cont = cont.replace(/\n/g, ' ');
cont = cont.replace(/\n+/g, '');
cont = cont.replace(/\s+/g, ' ');
result += cont;
}
if (cont.match(/\n/))
{
result += '\n' + this.GetTabs();
}
}
start = point;
//find the end of the tag
while (point < code.length && code.charAt(point) != '>')
{
point++;
}
tag = code.substr(start, point - start);
i = point;
//if this is a special tag, deal with it
if (tag.substr(1, 3) === '!--')
{
if (!tag.match(/--$/))
{
while (code.substr(point, 3) !== '-->')
{
point++;
}
point += 2;
tag = code.substr(start, point - start);
i = point;
}
if (result.charAt(result.length - 1) !== '\n')
{
result += '\n';
}
result += this.GetTabs();
result += tag + '>\n';
}
else if (tag[1] === '!')
{
result = this.PutTag(tag + '>', result);
}
else if (tag[1] == '?')
{
result += tag + '>\n';
}
else if (t = tag.match(/^<(script|style)/i))
{
t[1] = t[1].toLowerCase();
result = this.PutTag(this.CleanTag(tag), result);
//end = String(code.substr(i + 1)).indexOf('</' + t[1]);
end = String(code.substr(i + 1)).toLowerCase().indexOf('</' + t[1]);
if (end)
{
cont = code.substr(i + 1, end);
i += end;
result += cont;
}
}
else
{
result = this.PutTag(this.CleanTag(tag), result);
}
}
code = code.replace(/#BX_CODE_PIECE_(\d+)#/g, function(s, ind){return (ind && _this.pieces[ind]) ? _this.pieces[ind] : s;});
return code;
},
GetTabs: function()
{
var s = '', j;
for (j = 0; j < this.level; j++)
{
s += '\t';
}
return s;
},
CleanTag: function(tag)
{
var
m,
partRe = /\s*([^= ]+)(?:=((['"']).*?\3|[^ ]+))?/,
result = '',
suffix = '';
tag = tag.replace(/\n/g, ' '); //remove newlines
tag = tag.replace(/[\s]{2,}/g, ' '); //collapse whitespace
tag = tag.replace(/^\s+|\s+$/g, ' '); //collapse whitespace
if (tag.match(/\/$/))
{
suffix = '/';
tag = tag.replace(/\/+$/, '');
}
while (m = partRe.exec(tag))
{
if (m[2])
result += m[1] + '=' + m[2];
else if (m[1])
result += m[1];
result += ' ';
tag = tag.substr(m[0].length);
}
return result.replace(/\s*$/, '') + suffix + '>';
},
PutTag: function(tag, res)
{
var nl = tag.match(this.reLevel);
if (tag.match(this.reBefore) || nl)
{
res = res.replace(/\s*$/, '');
res += "\n";
}
if (nl && tag.charAt(1) == '/')
{
this.level--;
}
if (res.charAt(res.length-1) == '\n')
{
res += this.GetTabs();
}
if (nl && '/' != tag.charAt(1))
{
this.level++;
}
res += tag;
if (tag.match(this.reAfter) || tag.match(this.reLevel))
{
res = res.replace(/ *$/, '');
res += "\n";
}
return res;
}
};
function __run()
{
window.BXHtmlEditor.BXCodeFormatter = BXCodeFormatter;
window.BXHtmlEditor.BXEditorParser = BXEditorParser;
window.BXHtmlEditor.BXEditorPhpParser = BXEditorPhpParser;
window.BXHtmlEditor.BXEditorBbCodeParser = BXEditorBbCodeParser;
}
if (window.BXHtmlEditor)
{
__run();
}
else
{
BX.addCustomEvent(window, "OnBXHtmlEditorInit", __run);
}
})();