comparison static/js/tiny_mce/plugins/fullpage/editor_plugin_src.js @ 442:6c182ceb7147

Fixing #217; upgrade TinyMCE to 3.4.2 and enable the paste plugin.
author Brian Neal <bgneal@gmail.com>
date Thu, 26 May 2011 00:43:49 +0000
parents 88b2b9cb8c1f
children
comparison
equal deleted inserted replaced
441:33d0c55e57a9 442:6c182ceb7147
7 * License: http://tinymce.moxiecode.com/license 7 * License: http://tinymce.moxiecode.com/license
8 * Contributing: http://tinymce.moxiecode.com/contributing 8 * Contributing: http://tinymce.moxiecode.com/contributing
9 */ 9 */
10 10
11 (function() { 11 (function() {
12 var each = tinymce.each, Node = tinymce.html.Node;
13
12 tinymce.create('tinymce.plugins.FullPagePlugin', { 14 tinymce.create('tinymce.plugins.FullPagePlugin', {
13 init : function(ed, url) { 15 init : function(ed, url) {
14 var t = this; 16 var t = this;
15 17
16 t.editor = ed; 18 t.editor = ed;
22 width : 430 + parseInt(ed.getLang('fullpage.delta_width', 0)), 24 width : 430 + parseInt(ed.getLang('fullpage.delta_width', 0)),
23 height : 495 + parseInt(ed.getLang('fullpage.delta_height', 0)), 25 height : 495 + parseInt(ed.getLang('fullpage.delta_height', 0)),
24 inline : 1 26 inline : 1
25 }, { 27 }, {
26 plugin_url : url, 28 plugin_url : url,
27 head_html : t.head 29 data : t._htmlToData()
28 }); 30 });
29 }); 31 });
30 32
31 // Register buttons 33 // Register buttons
32 ed.addButton('fullpage', {title : 'fullpage.desc', cmd : 'mceFullPageProperties'}); 34 ed.addButton('fullpage', {title : 'fullpage.desc', cmd : 'mceFullPageProperties'});
33 35
34 ed.onBeforeSetContent.add(t._setContent, t); 36 ed.onBeforeSetContent.add(t._setContent, t);
35 ed.onSetContent.add(t._setBodyAttribs, t);
36 ed.onGetContent.add(t._getContent, t); 37 ed.onGetContent.add(t._getContent, t);
37 }, 38 },
38 39
39 getInfo : function() { 40 getInfo : function() {
40 return { 41 return {
46 }; 47 };
47 }, 48 },
48 49
49 // Private plugin internal methods 50 // Private plugin internal methods
50 51
51 _setBodyAttribs : function(ed, o) { 52 _htmlToData : function() {
52 var bdattr, i, len, kv, k, v, t, attr = this.head.match(/body(.*?)>/i); 53 var headerFragment = this._parseHeader(), data = {}, nodes, elm, matches, editor = this.editor;
53 54
54 if (attr && attr[1]) { 55 function getAttr(elm, name) {
55 bdattr = attr[1].match(/\s*(\w+\s*=\s*".*?"|\w+\s*=\s*'.*?'|\w+\s*=\s*\w+|\w+)\s*/g); 56 var value = elm.attr(name);
56 57
57 if (bdattr) { 58 return value || '';
58 for(i = 0, len = bdattr.length; i < len; i++) { 59 };
59 kv = bdattr[i].split('='); 60
60 k = kv[0].replace(/\s/,''); 61 // Default some values
61 v = kv[1]; 62 data.fontface = editor.getParam("fullpage_default_fontface", "");
62 63 data.fontsize = editor.getParam("fullpage_default_fontsize", "");
63 if (v) { 64
64 v = v.replace(/^\s+/,'').replace(/\s+$/,''); 65 // Parse XML PI
65 t = v.match(/^["'](.*)["']$/); 66 elm = headerFragment.firstChild;
66 67 if (elm.type == 7) {
67 if (t) 68 data.xml_pi = true;
68 v = t[1]; 69 matches = /encoding="([^"]+)"/.exec(elm.value);
69 } else 70 if (matches)
70 v = k; 71 data.docencoding = matches[1];
71 72 }
72 ed.dom.setAttrib(ed.getBody(), 'style', v); 73
74 // Parse doctype
75 elm = headerFragment.getAll('#doctype')[0];
76 if (elm)
77 data.doctype = '<!DOCTYPE' + elm.value + ">";
78
79 // Parse title element
80 elm = headerFragment.getAll('title')[0];
81 if (elm && elm.firstChild) {
82 data.metatitle = elm.firstChild.value;
83 }
84
85 // Parse meta elements
86 each(headerFragment.getAll('meta'), function(meta) {
87 var name = meta.attr('name'), httpEquiv = meta.attr('http-equiv'), matches;
88
89 if (name)
90 data['meta' + name.toLowerCase()] = meta.attr('content');
91 else if (httpEquiv == "Content-Type") {
92 matches = /charset\s*=\s*(.*)\s*/gi.exec(meta.attr('content'));
93
94 if (matches)
95 data.docencoding = matches[1];
96 }
97 });
98
99 // Parse html attribs
100 elm = headerFragment.getAll('html')[0];
101 if (elm)
102 data.langcode = getAttr(elm, 'lang') || getAttr(elm, 'xml:lang');
103
104 // Parse stylesheet
105 elm = headerFragment.getAll('link')[0];
106 if (elm && elm.attr('rel') == 'stylesheet')
107 data.stylesheet = elm.attr('href');
108
109 // Parse body parts
110 elm = headerFragment.getAll('body')[0];
111 if (elm) {
112 data.langdir = getAttr(elm, 'dir');
113 data.style = getAttr(elm, 'style');
114 data.visited_color = getAttr(elm, 'vlink');
115 data.link_color = getAttr(elm, 'link');
116 data.active_color = getAttr(elm, 'alink');
117 }
118
119 return data;
120 },
121
122 _dataToHtml : function(data) {
123 var headerFragment, headElement, html, elm, value, dom = this.editor.dom;
124
125 function setAttr(elm, name, value) {
126 elm.attr(name, value ? value : undefined);
127 };
128
129 function addHeadNode(node) {
130 if (headElement.firstChild)
131 headElement.insert(node, headElement.firstChild);
132 else
133 headElement.append(node);
134 };
135
136 headerFragment = this._parseHeader();
137 headElement = headerFragment.getAll('head')[0];
138 if (!headElement) {
139 elm = headerFragment.getAll('html')[0];
140 headElement = new Node('head', 1);
141
142 if (elm.firstChild)
143 elm.insert(headElement, elm.firstChild, true);
144 else
145 elm.append(headElement);
146 }
147
148 // Add/update/remove XML-PI
149 elm = headerFragment.firstChild;
150 if (data.xml_pi) {
151 value = 'version="1.0"';
152
153 if (data.docencoding)
154 value += ' encoding="' + data.docencoding + '"';
155
156 if (elm.type != 7) {
157 elm = new Node('xml', 7);
158 headerFragment.insert(elm, headerFragment.firstChild, true);
159 }
160
161 elm.value = value;
162 } else if (elm && elm.type == 7)
163 elm.remove();
164
165 // Add/update/remove doctype
166 elm = headerFragment.getAll('#doctype')[0];
167 if (data.doctype) {
168 if (!elm) {
169 elm = new Node('#doctype', 10);
170
171 if (data.xml_pi)
172 headerFragment.insert(elm, headerFragment.firstChild);
173 else
174 addHeadNode(elm);
175 }
176
177 elm.value = data.doctype.substring(9, data.doctype.length - 1);
178 } else if (elm)
179 elm.remove();
180
181 // Add/update/remove title
182 elm = headerFragment.getAll('title')[0];
183 if (data.metatitle) {
184 if (!elm) {
185 elm = new Node('title', 1);
186 elm.append(new Node('#text', 3)).value = data.metatitle;
187 addHeadNode(elm);
188 }
189 }
190
191 // Add meta encoding
192 if (data.docencoding) {
193 elm = null;
194 each(headerFragment.getAll('meta'), function(meta) {
195 if (meta.attr('http-equiv') == 'Content-Type')
196 elm = meta;
197 });
198
199 if (!elm) {
200 elm = new Node('meta', 1);
201 elm.attr('http-equiv', 'Content-Type');
202 elm.shortEnded = true;
203 addHeadNode(elm);
204 }
205
206 elm.attr('content', 'text/html; charset=' + data.docencoding);
207 }
208
209 // Add/update/remove meta
210 each('keywords,description,author,copyright,robots'.split(','), function(name) {
211 var nodes = headerFragment.getAll('meta'), i, meta, value = data['meta' + name];
212
213 for (i = 0; i < nodes.length; i++) {
214 meta = nodes[i];
215
216 if (meta.attr('name') == name) {
217 if (value)
218 meta.attr('content', value);
219 else
220 meta.remove();
221
222 return;
73 } 223 }
74 } 224 }
75 } 225
76 }, 226 if (value) {
77 227 elm = new Node('meta', 1);
78 _createSerializer : function() { 228 elm.attr('name', name);
79 return new tinymce.dom.Serializer({ 229 elm.attr('content', value);
80 dom : this.editor.dom, 230 elm.shortEnded = true;
81 apply_source_formatting : true 231
232 addHeadNode(elm);
233 }
82 }); 234 });
235
236 // Add/update/delete link
237 elm = headerFragment.getAll('link')[0];
238 if (elm && elm.attr('rel') == 'stylesheet') {
239 if (data.stylesheet)
240 elm.attr('href', data.stylesheet);
241 else
242 elm.remove();
243 } else if (data.stylesheet) {
244 elm = new Node('link', 1);
245 elm.attr({
246 rel : 'stylesheet',
247 text : 'text/css',
248 href : data.stylesheet
249 });
250 elm.shortEnded = true;
251
252 addHeadNode(elm);
253 }
254
255 // Update body attributes
256 elm = headerFragment.getAll('body')[0];
257 if (elm) {
258 setAttr(elm, 'dir', data.langdir);
259 setAttr(elm, 'style', data.style);
260 setAttr(elm, 'vlink', data.visited_color);
261 setAttr(elm, 'link', data.link_color);
262 setAttr(elm, 'alink', data.active_color);
263
264 // Update iframe body as well
265 dom.setAttribs(this.editor.getBody(), {
266 style : data.style,
267 dir : data.dir,
268 vLink : data.visited_color,
269 link : data.link_color,
270 aLink : data.active_color
271 });
272 }
273
274 // Set html attributes
275 elm = headerFragment.getAll('html')[0];
276 if (elm) {
277 setAttr(elm, 'lang', data.langcode);
278 setAttr(elm, 'xml:lang', data.langcode);
279 }
280
281 // Serialize header fragment and crop away body part
282 html = new tinymce.html.Serializer({
283 validate: false,
284 indent: true,
285 apply_source_formatting : true,
286 indent_before: 'head,html,body,meta,title,script,link,style',
287 indent_after: 'head,html,body,meta,title,script,link,style'
288 }).serialize(headerFragment);
289
290 this.head = html.substring(0, html.indexOf('</body>'));
291 },
292
293 _parseHeader : function() {
294 // Parse the contents with a DOM parser
295 return new tinymce.html.DomParser({
296 validate: false,
297 root_name: '#document'
298 }).parse(this.head);
83 }, 299 },
84 300
85 _setContent : function(ed, o) { 301 _setContent : function(ed, o) {
86 var t = this, sp, ep, c = o.content, v, st = ''; 302 var self = this, startPos, endPos, content = o.content, headerFragment, styles = '', dom = self.editor.dom, elm;
303
304 function low(s) {
305 return s.replace(/<\/?[A-Z]+/g, function(a) {
306 return a.toLowerCase();
307 })
308 };
87 309
88 // Ignore raw updated if we already have a head, this will fix issues with undo/redo keeping the head/foot separate 310 // Ignore raw updated if we already have a head, this will fix issues with undo/redo keeping the head/foot separate
89 if (o.format == 'raw' && t.head) 311 if (o.format == 'raw' && self.head)
90 return; 312 return;
91 313
92 if (o.source_view && ed.getParam('fullpage_hide_in_source_view')) 314 if (o.source_view && ed.getParam('fullpage_hide_in_source_view'))
93 return; 315 return;
94 316
95 // Parse out head, body and footer 317 // Parse out head, body and footer
96 c = c.replace(/<(\/?)BODY/gi, '<$1body'); 318 content = content.replace(/<(\/?)BODY/gi, '<$1body');
97 sp = c.indexOf('<body'); 319 startPos = content.indexOf('<body');
98 320
99 if (sp != -1) { 321 if (startPos != -1) {
100 sp = c.indexOf('>', sp); 322 startPos = content.indexOf('>', startPos);
101 t.head = c.substring(0, sp + 1); 323 self.head = low(content.substring(0, startPos + 1));
102 324
103 ep = c.indexOf('</body', sp); 325 endPos = content.indexOf('</body', startPos);
104 if (ep == -1) 326 if (endPos == -1)
105 ep = c.indexOf('</body', ep); 327 endPos = content.length;
106 328
107 o.content = c.substring(sp + 1, ep); 329 o.content = content.substring(startPos + 1, endPos);
108 t.foot = c.substring(ep); 330 self.foot = low(content.substring(endPos));
109
110 function low(s) {
111 return s.replace(/<\/?[A-Z]+/g, function(a) {
112 return a.toLowerCase();
113 })
114 };
115
116 t.head = low(t.head);
117 t.foot = low(t.foot);
118 } else { 331 } else {
119 t.head = ''; 332 self.head = this._getDefaultHeader();
120 if (ed.getParam('fullpage_default_xml_pi')) 333 self.foot = '\n</body>\n</html>';
121 t.head += '<?xml version="1.0" encoding="' + ed.getParam('fullpage_default_encoding', 'ISO-8859-1') + '" ?>\n'; 334 }
122 335
123 t.head += ed.getParam('fullpage_default_doctype', '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'); 336 // Parse header and update iframe
124 t.head += '\n<html>\n<head>\n<title>' + ed.getParam('fullpage_default_title', 'Untitled document') + '</title>\n'; 337 headerFragment = self._parseHeader();
125 338 each(headerFragment.getAll('style'), function(node) {
126 if (v = ed.getParam('fullpage_default_encoding')) 339 if (node.firstChild)
127 t.head += '<meta http-equiv="Content-Type" content="' + v + '" />\n'; 340 styles += node.firstChild.value;
128 341 });
129 if (v = ed.getParam('fullpage_default_font_family')) 342
130 st += 'font-family: ' + v + ';'; 343 elm = headerFragment.getAll('body')[0];
131 344 if (elm) {
132 if (v = ed.getParam('fullpage_default_font_size')) 345 dom.setAttribs(self.editor.getBody(), {
133 st += 'font-size: ' + v + ';'; 346 style : elm.attr('style') || '',
134 347 dir : elm.attr('dir') || '',
135 if (v = ed.getParam('fullpage_default_text_color')) 348 vLink : elm.attr('vlink') || '',
136 st += 'color: ' + v + ';'; 349 link : elm.attr('link') || '',
137 350 aLink : elm.attr('alink') || ''
138 t.head += '</head>\n<body' + (st ? ' style="' + st + '"' : '') + '>\n'; 351 });
139 t.foot = '\n</body>\n</html>'; 352 }
140 } 353
354 if (styles)
355 dom.add(self.editor.getDoc().getElementsByTagName('head')[0], 'style', {id : 'fullpage_styles'}, styles);
356 else
357 dom.remove('fullpage_styles');
358 },
359
360 _getDefaultHeader : function() {
361 var header = '', editor = this.editor, value, styles = '';
362
363 if (editor.getParam('fullpage_default_xml_pi'))
364 header += '<?xml version="1.0" encoding="' + editor.getParam('fullpage_default_encoding', 'ISO-8859-1') + '" ?>\n';
365
366 header += editor.getParam('fullpage_default_doctype', '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">');
367 header += '\n<html>\n<head>\n';
368
369 if (value = editor.getParam('fullpage_default_title'))
370 header += '<title>' + v + '</title>\n';
371
372 if (value = editor.getParam('fullpage_default_encoding'))
373 header += '<meta http-equiv="Content-Type" content="text/html; charset=' + value + '" />\n';
374
375 if (value = editor.getParam('fullpage_default_font_family'))
376 styles += 'font-family: ' + value + ';';
377
378 if (value = editor.getParam('fullpage_default_font_size'))
379 styles += 'font-size: ' + value + ';';
380
381 if (value = editor.getParam('fullpage_default_text_color'))
382 styles += 'color: ' + value + ';';
383
384 header += '</head>\n<body' + (styles ? ' style="' + styles + '"' : '') + '>\n';
385
386 return header;
141 }, 387 },
142 388
143 _getContent : function(ed, o) { 389 _getContent : function(ed, o) {
144 var t = this; 390 var self = this;
145 391
146 if (!o.source_view || !ed.getParam('fullpage_hide_in_source_view')) 392 if (!o.source_view || !ed.getParam('fullpage_hide_in_source_view'))
147 o.content = tinymce.trim(t.head) + '\n' + tinymce.trim(o.content) + '\n' + tinymce.trim(t.foot); 393 o.content = tinymce.trim(self.head) + '\n' + tinymce.trim(o.content) + '\n' + tinymce.trim(self.foot);
148 } 394 }
149 }); 395 });
150 396
151 // Register plugin 397 // Register plugin
152 tinymce.PluginManager.add('fullpage', tinymce.plugins.FullPagePlugin); 398 tinymce.PluginManager.add('fullpage', tinymce.plugins.FullPagePlugin);