| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485 |
- /**
- * plugin.js
- *
- * Copyright, Moxiecode Systems AB
- * Released under LGPL License.
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
- /*global tinymce:true */
- tinymce.PluginManager.add('fullpage', function(editor) {
- var each = tinymce.each, Node = tinymce.html.Node;
- var head, foot;
- function showDialog() {
- var data = htmlToData();
- editor.windowManager.open({
- title: 'Document properties',
- data: data,
- defaults: {type: 'textbox', size: 40},
- body: [
- {name: 'title', label: 'Title'},
- {name: 'keywords', label: 'Keywords'},
- {name: 'description', label: 'Description'},
- {name: 'robots', label: 'Robots'},
- {name: 'author', label: 'Author'},
- {name: 'docencoding', label: 'Encoding'}
- ],
- onSubmit: function(e) {
- dataToHtml(tinymce.extend(data, e.data));
- }
- });
- }
- function htmlToData() {
- var headerFragment = parseHeader(), data = {}, elm, matches;
- function getAttr(elm, name) {
- var value = elm.attr(name);
- return value || '';
- }
- // Default some values
- data.fontface = editor.getParam("fullpage_default_fontface", "");
- data.fontsize = editor.getParam("fullpage_default_fontsize", "");
- // Parse XML PI
- elm = headerFragment.firstChild;
- if (elm.type == 7) {
- data.xml_pi = true;
- matches = /encoding="([^"]+)"/.exec(elm.value);
- if (matches) {
- data.docencoding = matches[1];
- }
- }
- // Parse doctype
- elm = headerFragment.getAll('#doctype')[0];
- if (elm) {
- data.doctype = '<!DOCTYPE' + elm.value + ">";
- }
- // Parse title element
- elm = headerFragment.getAll('title')[0];
- if (elm && elm.firstChild) {
- data.title = elm.firstChild.value;
- }
- // Parse meta elements
- each(headerFragment.getAll('meta'), function(meta) {
- var name = meta.attr('name'), httpEquiv = meta.attr('http-equiv'), matches;
- if (name) {
- data[name.toLowerCase()] = meta.attr('content');
- } else if (httpEquiv == "Content-Type") {
- matches = /charset\s*=\s*(.*)\s*/gi.exec(meta.attr('content'));
- if (matches) {
- data.docencoding = matches[1];
- }
- }
- });
- // Parse html attribs
- elm = headerFragment.getAll('html')[0];
- if (elm) {
- data.langcode = getAttr(elm, 'lang') || getAttr(elm, 'xml:lang');
- }
- // Parse stylesheets
- data.stylesheets = [];
- tinymce.each(headerFragment.getAll('link'), function(link) {
- if (link.attr('rel') == 'stylesheet') {
- data.stylesheets.push(link.attr('href'));
- }
- });
- // Parse body parts
- elm = headerFragment.getAll('body')[0];
- if (elm) {
- data.langdir = getAttr(elm, 'dir');
- data.style = getAttr(elm, 'style');
- data.visited_color = getAttr(elm, 'vlink');
- data.link_color = getAttr(elm, 'link');
- data.active_color = getAttr(elm, 'alink');
- }
- return data;
- }
- function dataToHtml(data) {
- var headerFragment, headElement, html, elm, value, dom = editor.dom;
- function setAttr(elm, name, value) {
- elm.attr(name, value ? value : undefined);
- }
- function addHeadNode(node) {
- if (headElement.firstChild) {
- headElement.insert(node, headElement.firstChild);
- } else {
- headElement.append(node);
- }
- }
- headerFragment = parseHeader();
- headElement = headerFragment.getAll('head')[0];
- if (!headElement) {
- elm = headerFragment.getAll('html')[0];
- headElement = new Node('head', 1);
- if (elm.firstChild) {
- elm.insert(headElement, elm.firstChild, true);
- } else {
- elm.append(headElement);
- }
- }
- // Add/update/remove XML-PI
- elm = headerFragment.firstChild;
- if (data.xml_pi) {
- value = 'version="1.0"';
- if (data.docencoding) {
- value += ' encoding="' + data.docencoding + '"';
- }
- if (elm.type != 7) {
- elm = new Node('xml', 7);
- headerFragment.insert(elm, headerFragment.firstChild, true);
- }
- elm.value = value;
- } else if (elm && elm.type == 7) {
- elm.remove();
- }
- // Add/update/remove doctype
- elm = headerFragment.getAll('#doctype')[0];
- if (data.doctype) {
- if (!elm) {
- elm = new Node('#doctype', 10);
- if (data.xml_pi) {
- headerFragment.insert(elm, headerFragment.firstChild);
- } else {
- addHeadNode(elm);
- }
- }
- elm.value = data.doctype.substring(9, data.doctype.length - 1);
- } else if (elm) {
- elm.remove();
- }
- // Add meta encoding
- elm = null;
- each(headerFragment.getAll('meta'), function(meta) {
- if (meta.attr('http-equiv') == 'Content-Type') {
- elm = meta;
- }
- });
- if (data.docencoding) {
- if (!elm) {
- elm = new Node('meta', 1);
- elm.attr('http-equiv', 'Content-Type');
- elm.shortEnded = true;
- addHeadNode(elm);
- }
- elm.attr('content', 'text/html; charset=' + data.docencoding);
- } else {
- elm.remove();
- }
- // Add/update/remove title
- elm = headerFragment.getAll('title')[0];
- if (data.title) {
- if (!elm) {
- elm = new Node('title', 1);
- addHeadNode(elm);
- } else {
- elm.empty();
- }
- elm.append(new Node('#text', 3)).value = data.title;
- } else if (elm) {
- elm.remove();
- }
- // Add/update/remove meta
- each('keywords,description,author,copyright,robots'.split(','), function(name) {
- var nodes = headerFragment.getAll('meta'), i, meta, value = data[name];
- for (i = 0; i < nodes.length; i++) {
- meta = nodes[i];
- if (meta.attr('name') == name) {
- if (value) {
- meta.attr('content', value);
- } else {
- meta.remove();
- }
- return;
- }
- }
- if (value) {
- elm = new Node('meta', 1);
- elm.attr('name', name);
- elm.attr('content', value);
- elm.shortEnded = true;
- addHeadNode(elm);
- }
- });
- var currentStyleSheetsMap = {};
- tinymce.each(headerFragment.getAll('link'), function(stylesheet) {
- if (stylesheet.attr('rel') == 'stylesheet') {
- currentStyleSheetsMap[stylesheet.attr('href')] = stylesheet;
- }
- });
- // Add new
- tinymce.each(data.stylesheets, function(stylesheet) {
- if (!currentStyleSheetsMap[stylesheet]) {
- elm = new Node('link', 1);
- elm.attr({
- rel: 'stylesheet',
- text: 'text/css',
- href: stylesheet
- });
- elm.shortEnded = true;
- addHeadNode(elm);
- }
- delete currentStyleSheetsMap[stylesheet];
- });
- // Delete old
- tinymce.each(currentStyleSheetsMap, function(stylesheet) {
- stylesheet.remove();
- });
- // Update body attributes
- elm = headerFragment.getAll('body')[0];
- if (elm) {
- setAttr(elm, 'dir', data.langdir);
- setAttr(elm, 'style', data.style);
- setAttr(elm, 'vlink', data.visited_color);
- setAttr(elm, 'link', data.link_color);
- setAttr(elm, 'alink', data.active_color);
- // Update iframe body as well
- dom.setAttribs(editor.getBody(), {
- style : data.style,
- dir : data.dir,
- vLink : data.visited_color,
- link : data.link_color,
- aLink : data.active_color
- });
- }
- // Set html attributes
- elm = headerFragment.getAll('html')[0];
- if (elm) {
- setAttr(elm, 'lang', data.langcode);
- setAttr(elm, 'xml:lang', data.langcode);
- }
- // No need for a head element
- if (!headElement.firstChild) {
- headElement.remove();
- }
- // Serialize header fragment and crop away body part
- html = new tinymce.html.Serializer({
- validate: false,
- indent: true,
- apply_source_formatting : true,
- indent_before: 'head,html,body,meta,title,script,link,style',
- indent_after: 'head,html,body,meta,title,script,link,style'
- }).serialize(headerFragment);
- head = html.substring(0, html.indexOf('</body>'));
- }
- function parseHeader() {
- // Parse the contents with a DOM parser
- return new tinymce.html.DomParser({
- validate: false,
- root_name: '#document'
- }).parse(head);
- }
- function setContent(evt) {
- var startPos, endPos, content = evt.content, headerFragment, styles = '', dom = editor.dom, elm;
- if (evt.selection) {
- return;
- }
- function low(s) {
- return s.replace(/<\/?[A-Z]+/g, function(a) {
- return a.toLowerCase();
- });
- }
- // Ignore raw updated if we already have a head, this will fix issues with undo/redo keeping the head/foot separate
- if (evt.format == 'raw' && head) {
- return;
- }
- if (evt.source_view && editor.getParam('fullpage_hide_in_source_view')) {
- return;
- }
- // Parse out head, body and footer
- content = content.replace(/<(\/?)BODY/gi, '<$1body');
- startPos = content.indexOf('<body');
- if (startPos != -1) {
- startPos = content.indexOf('>', startPos);
- head = low(content.substring(0, startPos + 1));
- endPos = content.indexOf('</body', startPos);
- if (endPos == -1) {
- endPos = content.length;
- }
- evt.content = content.substring(startPos + 1, endPos);
- foot = low(content.substring(endPos));
- } else {
- head = getDefaultHeader();
- foot = '\n</body>\n</html>';
- }
- // Parse header and update iframe
- headerFragment = parseHeader();
- each(headerFragment.getAll('style'), function(node) {
- if (node.firstChild) {
- styles += node.firstChild.value;
- }
- });
- elm = headerFragment.getAll('body')[0];
- if (elm) {
- dom.setAttribs(editor.getBody(), {
- style: elm.attr('style') || '',
- dir: elm.attr('dir') || '',
- vLink: elm.attr('vlink') || '',
- link: elm.attr('link') || '',
- aLink: elm.attr('alink') || ''
- });
- }
- dom.remove('fullpage_styles');
- var headElm = editor.getDoc().getElementsByTagName('head')[0];
- if (styles) {
- dom.add(headElm, 'style', {
- id : 'fullpage_styles'
- }, styles);
- // Needed for IE 6/7
- elm = dom.get('fullpage_styles');
- if (elm.styleSheet) {
- elm.styleSheet.cssText = styles;
- }
- }
- var currentStyleSheetsMap = {};
- tinymce.each(headElm.getElementsByTagName('link'), function(stylesheet) {
- if (stylesheet.rel == 'stylesheet' && stylesheet.getAttribute('data-mce-fullpage')) {
- currentStyleSheetsMap[stylesheet.href] = stylesheet;
- }
- });
- // Add new
- tinymce.each(headerFragment.getAll('link'), function(stylesheet) {
- var href = stylesheet.attr('href');
- if (!currentStyleSheetsMap[href] && stylesheet.attr('rel') == 'stylesheet') {
- dom.add(headElm, 'link', {
- rel: 'stylesheet',
- text: 'text/css',
- href: href,
- 'data-mce-fullpage': '1'
- });
- }
- delete currentStyleSheetsMap[href];
- });
- // Delete old
- tinymce.each(currentStyleSheetsMap, function(stylesheet) {
- stylesheet.parentNode.removeChild(stylesheet);
- });
- }
- function getDefaultHeader() {
- var header = '', value, styles = '';
- if (editor.getParam('fullpage_default_xml_pi')) {
- header += '<?xml version="1.0" encoding="' + editor.getParam('fullpage_default_encoding', 'ISO-8859-1') + '" ?>\n';
- }
- header += editor.getParam('fullpage_default_doctype', '<!DOCTYPE html>');
- header += '\n<html>\n<head>\n';
- if ((value = editor.getParam('fullpage_default_title'))) {
- header += '<title>' + value + '</title>\n';
- }
- if ((value = editor.getParam('fullpage_default_encoding'))) {
- header += '<meta http-equiv="Content-Type" content="text/html; charset=' + value + '" />\n';
- }
- if ((value = editor.getParam('fullpage_default_font_family'))) {
- styles += 'font-family: ' + value + ';';
- }
- if ((value = editor.getParam('fullpage_default_font_size'))) {
- styles += 'font-size: ' + value + ';';
- }
- if ((value = editor.getParam('fullpage_default_text_color'))) {
- styles += 'color: ' + value + ';';
- }
- header += '</head>\n<body' + (styles ? ' style="' + styles + '"' : '') + '>\n';
- return header;
- }
- function getContent(evt) {
- if (!evt.selection && (!evt.source_view || !editor.getParam('fullpage_hide_in_source_view'))) {
- evt.content = tinymce.trim(head) + '\n' + tinymce.trim(evt.content) + '\n' + tinymce.trim(foot);
- }
- }
- editor.addCommand('mceFullPageProperties', showDialog);
- editor.addButton('fullpage', {
- title: 'Document properties',
- cmd : 'mceFullPageProperties'
- });
- editor.addMenuItem('fullpage', {
- text: 'Document properties',
- cmd : 'mceFullPageProperties',
- context: 'file'
- });
- editor.on('BeforeSetContent', setContent);
- editor.on('GetContent', getContent);
- });
|