src/pyams_skin/resources/js/ext/tinymce/dev/plugins/fullpage/plugin.js
changeset 69 a361355b55c7
equal deleted inserted replaced
68:fd8fb93e1b6a 69:a361355b55c7
       
     1 /**
       
     2  * plugin.js
       
     3  *
       
     4  * Copyright, Moxiecode Systems AB
       
     5  * Released under LGPL License.
       
     6  *
       
     7  * License: http://www.tinymce.com/license
       
     8  * Contributing: http://www.tinymce.com/contributing
       
     9  */
       
    10 
       
    11 /*global tinymce:true */
       
    12 
       
    13 tinymce.PluginManager.add('fullpage', function(editor) {
       
    14 	var each = tinymce.each, Node = tinymce.html.Node;
       
    15 	var head, foot;
       
    16 
       
    17 	function showDialog() {
       
    18 		var data = htmlToData();
       
    19 
       
    20 		editor.windowManager.open({
       
    21 			title: 'Document properties',
       
    22 			data: data,
       
    23 			defaults: {type: 'textbox', size: 40},
       
    24 			body: [
       
    25 				{name: 'title', label: 'Title'},
       
    26 				{name: 'keywords', label: 'Keywords'},
       
    27 				{name: 'description', label: 'Description'},
       
    28 				{name: 'robots', label: 'Robots'},
       
    29 				{name: 'author', label: 'Author'},
       
    30 				{name: 'docencoding', label: 'Encoding'}
       
    31 			],
       
    32 			onSubmit: function(e) {
       
    33 				dataToHtml(tinymce.extend(data, e.data));
       
    34 			}
       
    35 		});
       
    36 	}
       
    37 
       
    38 	function htmlToData() {
       
    39 		var headerFragment = parseHeader(), data = {}, elm, matches;
       
    40 
       
    41 		function getAttr(elm, name) {
       
    42 			var value = elm.attr(name);
       
    43 
       
    44 			return value || '';
       
    45 		}
       
    46 
       
    47 		// Default some values
       
    48 		data.fontface = editor.getParam("fullpage_default_fontface", "");
       
    49 		data.fontsize = editor.getParam("fullpage_default_fontsize", "");
       
    50 
       
    51 		// Parse XML PI
       
    52 		elm = headerFragment.firstChild;
       
    53 		if (elm.type == 7) {
       
    54 			data.xml_pi = true;
       
    55 			matches = /encoding="([^"]+)"/.exec(elm.value);
       
    56 			if (matches) {
       
    57 				data.docencoding = matches[1];
       
    58 			}
       
    59 		}
       
    60 
       
    61 		// Parse doctype
       
    62 		elm = headerFragment.getAll('#doctype')[0];
       
    63 		if (elm) {
       
    64 			data.doctype = '<!DOCTYPE' + elm.value + ">";
       
    65 		}
       
    66 
       
    67 		// Parse title element
       
    68 		elm = headerFragment.getAll('title')[0];
       
    69 		if (elm && elm.firstChild) {
       
    70 			data.title = elm.firstChild.value;
       
    71 		}
       
    72 
       
    73 		// Parse meta elements
       
    74 		each(headerFragment.getAll('meta'), function(meta) {
       
    75 			var name = meta.attr('name'), httpEquiv = meta.attr('http-equiv'), matches;
       
    76 
       
    77 			if (name) {
       
    78 				data[name.toLowerCase()] = meta.attr('content');
       
    79 			} else if (httpEquiv == "Content-Type") {
       
    80 				matches = /charset\s*=\s*(.*)\s*/gi.exec(meta.attr('content'));
       
    81 
       
    82 				if (matches) {
       
    83 					data.docencoding = matches[1];
       
    84 				}
       
    85 			}
       
    86 		});
       
    87 
       
    88 		// Parse html attribs
       
    89 		elm = headerFragment.getAll('html')[0];
       
    90 		if (elm) {
       
    91 			data.langcode = getAttr(elm, 'lang') || getAttr(elm, 'xml:lang');
       
    92 		}
       
    93 
       
    94 		// Parse stylesheets
       
    95 		data.stylesheets = [];
       
    96 		tinymce.each(headerFragment.getAll('link'), function(link) {
       
    97 			if (link.attr('rel') == 'stylesheet') {
       
    98 				data.stylesheets.push(link.attr('href'));
       
    99 			}
       
   100 		});
       
   101 
       
   102 		// Parse body parts
       
   103 		elm = headerFragment.getAll('body')[0];
       
   104 		if (elm) {
       
   105 			data.langdir = getAttr(elm, 'dir');
       
   106 			data.style = getAttr(elm, 'style');
       
   107 			data.visited_color = getAttr(elm, 'vlink');
       
   108 			data.link_color = getAttr(elm, 'link');
       
   109 			data.active_color = getAttr(elm, 'alink');
       
   110 		}
       
   111 
       
   112 		return data;
       
   113 	}
       
   114 
       
   115 	function dataToHtml(data) {
       
   116 		var headerFragment, headElement, html, elm, value, dom = editor.dom;
       
   117 
       
   118 		function setAttr(elm, name, value) {
       
   119 			elm.attr(name, value ? value : undefined);
       
   120 		}
       
   121 
       
   122 		function addHeadNode(node) {
       
   123 			if (headElement.firstChild) {
       
   124 				headElement.insert(node, headElement.firstChild);
       
   125 			} else {
       
   126 				headElement.append(node);
       
   127 			}
       
   128 		}
       
   129 
       
   130 		headerFragment = parseHeader();
       
   131 		headElement = headerFragment.getAll('head')[0];
       
   132 		if (!headElement) {
       
   133 			elm = headerFragment.getAll('html')[0];
       
   134 			headElement = new Node('head', 1);
       
   135 
       
   136 			if (elm.firstChild) {
       
   137 				elm.insert(headElement, elm.firstChild, true);
       
   138 			} else {
       
   139 				elm.append(headElement);
       
   140 			}
       
   141 		}
       
   142 
       
   143 		// Add/update/remove XML-PI
       
   144 		elm = headerFragment.firstChild;
       
   145 		if (data.xml_pi) {
       
   146 			value = 'version="1.0"';
       
   147 
       
   148 			if (data.docencoding) {
       
   149 				value += ' encoding="' + data.docencoding + '"';
       
   150 			}
       
   151 
       
   152 			if (elm.type != 7) {
       
   153 				elm = new Node('xml', 7);
       
   154 				headerFragment.insert(elm, headerFragment.firstChild, true);
       
   155 			}
       
   156 
       
   157 			elm.value = value;
       
   158 		} else if (elm && elm.type == 7) {
       
   159 			elm.remove();
       
   160 		}
       
   161 
       
   162 		// Add/update/remove doctype
       
   163 		elm = headerFragment.getAll('#doctype')[0];
       
   164 		if (data.doctype) {
       
   165 			if (!elm) {
       
   166 				elm = new Node('#doctype', 10);
       
   167 
       
   168 				if (data.xml_pi) {
       
   169 					headerFragment.insert(elm, headerFragment.firstChild);
       
   170 				} else {
       
   171 					addHeadNode(elm);
       
   172 				}
       
   173 			}
       
   174 
       
   175 			elm.value = data.doctype.substring(9, data.doctype.length - 1);
       
   176 		} else if (elm) {
       
   177 			elm.remove();
       
   178 		}
       
   179 
       
   180 		// Add meta encoding
       
   181 		elm = null;
       
   182 		each(headerFragment.getAll('meta'), function(meta) {
       
   183 			if (meta.attr('http-equiv') == 'Content-Type') {
       
   184 				elm = meta;
       
   185 			}
       
   186 		});
       
   187 
       
   188 		if (data.docencoding) {
       
   189 			if (!elm) {
       
   190 				elm = new Node('meta', 1);
       
   191 				elm.attr('http-equiv', 'Content-Type');
       
   192 				elm.shortEnded = true;
       
   193 				addHeadNode(elm);
       
   194 			}
       
   195 
       
   196 			elm.attr('content', 'text/html; charset=' + data.docencoding);
       
   197 		} else if (elm) {
       
   198 			elm.remove();
       
   199 		}
       
   200 
       
   201 		// Add/update/remove title
       
   202 		elm = headerFragment.getAll('title')[0];
       
   203 		if (data.title) {
       
   204 			if (!elm) {
       
   205 				elm = new Node('title', 1);
       
   206 				addHeadNode(elm);
       
   207 			} else {
       
   208 				elm.empty();
       
   209 			}
       
   210 
       
   211 			elm.append(new Node('#text', 3)).value = data.title;
       
   212 		} else if (elm) {
       
   213 			elm.remove();
       
   214 		}
       
   215 
       
   216 		// Add/update/remove meta
       
   217 		each('keywords,description,author,copyright,robots'.split(','), function(name) {
       
   218 			var nodes = headerFragment.getAll('meta'), i, meta, value = data[name];
       
   219 
       
   220 			for (i = 0; i < nodes.length; i++) {
       
   221 				meta = nodes[i];
       
   222 
       
   223 				if (meta.attr('name') == name) {
       
   224 					if (value) {
       
   225 						meta.attr('content', value);
       
   226 					} else {
       
   227 						meta.remove();
       
   228 					}
       
   229 
       
   230 					return;
       
   231 				}
       
   232 			}
       
   233 
       
   234 			if (value) {
       
   235 				elm = new Node('meta', 1);
       
   236 				elm.attr('name', name);
       
   237 				elm.attr('content', value);
       
   238 				elm.shortEnded = true;
       
   239 
       
   240 				addHeadNode(elm);
       
   241 			}
       
   242 		});
       
   243 
       
   244 		var currentStyleSheetsMap = {};
       
   245 		tinymce.each(headerFragment.getAll('link'), function(stylesheet) {
       
   246 			if (stylesheet.attr('rel') == 'stylesheet') {
       
   247 				currentStyleSheetsMap[stylesheet.attr('href')] = stylesheet;
       
   248 			}
       
   249 		});
       
   250 
       
   251 		// Add new
       
   252 		tinymce.each(data.stylesheets, function(stylesheet) {
       
   253 			if (!currentStyleSheetsMap[stylesheet]) {
       
   254 				elm = new Node('link', 1);
       
   255 				elm.attr({
       
   256 					rel: 'stylesheet',
       
   257 					text: 'text/css',
       
   258 					href: stylesheet
       
   259 				});
       
   260 				elm.shortEnded = true;
       
   261 				addHeadNode(elm);
       
   262 			}
       
   263 
       
   264 			delete currentStyleSheetsMap[stylesheet];
       
   265 		});
       
   266 
       
   267 		// Delete old
       
   268 		tinymce.each(currentStyleSheetsMap, function(stylesheet) {
       
   269 			stylesheet.remove();
       
   270 		});
       
   271 
       
   272 		// Update body attributes
       
   273 		elm = headerFragment.getAll('body')[0];
       
   274 		if (elm) {
       
   275 			setAttr(elm, 'dir', data.langdir);
       
   276 			setAttr(elm, 'style', data.style);
       
   277 			setAttr(elm, 'vlink', data.visited_color);
       
   278 			setAttr(elm, 'link', data.link_color);
       
   279 			setAttr(elm, 'alink', data.active_color);
       
   280 
       
   281 			// Update iframe body as well
       
   282 			dom.setAttribs(editor.getBody(), {
       
   283 				style: data.style,
       
   284 				dir: data.dir,
       
   285 				vLink: data.visited_color,
       
   286 				link: data.link_color,
       
   287 				aLink: data.active_color
       
   288 			});
       
   289 		}
       
   290 
       
   291 		// Set html attributes
       
   292 		elm = headerFragment.getAll('html')[0];
       
   293 		if (elm) {
       
   294 			setAttr(elm, 'lang', data.langcode);
       
   295 			setAttr(elm, 'xml:lang', data.langcode);
       
   296 		}
       
   297 
       
   298 		// No need for a head element
       
   299 		if (!headElement.firstChild) {
       
   300 			headElement.remove();
       
   301 		}
       
   302 
       
   303 		// Serialize header fragment and crop away body part
       
   304 		html = new tinymce.html.Serializer({
       
   305 			validate: false,
       
   306 			indent: true,
       
   307 			apply_source_formatting: true,
       
   308 			indent_before: 'head,html,body,meta,title,script,link,style',
       
   309 			indent_after: 'head,html,body,meta,title,script,link,style'
       
   310 		}).serialize(headerFragment);
       
   311 
       
   312 		head = html.substring(0, html.indexOf('</body>'));
       
   313 	}
       
   314 
       
   315 	function parseHeader() {
       
   316 		// Parse the contents with a DOM parser
       
   317 		return new tinymce.html.DomParser({
       
   318 			validate: false,
       
   319 			root_name: '#document'
       
   320 		}).parse(head);
       
   321 	}
       
   322 
       
   323 	function setContent(evt) {
       
   324 		var startPos, endPos, content = evt.content, headerFragment, styles = '', dom = editor.dom, elm;
       
   325 
       
   326 		if (evt.selection) {
       
   327 			return;
       
   328 		}
       
   329 
       
   330 		function low(s) {
       
   331 			return s.replace(/<\/?[A-Z]+/g, function(a) {
       
   332 				return a.toLowerCase();
       
   333 			});
       
   334 		}
       
   335 
       
   336 		// Ignore raw updated if we already have a head, this will fix issues with undo/redo keeping the head/foot separate
       
   337 		if (evt.format == 'raw' && head) {
       
   338 			return;
       
   339 		}
       
   340 
       
   341 		if (evt.source_view && editor.getParam('fullpage_hide_in_source_view')) {
       
   342 			return;
       
   343 		}
       
   344 
       
   345 		// Fixed so new document/setContent('') doesn't remove existing header/footer except when it's in source code view
       
   346 		if (content.length === 0 && !evt.source_view) {
       
   347 			content = tinymce.trim(head) + '\n' + tinymce.trim(content) + '\n' + tinymce.trim(foot);
       
   348 		}
       
   349 
       
   350 		// Parse out head, body and footer
       
   351 		content = content.replace(/<(\/?)BODY/gi, '<$1body');
       
   352 		startPos = content.indexOf('<body');
       
   353 
       
   354 		if (startPos != -1) {
       
   355 			startPos = content.indexOf('>', startPos);
       
   356 			head = low(content.substring(0, startPos + 1));
       
   357 
       
   358 			endPos = content.indexOf('</body', startPos);
       
   359 			if (endPos == -1) {
       
   360 				endPos = content.length;
       
   361 			}
       
   362 
       
   363 			evt.content = content.substring(startPos + 1, endPos);
       
   364 			foot = low(content.substring(endPos));
       
   365 		} else {
       
   366 			head = getDefaultHeader();
       
   367 			foot = '\n</body>\n</html>';
       
   368 		}
       
   369 
       
   370 		// Parse header and update iframe
       
   371 		headerFragment = parseHeader();
       
   372 		each(headerFragment.getAll('style'), function(node) {
       
   373 			if (node.firstChild) {
       
   374 				styles += node.firstChild.value;
       
   375 			}
       
   376 		});
       
   377 
       
   378 		elm = headerFragment.getAll('body')[0];
       
   379 		if (elm) {
       
   380 			dom.setAttribs(editor.getBody(), {
       
   381 				style: elm.attr('style') || '',
       
   382 				dir: elm.attr('dir') || '',
       
   383 				vLink: elm.attr('vlink') || '',
       
   384 				link: elm.attr('link') || '',
       
   385 				aLink: elm.attr('alink') || ''
       
   386 			});
       
   387 		}
       
   388 
       
   389 		dom.remove('fullpage_styles');
       
   390 
       
   391 		var headElm = editor.getDoc().getElementsByTagName('head')[0];
       
   392 
       
   393 		if (styles) {
       
   394 			dom.add(headElm, 'style', {
       
   395 				id: 'fullpage_styles'
       
   396 			}, styles);
       
   397 
       
   398 			// Needed for IE 6/7
       
   399 			elm = dom.get('fullpage_styles');
       
   400 			if (elm.styleSheet) {
       
   401 				elm.styleSheet.cssText = styles;
       
   402 			}
       
   403 		}
       
   404 
       
   405 		var currentStyleSheetsMap = {};
       
   406 		tinymce.each(headElm.getElementsByTagName('link'), function(stylesheet) {
       
   407 			if (stylesheet.rel == 'stylesheet' && stylesheet.getAttribute('data-mce-fullpage')) {
       
   408 				currentStyleSheetsMap[stylesheet.href] = stylesheet;
       
   409 			}
       
   410 		});
       
   411 
       
   412 		// Add new
       
   413 		tinymce.each(headerFragment.getAll('link'), function(stylesheet) {
       
   414 			var href = stylesheet.attr('href');
       
   415 
       
   416 			if (!currentStyleSheetsMap[href] && stylesheet.attr('rel') == 'stylesheet') {
       
   417 				dom.add(headElm, 'link', {
       
   418 					rel: 'stylesheet',
       
   419 					text: 'text/css',
       
   420 					href: href,
       
   421 					'data-mce-fullpage': '1'
       
   422 				});
       
   423 			}
       
   424 
       
   425 			delete currentStyleSheetsMap[href];
       
   426 		});
       
   427 
       
   428 		// Delete old
       
   429 		tinymce.each(currentStyleSheetsMap, function(stylesheet) {
       
   430 			stylesheet.parentNode.removeChild(stylesheet);
       
   431 		});
       
   432 	}
       
   433 
       
   434 	function getDefaultHeader() {
       
   435 		var header = '', value, styles = '';
       
   436 
       
   437 		if (editor.getParam('fullpage_default_xml_pi')) {
       
   438 			header += '<?xml version="1.0" encoding="' + editor.getParam('fullpage_default_encoding', 'ISO-8859-1') + '" ?>\n';
       
   439 		}
       
   440 
       
   441 		header += editor.getParam('fullpage_default_doctype', '<!DOCTYPE html>');
       
   442 		header += '\n<html>\n<head>\n';
       
   443 
       
   444 		if ((value = editor.getParam('fullpage_default_title'))) {
       
   445 			header += '<title>' + value + '</title>\n';
       
   446 		}
       
   447 
       
   448 		if ((value = editor.getParam('fullpage_default_encoding'))) {
       
   449 			header += '<meta http-equiv="Content-Type" content="text/html; charset=' + value + '" />\n';
       
   450 		}
       
   451 
       
   452 		if ((value = editor.getParam('fullpage_default_font_family'))) {
       
   453 			styles += 'font-family: ' + value + ';';
       
   454 		}
       
   455 
       
   456 		if ((value = editor.getParam('fullpage_default_font_size'))) {
       
   457 			styles += 'font-size: ' + value + ';';
       
   458 		}
       
   459 
       
   460 		if ((value = editor.getParam('fullpage_default_text_color'))) {
       
   461 			styles += 'color: ' + value + ';';
       
   462 		}
       
   463 
       
   464 		header += '</head>\n<body' + (styles ? ' style="' + styles + '"' : '') + '>\n';
       
   465 
       
   466 		return header;
       
   467 	}
       
   468 
       
   469 	function getContent(evt) {
       
   470 		if (!evt.selection && (!evt.source_view || !editor.getParam('fullpage_hide_in_source_view'))) {
       
   471 			evt.content = tinymce.trim(head) + '\n' + tinymce.trim(evt.content) + '\n' + tinymce.trim(foot);
       
   472 		}
       
   473 	}
       
   474 
       
   475 	editor.addCommand('mceFullPageProperties', showDialog);
       
   476 
       
   477 	editor.addButton('fullpage', {
       
   478 		title: 'Document properties',
       
   479 		cmd: 'mceFullPageProperties'
       
   480 	});
       
   481 
       
   482 	editor.addMenuItem('fullpage', {
       
   483 		text: 'Document properties',
       
   484 		cmd: 'mceFullPageProperties',
       
   485 		context: 'file'
       
   486 	});
       
   487 
       
   488 	editor.on('BeforeSetContent', setContent);
       
   489 	editor.on('GetContent', getContent);
       
   490 });