]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/javascript/tiny_mce/plugins/fullpage/editor_plugin_src.js
Release 6.5.0
[Github/sugarcrm.git] / include / javascript / tiny_mce / plugins / fullpage / editor_plugin_src.js
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                         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>' + value + '</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;
387                 },
388
389                 _getContent : function(ed, o) {
390                         var self = this;
391
392                         if (!o.source_view || !ed.getParam('fullpage_hide_in_source_view'))
393                                 o.content = tinymce.trim(self.head) + '\n' + tinymce.trim(o.content) + '\n' + tinymce.trim(self.foot);
394                 }
395         });
396
397         // Register plugin
398         tinymce.PluginManager.add('fullpage', tinymce.plugins.FullPagePlugin);
399 })();