bgneal@312: /** bgneal@312: * editor_plugin_src.js bgneal@312: * bgneal@312: * Copyright 2009, Moxiecode Systems AB bgneal@312: * Released under LGPL License. bgneal@312: * bgneal@312: * License: http://tinymce.moxiecode.com/license bgneal@312: * Contributing: http://tinymce.moxiecode.com/contributing bgneal@312: */ bgneal@312: bgneal@312: (function() { bgneal@442: var each = tinymce.each, Node = tinymce.html.Node; bgneal@442: bgneal@312: tinymce.create('tinymce.plugins.FullPagePlugin', { bgneal@312: init : function(ed, url) { bgneal@312: var t = this; bgneal@312: bgneal@312: t.editor = ed; bgneal@312: bgneal@312: // Register commands bgneal@312: ed.addCommand('mceFullPageProperties', function() { bgneal@312: ed.windowManager.open({ bgneal@312: file : url + '/fullpage.htm', bgneal@312: width : 430 + parseInt(ed.getLang('fullpage.delta_width', 0)), bgneal@312: height : 495 + parseInt(ed.getLang('fullpage.delta_height', 0)), bgneal@312: inline : 1 bgneal@312: }, { bgneal@312: plugin_url : url, bgneal@442: data : t._htmlToData() bgneal@312: }); bgneal@312: }); bgneal@312: bgneal@312: // Register buttons bgneal@312: ed.addButton('fullpage', {title : 'fullpage.desc', cmd : 'mceFullPageProperties'}); bgneal@312: bgneal@312: ed.onBeforeSetContent.add(t._setContent, t); bgneal@312: ed.onGetContent.add(t._getContent, t); bgneal@312: }, bgneal@312: bgneal@312: getInfo : function() { bgneal@312: return { bgneal@312: longname : 'Fullpage', bgneal@312: author : 'Moxiecode Systems AB', bgneal@312: authorurl : 'http://tinymce.moxiecode.com', bgneal@312: infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullpage', bgneal@312: version : tinymce.majorVersion + "." + tinymce.minorVersion bgneal@312: }; bgneal@312: }, bgneal@312: bgneal@312: // Private plugin internal methods bgneal@312: bgneal@442: _htmlToData : function() { bgneal@442: var headerFragment = this._parseHeader(), data = {}, nodes, elm, matches, editor = this.editor; bgneal@312: bgneal@442: function getAttr(elm, name) { bgneal@442: var value = elm.attr(name); bgneal@312: bgneal@442: return value || ''; bgneal@442: }; bgneal@312: bgneal@442: // Default some values bgneal@442: data.fontface = editor.getParam("fullpage_default_fontface", ""); bgneal@442: data.fontsize = editor.getParam("fullpage_default_fontsize", ""); bgneal@312: bgneal@442: // Parse XML PI bgneal@442: elm = headerFragment.firstChild; bgneal@442: if (elm.type == 7) { bgneal@442: data.xml_pi = true; bgneal@442: matches = /encoding="([^"]+)"/.exec(elm.value); bgneal@442: if (matches) bgneal@442: data.docencoding = matches[1]; bgneal@442: } bgneal@312: bgneal@442: // Parse doctype bgneal@442: elm = headerFragment.getAll('#doctype')[0]; bgneal@442: if (elm) bgneal@442: data.doctype = '"; bgneal@442: bgneal@442: // Parse title element bgneal@442: elm = headerFragment.getAll('title')[0]; bgneal@442: if (elm && elm.firstChild) { bgneal@442: data.metatitle = elm.firstChild.value; bgneal@442: } bgneal@442: bgneal@442: // Parse meta elements bgneal@442: each(headerFragment.getAll('meta'), function(meta) { bgneal@442: var name = meta.attr('name'), httpEquiv = meta.attr('http-equiv'), matches; bgneal@442: bgneal@442: if (name) bgneal@442: data['meta' + name.toLowerCase()] = meta.attr('content'); bgneal@442: else if (httpEquiv == "Content-Type") { bgneal@442: matches = /charset\s*=\s*(.*)\s*/gi.exec(meta.attr('content')); bgneal@442: bgneal@442: if (matches) bgneal@442: data.docencoding = matches[1]; bgneal@442: } bgneal@442: }); bgneal@442: bgneal@442: // Parse html attribs bgneal@442: elm = headerFragment.getAll('html')[0]; bgneal@442: if (elm) bgneal@442: data.langcode = getAttr(elm, 'lang') || getAttr(elm, 'xml:lang'); bgneal@442: bgneal@442: // Parse stylesheet bgneal@442: elm = headerFragment.getAll('link')[0]; bgneal@442: if (elm && elm.attr('rel') == 'stylesheet') bgneal@442: data.stylesheet = elm.attr('href'); bgneal@442: bgneal@442: // Parse body parts bgneal@442: elm = headerFragment.getAll('body')[0]; bgneal@442: if (elm) { bgneal@442: data.langdir = getAttr(elm, 'dir'); bgneal@442: data.style = getAttr(elm, 'style'); bgneal@442: data.visited_color = getAttr(elm, 'vlink'); bgneal@442: data.link_color = getAttr(elm, 'link'); bgneal@442: data.active_color = getAttr(elm, 'alink'); bgneal@442: } bgneal@442: bgneal@442: return data; bgneal@442: }, bgneal@442: bgneal@442: _dataToHtml : function(data) { bgneal@442: var headerFragment, headElement, html, elm, value, dom = this.editor.dom; bgneal@442: bgneal@442: function setAttr(elm, name, value) { bgneal@442: elm.attr(name, value ? value : undefined); bgneal@442: }; bgneal@442: bgneal@442: function addHeadNode(node) { bgneal@442: if (headElement.firstChild) bgneal@442: headElement.insert(node, headElement.firstChild); bgneal@442: else bgneal@442: headElement.append(node); bgneal@442: }; bgneal@442: bgneal@442: headerFragment = this._parseHeader(); bgneal@442: headElement = headerFragment.getAll('head')[0]; bgneal@442: if (!headElement) { bgneal@442: elm = headerFragment.getAll('html')[0]; bgneal@442: headElement = new Node('head', 1); bgneal@442: bgneal@442: if (elm.firstChild) bgneal@442: elm.insert(headElement, elm.firstChild, true); bgneal@442: else bgneal@442: elm.append(headElement); bgneal@442: } bgneal@442: bgneal@442: // Add/update/remove XML-PI bgneal@442: elm = headerFragment.firstChild; bgneal@442: if (data.xml_pi) { bgneal@442: value = 'version="1.0"'; bgneal@442: bgneal@442: if (data.docencoding) bgneal@442: value += ' encoding="' + data.docencoding + '"'; bgneal@442: bgneal@442: if (elm.type != 7) { bgneal@442: elm = new Node('xml', 7); bgneal@442: headerFragment.insert(elm, headerFragment.firstChild, true); bgneal@442: } bgneal@442: bgneal@442: elm.value = value; bgneal@442: } else if (elm && elm.type == 7) bgneal@442: elm.remove(); bgneal@442: bgneal@442: // Add/update/remove doctype bgneal@442: elm = headerFragment.getAll('#doctype')[0]; bgneal@442: if (data.doctype) { bgneal@442: if (!elm) { bgneal@442: elm = new Node('#doctype', 10); bgneal@442: bgneal@442: if (data.xml_pi) bgneal@442: headerFragment.insert(elm, headerFragment.firstChild); bgneal@442: else bgneal@442: addHeadNode(elm); bgneal@442: } bgneal@442: bgneal@442: elm.value = data.doctype.substring(9, data.doctype.length - 1); bgneal@442: } else if (elm) bgneal@442: elm.remove(); bgneal@442: bgneal@442: // Add/update/remove title bgneal@442: elm = headerFragment.getAll('title')[0]; bgneal@442: if (data.metatitle) { bgneal@442: if (!elm) { bgneal@442: elm = new Node('title', 1); bgneal@442: elm.append(new Node('#text', 3)).value = data.metatitle; bgneal@442: addHeadNode(elm); bgneal@442: } bgneal@442: } bgneal@442: bgneal@442: // Add meta encoding bgneal@442: if (data.docencoding) { bgneal@442: elm = null; bgneal@442: each(headerFragment.getAll('meta'), function(meta) { bgneal@442: if (meta.attr('http-equiv') == 'Content-Type') bgneal@442: elm = meta; bgneal@442: }); bgneal@442: bgneal@442: if (!elm) { bgneal@442: elm = new Node('meta', 1); bgneal@442: elm.attr('http-equiv', 'Content-Type'); bgneal@442: elm.shortEnded = true; bgneal@442: addHeadNode(elm); bgneal@442: } bgneal@442: bgneal@442: elm.attr('content', 'text/html; charset=' + data.docencoding); bgneal@442: } bgneal@442: bgneal@442: // Add/update/remove meta bgneal@442: each('keywords,description,author,copyright,robots'.split(','), function(name) { bgneal@442: var nodes = headerFragment.getAll('meta'), i, meta, value = data['meta' + name]; bgneal@442: bgneal@442: for (i = 0; i < nodes.length; i++) { bgneal@442: meta = nodes[i]; bgneal@442: bgneal@442: if (meta.attr('name') == name) { bgneal@442: if (value) bgneal@442: meta.attr('content', value); bgneal@442: else bgneal@442: meta.remove(); bgneal@442: bgneal@442: return; bgneal@312: } bgneal@312: } bgneal@442: bgneal@442: if (value) { bgneal@442: elm = new Node('meta', 1); bgneal@442: elm.attr('name', name); bgneal@442: elm.attr('content', value); bgneal@442: elm.shortEnded = true; bgneal@442: bgneal@442: addHeadNode(elm); bgneal@442: } bgneal@442: }); bgneal@442: bgneal@442: // Add/update/delete link bgneal@442: elm = headerFragment.getAll('link')[0]; bgneal@442: if (elm && elm.attr('rel') == 'stylesheet') { bgneal@442: if (data.stylesheet) bgneal@442: elm.attr('href', data.stylesheet); bgneal@442: else bgneal@442: elm.remove(); bgneal@442: } else if (data.stylesheet) { bgneal@442: elm = new Node('link', 1); bgneal@442: elm.attr({ bgneal@442: rel : 'stylesheet', bgneal@442: text : 'text/css', bgneal@442: href : data.stylesheet bgneal@442: }); bgneal@442: elm.shortEnded = true; bgneal@442: bgneal@442: addHeadNode(elm); bgneal@312: } bgneal@442: bgneal@442: // Update body attributes bgneal@442: elm = headerFragment.getAll('body')[0]; bgneal@442: if (elm) { bgneal@442: setAttr(elm, 'dir', data.langdir); bgneal@442: setAttr(elm, 'style', data.style); bgneal@442: setAttr(elm, 'vlink', data.visited_color); bgneal@442: setAttr(elm, 'link', data.link_color); bgneal@442: setAttr(elm, 'alink', data.active_color); bgneal@442: bgneal@442: // Update iframe body as well bgneal@442: dom.setAttribs(this.editor.getBody(), { bgneal@442: style : data.style, bgneal@442: dir : data.dir, bgneal@442: vLink : data.visited_color, bgneal@442: link : data.link_color, bgneal@442: aLink : data.active_color bgneal@442: }); bgneal@442: } bgneal@442: bgneal@442: // Set html attributes bgneal@442: elm = headerFragment.getAll('html')[0]; bgneal@442: if (elm) { bgneal@442: setAttr(elm, 'lang', data.langcode); bgneal@442: setAttr(elm, 'xml:lang', data.langcode); bgneal@442: } bgneal@442: bgneal@442: // Serialize header fragment and crop away body part bgneal@442: html = new tinymce.html.Serializer({ bgneal@442: validate: false, bgneal@442: indent: true, bgneal@442: apply_source_formatting : true, bgneal@442: indent_before: 'head,html,body,meta,title,script,link,style', bgneal@442: indent_after: 'head,html,body,meta,title,script,link,style' bgneal@442: }).serialize(headerFragment); bgneal@442: bgneal@442: this.head = html.substring(0, html.indexOf('')); bgneal@312: }, bgneal@312: bgneal@442: _parseHeader : function() { bgneal@442: // Parse the contents with a DOM parser bgneal@442: return new tinymce.html.DomParser({ bgneal@442: validate: false, bgneal@442: root_name: '#document' bgneal@442: }).parse(this.head); bgneal@312: }, bgneal@312: bgneal@312: _setContent : function(ed, o) { bgneal@442: var self = this, startPos, endPos, content = o.content, headerFragment, styles = '', dom = self.editor.dom, elm; bgneal@442: bgneal@442: function low(s) { bgneal@442: return s.replace(/<\/?[A-Z]+/g, function(a) { bgneal@442: return a.toLowerCase(); bgneal@442: }) bgneal@442: }; bgneal@312: bgneal@312: // Ignore raw updated if we already have a head, this will fix issues with undo/redo keeping the head/foot separate bgneal@442: if (o.format == 'raw' && self.head) bgneal@312: return; bgneal@312: bgneal@312: if (o.source_view && ed.getParam('fullpage_hide_in_source_view')) bgneal@312: return; bgneal@312: bgneal@312: // Parse out head, body and footer bgneal@442: content = content.replace(/<(\/?)BODY/gi, '<$1body'); bgneal@442: startPos = content.indexOf('', startPos); bgneal@442: self.head = low(content.substring(0, startPos + 1)); bgneal@312: bgneal@442: endPos = content.indexOf('\n'; bgneal@312: bgneal@442: header += editor.getParam('fullpage_default_doctype', ''); bgneal@442: header += '\n\n\n'; bgneal@312: bgneal@442: if (value = editor.getParam('fullpage_default_title')) bgneal@442: header += '' + v + '\n'; bgneal@312: bgneal@442: if (value = editor.getParam('fullpage_default_encoding')) bgneal@442: header += '\n'; bgneal@442: bgneal@442: if (value = editor.getParam('fullpage_default_font_family')) bgneal@442: styles += 'font-family: ' + value + ';'; bgneal@442: bgneal@442: if (value = editor.getParam('fullpage_default_font_size')) bgneal@442: styles += 'font-size: ' + value + ';'; bgneal@442: bgneal@442: if (value = editor.getParam('fullpage_default_text_color')) bgneal@442: styles += 'color: ' + value + ';'; bgneal@442: bgneal@442: header += '\n\n'; bgneal@442: bgneal@442: return header; bgneal@312: }, bgneal@312: bgneal@312: _getContent : function(ed, o) { bgneal@442: var self = this; bgneal@312: bgneal@312: if (!o.source_view || !ed.getParam('fullpage_hide_in_source_view')) bgneal@442: o.content = tinymce.trim(self.head) + '\n' + tinymce.trim(o.content) + '\n' + tinymce.trim(self.foot); bgneal@312: } bgneal@312: }); bgneal@312: bgneal@312: // Register plugin bgneal@312: tinymce.PluginManager.add('fullpage', tinymce.plugins.FullPagePlugin); bgneal@442: })();