function _getCssList(css) {
css = css.replace(/"/g, '"');
var list = {},
reg = /\s*([\w\-]+)\s*:([^;]*)(;|$)/g,
match;
while ((match = reg.exec(css))) {
var key = _trim(match[1].toLowerCase()),
val = _trim(_toHex(match[2]));
list[key] = val;
}
return list;
}
function _getAttrList(tag) {
var list = {},
reg = /\s+(?:([\w\-:]+)|(?:([\w\-:]+)=([^\s"'<>]+))|(?:([\w\-:"]+)="([^"]*)")|(?:([\w\-:"]+)='([^']*)'))(?=(?:\s|\/|>)+)/g,
match;
while ((match = reg.exec(tag))) {
var key = (match[1] || match[2] || match[4] || match[6]).toLowerCase(),
val = (match[2] ? match[3] : (match[4] ? match[5] : match[7])) || '';
list[key] = val;
}
return list;
}
function _addClassToTag(tag, className) {
if (/\s+class\s*=/.test(tag)) {
tag = tag.replace(/(\s+class=["']?)([^"']*)(["']?[\s>])/, function($0, $1, $2, $3) {
if ((' ' + $2 + ' ').indexOf(' ' + className + ' ') < 0) {
return $2 === '' ? $1 + className + $3 : $1 + $2 + ' ' + className + $3;
} else {
return $0;
}
});
} else {
tag = tag.substr(0, tag.length - 1) + ' class="' + className + '">';
}
return tag;
}
function _formatCss(css) {
var str = '';
_each(_getCssList(css), function(key, val) {
str += key + ':' + val + ';';
});
return str;
}
function _formatUrl(url, mode, host, pathname) {
mode = _undef(mode, '').toLowerCase();
// 移除连续斜线,比如,http://localhost/upload/file/201205//maincus.swf
// base64 data 除外
if (url.substr(0, 5) != 'data:') {
url = url.replace(/([^:])\/\//g, '$1/');
}
if (_inArray(mode, ['absolute', 'relative', 'domain']) < 0) {
return url;
}
host = host || location.protocol + '//' + location.host;
if (pathname === undefined) {
var m = location.pathname.match(/^(\/.*)\//);
pathname = m ? m[1] : '';
}
var match;
if ((match = /^(\w+:\/\/[^\/]*)/.exec(url))) {
if (match[1] !== host) {
return url;
}
} else if (/^\w+:/.test(url)) {
return url;
}
function getRealPath(path) {
var parts = path.split('/'), paths = [];
for (var i = 0, len = parts.length; i < len; i++) {
var part = parts[i];
if (part == '..') {
if (paths.length > 0) {
paths.pop();
}
} else if (part !== '' && part != '.') {
paths.push(part);
}
}
return '/' + paths.join('/');
}
if (/^\//.test(url)) {
url = host + getRealPath(url.substr(1));
} else if (!/^\w+:\/\//.test(url)) {
url = host + getRealPath(pathname + '/' + url);
}
function getRelativePath(path, depth) {
if (url.substr(0, path.length) === path) {
var arr = [];
for (var i = 0; i < depth; i++) {
arr.push('..');
}
var prefix = '.';
if (arr.length > 0) {
prefix += '/' + arr.join('/');
}
if (pathname == '/') {
prefix += '/';
}
return prefix + url.substr(path.length);
} else {
if ((match = /^(.*)\//.exec(path))) {
return getRelativePath(match[1], ++depth);
}
}
}
if (mode === 'relative') {
url = getRelativePath(host + pathname, 0).substr(2);
} else if (mode === 'absolute') {
if (url.substr(0, host.length) === host) {
url = url.substr(host.length);
}
}
return url;
}
function _formatHtml(html, htmlTags, urlType, wellFormatted, indentChar) {
// null or undefined: object == null
if (html == null) {
html = '';
}
urlType = urlType || '';
wellFormatted = _undef(wellFormatted, false);
indentChar = _undef(indentChar, '\t');
var fontSizeList = 'xx-small,x-small,small,medium,large,x-large,xx-large'.split(',');
// 将pre里的br转换成\n
html = html.replace(/(<(?:pre|pre\s[^>]*)>)([\s\S]*?)(<\/pre>)/ig, function($0, $1, $2, $3) {
return $1 + $2.replace(/<(?:br|br\s[^>]*)>/ig, '\n') + $3;
});
//
to
html = html.replace(/<(?:br|br\s[^>]*)\s*\/?>\s*<\/p>/ig, '');
// to
html = html.replace(/(<(?:p|p\s[^>]*)>)\s*(<\/p>)/ig, '$1
$2');
// empty char
html = html.replace(/\u200B/g, '');
// ©
html = html.replace(/\u00A9/g, '©');
// ®
html = html.replace(/\u00AE/g, '®');
// Bugfix:
// https://github.com/kindsoft/kindeditor/issues/147
html = html.replace(/\u2003/g, ' ');
html = html.replace(/\u3000/g, ' ');
// Bugfix:
// https://github.com/kindsoft/kindeditor/issues/116
// https://github.com/kindsoft/kindeditor/issues/145
html = html.replace(/<[^>]+/g, function($0) {
return $0.replace(/\s+/g, ' ');
});
var htmlTagMap = {};
if (htmlTags) {
// 展开htmlTags里的key
_each(htmlTags, function(key, val) {
var arr = key.split(',');
for (var i = 0, len = arr.length; i < len; i++) {
htmlTagMap[arr[i]] = _toMap(val);
}
});
// 删除script和style里的内容
if (!htmlTagMap.script) {
html = html.replace(/(<(?:script|script\s[^>]*)>)([\s\S]*?)(<\/script>)/ig, '');
}
if (!htmlTagMap.style) {
html = html.replace(/(<(?:style|style\s[^>]*)>)([\s\S]*?)(<\/style>)/ig, '');
}
}
var re = /(\s*)<(\/)?([\w\-:]+)((?:\s+|(?:\s+[\w\-:]+)|(?:\s+[\w\-:]+=[^\s"'<>]+)|(?:\s+[\w\-:"]+="[^"]*")|(?:\s+[\w\-:"]+='[^']*'))*)(\/)?>(\s*)/g;
var tagStack = [];
html = html.replace(re, function($0, $1, $2, $3, $4, $5, $6) {
var full = $0,
startNewline = $1 || '',
startSlash = $2 || '',
tagName = $3.toLowerCase(),
attr = $4 || '',
endSlash = $5 ? ' ' + $5 : '',
endNewline = $6 || '';
// 不在名单里的过滤掉
if (htmlTags && !htmlTagMap[tagName]) {
return '';
}
// 无闭合标签的自动添加斜线
if (endSlash === '' && _SINGLE_TAG_MAP[tagName]) {
endSlash = ' /';
}
// inline tag时自动将多个空白转换成一个空格
if (_INLINE_TAG_MAP[tagName]) {
if (startNewline) {
startNewline = ' ';
}
if (endNewline) {
endNewline = ' ';
}
}
// pre,style,script tag的格式化
if (_PRE_TAG_MAP[tagName]) {
if (startSlash) {
endNewline = '\n';
} else {
startNewline = '\n';
}
}
// br tag
if (wellFormatted && tagName == 'br') {
endNewline = '\n';
}
// block tag的格式化
if (_BLOCK_TAG_MAP[tagName] && !_PRE_TAG_MAP[tagName]) {
if (wellFormatted) {
if (startSlash && tagStack.length > 0 && tagStack[tagStack.length - 1] === tagName) {
tagStack.pop();
} else {
tagStack.push(tagName);
}
startNewline = '\n';
endNewline = '\n';
for (var i = 0, len = startSlash ? tagStack.length : tagStack.length - 1; i < len; i++) {
startNewline += indentChar;
if (!startSlash) {
endNewline += indentChar;
}
}
if (endSlash) {
tagStack.pop();
} else if (!startSlash) {
endNewline += indentChar;
}
} else {
startNewline = endNewline = '';
}
}
if (attr !== '') {
var attrMap = _getAttrList(full);
// 将font tag转换成span tag
if (tagName === 'font') {
var fontStyleMap = {}, fontStyle = '';
_each(attrMap, function(key, val) {
if (key === 'color') {
fontStyleMap.color = val;
delete attrMap[key];
}
if (key === 'size') {
fontStyleMap['font-size'] = fontSizeList[parseInt(val, 10) - 1] || '';
delete attrMap[key];
}
if (key === 'face') {
fontStyleMap['font-family'] = val;
delete attrMap[key];
}
if (key === 'style') {
fontStyle = val;
}
});
if (fontStyle && !/;$/.test(fontStyle)) {
fontStyle += ';';
}
_each(fontStyleMap, function(key, val) {
if (val === '') {
return;
}
if (/\s/.test(val)) {
val = "'" + val + "'";
}
fontStyle += key + ':' + val + ';';
});
attrMap.style = fontStyle;
}
// 处理attribute和style
_each(attrMap, function(key, val) {
// 补全单独属性
if (_FILL_ATTR_MAP[key]) {
attrMap[key] = key;
}
// 处理URL
if (_inArray(key, ['src', 'href']) >= 0) {
attrMap[key] = _formatUrl(val, urlType);
}
// 过滤属性
if (htmlTags && key !== 'style' && !htmlTagMap[tagName]['*'] && !htmlTagMap[tagName][key] ||
tagName === 'body' && key === 'contenteditable' ||
/^kindeditor_\d+$/.test(key)) {
delete attrMap[key];
}
if (key === 'style' && val !== '') {
var styleMap = _getCssList(val);
_each(styleMap, function(k, v) {
// 过滤样式
if (htmlTags && !htmlTagMap[tagName].style && !htmlTagMap[tagName]['.' + k]) {
delete styleMap[k];
}
});
var style = '';
_each(styleMap, function(k, v) {
style += k + ':' + v + ';';
});
attrMap.style = style;
}
});
attr = '';
_each(attrMap, function(key, val) {
if (key === 'style' && val === '') {
return;
}
val = val.replace(/"/g, '"');
attr += ' ' + key + '="' + val + '"';
});
}
if (tagName === 'font') {
tagName = 'span';
}
return startNewline + '<' + startSlash + tagName + attr + endSlash + '>' + endNewline;
});
// 将pre里的\n转换成 临时标签 + \n,防止被替换
html = html.replace(/(<(?:pre|pre\s[^>]*)>)([\s\S]*?)(<\/pre>)/ig, function($0, $1, $2, $3) {
return $1 + $2.replace(/\n/g, '\n') + $3;
});
html = html.replace(/\n\s*\n/g, '\n');
// 删除临时标签
html = html.replace(/\n/g, '\n');
return _trim(html);
}
// 清理MS Word专用标签
function _clearMsWord(html, htmlTags) {
html = html.replace(//ig, '')
.replace(//ig, '')
.replace(/