2 * editor_plugin_src.js
\r
4 * Copyright 2009, Moxiecode Systems AB
\r
5 * Released under LGPL License.
\r
7 * License: http://tinymce.moxiecode.com/license
\r
8 * Contributing: http://tinymce.moxiecode.com/contributing
\r
12 var each = tinymce.each, Node = tinymce.html.Node;
\r
14 tinymce.create('tinymce.plugins.FullPagePlugin', {
\r
15 init : function(ed, url) {
\r
20 // Register commands
\r
21 ed.addCommand('mceFullPageProperties', function() {
\r
22 ed.windowManager.open({
\r
23 file : url + '/fullpage.htm',
\r
24 width : 430 + parseInt(ed.getLang('fullpage.delta_width', 0)),
\r
25 height : 495 + parseInt(ed.getLang('fullpage.delta_height', 0)),
\r
29 data : t._htmlToData()
\r
34 ed.addButton('fullpage', {title : 'fullpage.desc', cmd : 'mceFullPageProperties'});
\r
36 ed.onBeforeSetContent.add(t._setContent, t);
\r
37 ed.onGetContent.add(t._getContent, t);
\r
40 getInfo : function() {
\r
42 longname : 'Fullpage',
\r
43 author : 'Moxiecode Systems AB',
\r
44 authorurl : 'http://tinymce.moxiecode.com',
\r
45 infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullpage',
\r
46 version : tinymce.majorVersion + "." + tinymce.minorVersion
\r
50 // Private plugin internal methods
\r
52 _htmlToData : function() {
\r
53 var headerFragment = this._parseHeader(), data = {}, nodes, elm, matches, editor = this.editor;
\r
55 function getAttr(elm, name) {
\r
56 var value = elm.attr(name);
\r
61 // Default some values
\r
62 data.fontface = editor.getParam("fullpage_default_fontface", "");
\r
63 data.fontsize = editor.getParam("fullpage_default_fontsize", "");
\r
66 elm = headerFragment.firstChild;
\r
67 if (elm.type == 7) {
\r
69 matches = /encoding="([^"]+)"/.exec(elm.value);
\r
71 data.docencoding = matches[1];
\r
75 elm = headerFragment.getAll('#doctype')[0];
\r
77 data.doctype = '<!DOCTYPE' + elm.value + ">";
\r
79 // Parse title element
\r
80 elm = headerFragment.getAll('title')[0];
\r
81 if (elm && elm.firstChild) {
\r
82 data.metatitle = elm.firstChild.value;
\r
85 // Parse meta elements
\r
86 each(headerFragment.getAll('meta'), function(meta) {
\r
87 var name = meta.attr('name'), httpEquiv = meta.attr('http-equiv'), matches;
\r
90 data['meta' + name.toLowerCase()] = meta.attr('content');
\r
91 else if (httpEquiv == "Content-Type") {
\r
92 matches = /charset\s*=\s*(.*)\s*/gi.exec(meta.attr('content'));
\r
95 data.docencoding = matches[1];
\r
99 // Parse html attribs
\r
100 elm = headerFragment.getAll('html')[0];
\r
102 data.langcode = getAttr(elm, 'lang') || getAttr(elm, 'xml:lang');
\r
104 // Parse stylesheet
\r
105 elm = headerFragment.getAll('link')[0];
\r
106 if (elm && elm.attr('rel') == 'stylesheet')
\r
107 data.stylesheet = elm.attr('href');
\r
109 // Parse body parts
\r
110 elm = headerFragment.getAll('body')[0];
\r
112 data.langdir = getAttr(elm, 'dir');
\r
113 data.style = getAttr(elm, 'style');
\r
114 data.visited_color = getAttr(elm, 'vlink');
\r
115 data.link_color = getAttr(elm, 'link');
\r
116 data.active_color = getAttr(elm, 'alink');
\r
122 _dataToHtml : function(data) {
\r
123 var headerFragment, headElement, html, elm, value, dom = this.editor.dom;
\r
125 function setAttr(elm, name, value) {
\r
126 elm.attr(name, value ? value : undefined);
\r
129 function addHeadNode(node) {
\r
130 if (headElement.firstChild)
\r
131 headElement.insert(node, headElement.firstChild);
\r
133 headElement.append(node);
\r
136 headerFragment = this._parseHeader();
\r
137 headElement = headerFragment.getAll('head')[0];
\r
138 if (!headElement) {
\r
139 elm = headerFragment.getAll('html')[0];
\r
140 headElement = new Node('head', 1);
\r
142 if (elm.firstChild)
\r
143 elm.insert(headElement, elm.firstChild, true);
\r
145 elm.append(headElement);
\r
148 // Add/update/remove XML-PI
\r
149 elm = headerFragment.firstChild;
\r
151 value = 'version="1.0"';
\r
153 if (data.docencoding)
\r
154 value += ' encoding="' + data.docencoding + '"';
\r
156 if (elm.type != 7) {
\r
157 elm = new Node('xml', 7);
\r
158 headerFragment.insert(elm, headerFragment.firstChild, true);
\r
162 } else if (elm && elm.type == 7)
\r
165 // Add/update/remove doctype
\r
166 elm = headerFragment.getAll('#doctype')[0];
\r
167 if (data.doctype) {
\r
169 elm = new Node('#doctype', 10);
\r
172 headerFragment.insert(elm, headerFragment.firstChild);
\r
177 elm.value = data.doctype.substring(9, data.doctype.length - 1);
\r
181 // Add/update/remove title
\r
182 elm = headerFragment.getAll('title')[0];
\r
183 if (data.metatitle) {
\r
185 elm = new Node('title', 1);
\r
186 elm.append(new Node('#text', 3)).value = data.metatitle;
\r
191 // Add meta encoding
\r
192 if (data.docencoding) {
\r
194 each(headerFragment.getAll('meta'), function(meta) {
\r
195 if (meta.attr('http-equiv') == 'Content-Type')
\r
200 elm = new Node('meta', 1);
\r
201 elm.attr('http-equiv', 'Content-Type');
\r
202 elm.shortEnded = true;
\r
206 elm.attr('content', 'text/html; charset=' + data.docencoding);
\r
209 // Add/update/remove meta
\r
210 each('keywords,description,author,copyright,robots'.split(','), function(name) {
\r
211 var nodes = headerFragment.getAll('meta'), i, meta, value = data['meta' + name];
\r
213 for (i = 0; i < nodes.length; i++) {
\r
216 if (meta.attr('name') == name) {
\r
218 meta.attr('content', value);
\r
227 elm = new Node('meta', 1);
\r
228 elm.attr('name', name);
\r
229 elm.attr('content', value);
\r
230 elm.shortEnded = true;
\r
236 // Add/update/delete link
\r
237 elm = headerFragment.getAll('link')[0];
\r
238 if (elm && elm.attr('rel') == 'stylesheet') {
\r
239 if (data.stylesheet)
\r
240 elm.attr('href', data.stylesheet);
\r
243 } else if (data.stylesheet) {
\r
244 elm = new Node('link', 1);
\r
246 rel : 'stylesheet',
\r
248 href : data.stylesheet
\r
250 elm.shortEnded = true;
\r
255 // Update body attributes
\r
256 elm = headerFragment.getAll('body')[0];
\r
258 setAttr(elm, 'dir', data.langdir);
\r
259 setAttr(elm, 'style', data.style);
\r
260 setAttr(elm, 'vlink', data.visited_color);
\r
261 setAttr(elm, 'link', data.link_color);
\r
262 setAttr(elm, 'alink', data.active_color);
\r
264 // Update iframe body as well
\r
265 dom.setAttribs(this.editor.getBody(), {
\r
266 style : data.style,
\r
268 vLink : data.visited_color,
\r
269 link : data.link_color,
\r
270 aLink : data.active_color
\r
274 // Set html attributes
\r
275 elm = headerFragment.getAll('html')[0];
\r
277 setAttr(elm, 'lang', data.langcode);
\r
278 setAttr(elm, 'xml:lang', data.langcode);
\r
281 // Serialize header fragment and crop away body part
\r
282 html = new tinymce.html.Serializer({
\r
285 apply_source_formatting : true,
\r
286 indent_before: 'head,html,body,meta,title,script,link,style',
\r
287 indent_after: 'head,html,body,meta,title,script,link,style'
\r
288 }).serialize(headerFragment);
\r
290 this.head = html.substring(0, html.indexOf('</body>'));
\r
293 _parseHeader : function() {
\r
294 // Parse the contents with a DOM parser
\r
295 return new tinymce.html.DomParser({
\r
297 root_name: '#document'
\r
298 }).parse(this.head);
\r
301 _setContent : function(ed, o) {
\r
302 var self = this, startPos, endPos, content = o.content, headerFragment, styles = '', dom = self.editor.dom, elm;
\r
305 return s.replace(/<\/?[A-Z]+/g, function(a) {
\r
306 return a.toLowerCase();
\r
310 // Ignore raw updated if we already have a head, this will fix issues with undo/redo keeping the head/foot separate
\r
311 if (o.format == 'raw' && self.head)
\r
314 if (o.source_view && ed.getParam('fullpage_hide_in_source_view'))
\r
317 // Parse out head, body and footer
\r
318 content = content.replace(/<(\/?)BODY/gi, '<$1body');
\r
319 startPos = content.indexOf('<body');
\r
321 if (startPos != -1) {
\r
322 startPos = content.indexOf('>', startPos);
\r
323 self.head = low(content.substring(0, startPos + 1));
\r
325 endPos = content.indexOf('</body', startPos);
\r
327 endPos = content.length;
\r
329 o.content = content.substring(startPos + 1, endPos);
\r
330 self.foot = low(content.substring(endPos));
\r
332 self.head = this._getDefaultHeader();
\r
333 self.foot = '\n</body>\n</html>';
\r
336 // Parse header and update iframe
\r
337 headerFragment = self._parseHeader();
\r
338 each(headerFragment.getAll('style'), function(node) {
\r
339 if (node.firstChild)
\r
340 styles += node.firstChild.value;
\r
343 elm = headerFragment.getAll('body')[0];
\r
345 dom.setAttribs(self.editor.getBody(), {
\r
346 style : elm.attr('style') || '',
\r
347 dir : elm.attr('dir') || '',
\r
348 vLink : elm.attr('vlink') || '',
\r
349 link : elm.attr('link') || '',
\r
350 aLink : elm.attr('alink') || ''
\r
354 dom.remove('fullpage_styles');
\r
357 dom.add(self.editor.getDoc().getElementsByTagName('head')[0], 'style', {id : 'fullpage_styles'}, styles);
\r
359 // Needed for IE 6/7
\r
360 elm = dom.get('fullpage_styles');
\r
361 if (elm.styleSheet)
\r
362 elm.styleSheet.cssText = styles;
\r
366 _getDefaultHeader : function() {
\r
367 var header = '', editor = this.editor, value, styles = '';
\r
369 if (editor.getParam('fullpage_default_xml_pi'))
\r
370 header += '<?xml version="1.0" encoding="' + editor.getParam('fullpage_default_encoding', 'ISO-8859-1') + '" ?>\n';
\r
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">');
\r
373 header += '\n<html>\n<head>\n';
\r
375 if (value = editor.getParam('fullpage_default_title'))
\r
376 header += '<title>' + value + '</title>\n';
\r
378 if (value = editor.getParam('fullpage_default_encoding'))
\r
379 header += '<meta http-equiv="Content-Type" content="text/html; charset=' + value + '" />\n';
\r
381 if (value = editor.getParam('fullpage_default_font_family'))
\r
382 styles += 'font-family: ' + value + ';';
\r
384 if (value = editor.getParam('fullpage_default_font_size'))
\r
385 styles += 'font-size: ' + value + ';';
\r
387 if (value = editor.getParam('fullpage_default_text_color'))
\r
388 styles += 'color: ' + value + ';';
\r
390 header += '</head>\n<body' + (styles ? ' style="' + styles + '"' : '') + '>\n';
\r
395 _getContent : function(ed, o) {
\r
398 if (!o.source_view || !ed.getParam('fullpage_hide_in_source_view'))
\r
399 o.content = tinymce.trim(self.head) + '\n' + tinymce.trim(o.content) + '\n' + tinymce.trim(self.foot);
\r
404 tinymce.PluginManager.add('fullpage', tinymce.plugins.FullPagePlugin);
\r