Subversion-Projekte lars-tiefland.content-management

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
/**
2
 * editor_plugin_src.js
3
 *
4
 * Copyright 2009, Moxiecode Systems AB
5
 * Released under LGPL License.
6
 *
7
 * License: http://tinymce.moxiecode.com/license
8
 * Contributing: http://tinymce.moxiecode.com/contributing
9
 */
10
 
11
(function() {
12
	var each = tinymce.each, Node = tinymce.html.Node;
13
 
14
	tinymce.create('tinymce.plugins.FullPagePlugin', {
15
		init : function(ed, url) {
16
			var t = this;
17
 
18
			t.editor = ed;
19
 
20
			// Register commands
21
			ed.addCommand('mceFullPageProperties', function() {
22
				ed.windowManager.open({
23
					file : url + '/fullpage.htm',
24
					width : 430 + parseInt(ed.getLang('fullpage.delta_width', 0)),
25
					height : 495 + parseInt(ed.getLang('fullpage.delta_height', 0)),
26
					inline : 1
27
				}, {
28
					plugin_url : url,
29
					data : t._htmlToData()
30
				});
31
			});
32
 
33
			// Register buttons
34
			ed.addButton('fullpage', {title : 'fullpage.desc', cmd : 'mceFullPageProperties'});
35
 
36
			ed.onBeforeSetContent.add(t._setContent, t);
37
			ed.onGetContent.add(t._getContent, t);
38
		},
39
 
40
		getInfo : function() {
41
			return {
42
				longname : 'Fullpage',
43
				author : 'Moxiecode Systems AB',
44
				authorurl : 'http://tinymce.moxiecode.com',
45
				infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullpage',
46
				version : tinymce.majorVersion + "." + tinymce.minorVersion
47
			};
48
		},
49
 
50
		// Private plugin internal methods
51
 
52
		_htmlToData : function() {
53
			var headerFragment = this._parseHeader(), data = {}, nodes, elm, matches, editor = this.editor;
54
 
55
			function getAttr(elm, name) {
56
				var value = elm.attr(name);
57
 
58
				return value || '';
59
			};
60
 
61
			// Default some values
62
			data.fontface = editor.getParam("fullpage_default_fontface", "");
63
			data.fontsize = editor.getParam("fullpage_default_fontsize", "");
64
 
65
			// Parse XML PI
66
			elm = headerFragment.firstChild;
67
			if (elm.type == 7) {
68
				data.xml_pi = true;
69
				matches = /encoding="([^"]+)"/.exec(elm.value);
70
				if (matches)
71
					data.docencoding = matches[1];
72
			}
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;
223
					}
224
				}
225
 
226
				if (value) {
227
					elm = new Node('meta', 1);
228
					elm.attr('name', name);
229
					elm.attr('content', value);
230
					elm.shortEnded = true;
231
 
232
					addHeadNode(elm);
233
				}
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);
299
		},
300
 
301
		_setContent : function(ed, o) {
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
			};
309
 
310
			// Ignore raw updated if we already have a head, this will fix issues with undo/redo keeping the head/foot separate
311
			if (o.format == 'raw' && self.head)
312
				return;
313
 
314
			if (o.source_view && ed.getParam('fullpage_hide_in_source_view'))
315
				return;
316
 
317
			// Parse out head, body and footer
318
			content = content.replace(/<(\/?)BODY/gi, '<$1body');
319
			startPos = content.indexOf('<body');
320
 
321
			if (startPos != -1) {
322
				startPos = content.indexOf('>', startPos);
323
				self.head = low(content.substring(0, startPos + 1));
324
 
325
				endPos = content.indexOf('</body', startPos);
326
				if (endPos == -1)
327
					endPos = content.length;
328
 
329
				o.content = content.substring(startPos + 1, endPos);
330
				self.foot = low(content.substring(endPos));
331
			} else {
332
				self.head = this._getDefaultHeader();
333
				self.foot = '\n</body>\n</html>';
334
			}
335
 
336
			// Parse header and update iframe
337
			headerFragment = self._parseHeader();
338
			each(headerFragment.getAll('style'), function(node) {
339
				if (node.firstChild)
340
					styles += node.firstChild.value;
341
			});
342
 
343
			elm = headerFragment.getAll('body')[0];
344
			if (elm) {
345
				dom.setAttribs(self.editor.getBody(), {
346
					style : elm.attr('style') || '',
347
					dir : elm.attr('dir') || '',
348
					vLink : elm.attr('vlink') || '',
349
					link : elm.attr('link') || '',
350
					aLink : elm.attr('alink') || ''
351
				});
352
			}
353
 
354
			dom.remove('fullpage_styles');
355
 
356
			if (styles) {
357
				dom.add(self.editor.getDoc().getElementsByTagName('head')[0], 'style', {id : 'fullpage_styles'}, styles);
358
 
359
				// Needed for IE 6/7
360
				elm = dom.get('fullpage_styles');
361
				if (elm.styleSheet)
362
					elm.styleSheet.cssText = styles;
363
			}
364
		},
365
 
366
		_getDefaultHeader : function() {
367
			var header = '', editor = this.editor, value, styles = '';
368
 
369
			if (editor.getParam('fullpage_default_xml_pi'))
370
				header += '<?xml version="1.0" encoding="' + editor.getParam('fullpage_default_encoding', 'ISO-8859-1') + '" ?>\n';
371
 
372
			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">');
373
			header += '\n<html>\n<head>\n';
374
 
375
			if (value = editor.getParam('fullpage_default_title'))
376
				header += '<title>' + value + '</title>\n';
377
 
378
			if (value = editor.getParam('fullpage_default_encoding'))
379
				header += '<meta http-equiv="Content-Type" content="text/html; charset=' + value + '" />\n';
380
 
381
			if (value = editor.getParam('fullpage_default_font_family'))
382
				styles += 'font-family: ' + value + ';';
383
 
384
			if (value = editor.getParam('fullpage_default_font_size'))
385
				styles += 'font-size: ' + value + ';';
386
 
387
			if (value = editor.getParam('fullpage_default_text_color'))
388
				styles += 'color: ' + value + ';';
389
 
390
			header += '</head>\n<body' + (styles ? ' style="' + styles + '"' : '') + '>\n';
391
 
392
			return header;
393
		},
394
 
395
		_getContent : function(ed, o) {
396
			var self = this;
397
 
398
			if (!o.source_view || !ed.getParam('fullpage_hide_in_source_view'))
399
				o.content = tinymce.trim(self.head) + '\n' + tinymce.trim(o.content) + '\n' + tinymce.trim(self.foot);
400
		}
401
	});
402
 
403
	// Register plugin
404
	tinymce.PluginManager.add('fullpage', tinymce.plugins.FullPagePlugin);
405
})();