Utils.js
3.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/**
* Utils.js
*
* Released under LGPL License.
* Copyright (c) 1999-2015 Ephox Corp. All rights reserved
*
* License: http://www.tinymce.com/license
* Contributing: http://www.tinymce.com/contributing
*/
/**
* This class contails various utility functions for the paste plugin.
*
* @class tinymce.pasteplugin.Utils
*/
define("tinymce/pasteplugin/Utils", [
"tinymce/util/Tools",
"tinymce/html/DomParser",
"tinymce/html/Schema"
], function(Tools, DomParser, Schema) {
function filter(content, items) {
Tools.each(items, function(v) {
if (v.constructor == RegExp) {
content = content.replace(v, '');
} else {
content = content.replace(v[0], v[1]);
}
});
return content;
}
/**
* Gets the innerText of the specified element. It will handle edge cases
* and works better than textContent on Gecko.
*
* @param {String} html HTML string to get text from.
* @return {String} String of text with line feeds.
*/
function innerText(html) {
var schema = new Schema(), domParser = new DomParser({}, schema), text = '';
var shortEndedElements = schema.getShortEndedElements();
var ignoreElements = Tools.makeMap('script noscript style textarea video audio iframe object', ' ');
var blockElements = schema.getBlockElements();
function walk(node) {
var name = node.name, currentNode = node;
if (name === 'br') {
text += '\n';
return;
}
// img/input/hr
if (shortEndedElements[name]) {
text += ' ';
}
// Ingore script, video contents
if (ignoreElements[name]) {
text += ' ';
return;
}
if (node.type == 3) {
text += node.value;
}
// Walk all children
if (!node.shortEnded) {
if ((node = node.firstChild)) {
do {
walk(node);
} while ((node = node.next));
}
}
// Add \n or \n\n for blocks or P
if (blockElements[name] && currentNode.next) {
text += '\n';
if (name == 'p') {
text += '\n';
}
}
}
html = filter(html, [
/<!\[[^\]]+\]>/g // Conditional comments
]);
walk(domParser.parse(html));
return text;
}
/**
* Trims the specified HTML by removing all WebKit fragments, all elements wrapping the body trailing BR elements etc.
*
* @param {String} html Html string to trim contents on.
* @return {String} Html contents that got trimmed.
*/
function trimHtml(html) {
function trimSpaces(all, s1, s2) {
// WebKit meant to preserve multiple spaces but instead inserted around all inline tags,
// including the spans with inline styles created on paste
if (!s1 && !s2) {
return ' ';
}
return '\u00a0';
}
html = filter(html, [
/^[\s\S]*<body[^>]*>\s*|\s*<\/body[^>]*>[\s\S]*$/g, // Remove anything but the contents within the BODY element
/<!--StartFragment-->|<!--EndFragment-->/g, // Inner fragments (tables from excel on mac)
[/( ?)<span class="Apple-converted-space">\u00a0<\/span>( ?)/g, trimSpaces],
/<br class="Apple-interchange-newline">/g,
/<br>$/i // Trailing BR elements
]);
return html;
}
// TODO: Should be in some global class
function createIdGenerator(prefix) {
var count = 0;
return function() {
return prefix + (count++);
};
}
return {
filter: filter,
innerText: innerText,
trimHtml: trimHtml,
createIdGenerator: createIdGenerator
};
});