comparison WebContent/jscripts/tiny_mce/plugins/fullpage/editor_plugin_src.js @ 5:0be9d53a6967

editor for annotations
author dwinter
date Tue, 13 Dec 2011 17:43:46 +0100
parents
children
comparison
equal deleted inserted replaced
4:c32080f364c6 5:0be9d53a6967
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 })();