-
Notifications
You must be signed in to change notification settings - Fork 2
/
plugin.js
175 lines (162 loc) · 5.72 KB
/
plugin.js
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/**
* plugin.js
*
* Released under LGPL License.
* Copyright (c) 2015 SIRAP SAS All rights reserved
*
* License: http://www.tinymce.com/license
* Contributing: http://www.tinymce.com/contributing
*/
var tinymce = window.tinymce
var jQuery = window.jQuery
;(function (tinymce) {
tinymce.PluginManager.add('inlinestyles', function (editor) {
/**
* @param stylesArray - the array of string
* "{name}:{value};" pairs that are to be broken down
*
*/
function createCSSRuleObject (stylesArray) {
var cssObj = {}
for (var _s in stylesArray) {
var S = stylesArray[_s].split(':')
if (S[0].trim() === '' || S[1].trim() === '') continue
cssObj[S[0].trim()] = S[1].trim()
}
return cssObj
}
/**
* @param $out - the tmp html content
*
*/
function interpritAppendedStylesheet ($out) {
if ($out[0] && $out[0].styleSheets && $out[0].styleSheets.length) {
var stylesheet = $out[0].styleSheets[0] // first stylesheet
if (stylesheet.cssRules) {
for (var r in stylesheet.cssRules) {
try {
var rule = stylesheet.cssRules[r]
if (!isNaN(rule)) break // make sure the rule exists
var $destObj = $out.find(rule.selectorText)
var obj = rule.cssText.replace(rule.selectorText, '')
obj = obj.replace('{', '').replace('}', '') // clean up the { and }'s
var styles = obj.split(';') // separate each
$destObj.css(createCSSRuleObject(styles)) // do the inline styling
} catch (e) {
console.error(e)
}
}
}
}
}
function isPatternRelevant (newHTML, pattern, relevantPatterns) {
if (newHTML.indexOf(pattern) > -1) relevantPatterns.push(new RegExp(pattern, 'i'))
}
/**
* The main method - inflinify
* this utilizes two text areas and a div for final output -
* (1) css input textarea for the css to apply
* (2) html content for the css to apply TO
*/
function inlinify (input) {
var tmpWindow = window.open('', 'tmpHtml', 'width=0,height=0')
window.blur() // re focus on main window
var tmpDoc = tmpWindow.document // create a window that we can use
var $tmpDoc = jQuery(tmpDoc) // jquerify the temp window
tmpDoc.write(input) // write the HTML out to a new window doc
interpritAppendedStylesheet($tmpDoc) // apply styles to the document just created
$tmpDoc.find('style').remove() // sanitize all style tags present prior to the transformation
var newHTML = $tmpDoc.find('html').html()
tmpWindow.close()
var relevantPatterns = []
isPatternRelevant(newHTML, 'href="', relevantPatterns)
isPatternRelevant(newHTML, 'src="', relevantPatterns)
return sanitize(newHTML, relevantPatterns)
}
function sanitize (html, patterns) {
var ret = html
for (var i = 0; i < patterns.length; i++) {
ret = san(ret, patterns[i])
}
return ret
}
/**
* This method will take HTML and a PATTERN and essentially
* sanitize the following chars within the HTML with that
* pattern through a filter:
* Currently this only applies to &' -> &
*/
function san (html, pattern) {
function sanitize () {
// get the start of what we will sanitize
var startIndex = remainingString.indexOf('"')
// and the end
var endIndex = remainingString.indexOf('"', startIndex + 1)
// get the data to sanitize
var newHREF = html.substring(i + startIndex + 1, i + endIndex + 1)
// here we actually perform the replacement
newHREF = newHREF.replace(/&/g, '&')
// add the pattern + the new data + a closing quote
var regExpStartLen = '/'.length
var regExpFlagsLen = '/i'.length
ret += String(pattern).substring(regExpStartLen, String(pattern).length - regExpFlagsLen) + newHREF
i += endIndex
}
var ret = ''
var remainingString
var hrefIndex
for (var i = 0; i < html.length; i++) {
remainingString = html.substring(i)
hrefIndex = remainingString.search(pattern)
if (hrefIndex === 0) {
// actually sanitize the pattern, i.e. href="[sanitize-candidate]"
// must be encapsulated within quotes, "
sanitize()
continue
} else {
// if we have another href, copy everything until that href index
if (hrefIndex > 0) {
ret += html.substring(i, hrefIndex)
i = hrefIndex - 1
} else {
// otherwise just add the remaining chars and stop trying to sanitize
ret += html.substring(i)
break
}
}
}
return ret
}
function inlinifyOnEvent (evt) {
var modified
try {
modified = inlinify(evt.content)
} catch (e) {
console.error('Inlining css stylesheets failed')
console.error(e)
console.error(e.stack)
}
if (modified) {
evt.content = '<!DOCTYPE html><html>' + modified + '</html>'
}
}
var source_view = false
// var fullcontent //, head, body, foot
var contentAllreadyLoaded = false
editor.on('GetContent', function (evt) {
source_view = evt.source_view || false
})
editor.on('BeforeSetContent', function (evt) {
if (!evt.ignoreInlinify) {
if (source_view) {
// fullcontent = evt.content
source_view = false
inlinifyOnEvent(evt)
} else if (!contentAllreadyLoaded && evt.content && evt.content.length) {
inlinifyOnEvent(evt)
contentAllreadyLoaded = true
}
}
})
})
})(tinymce)