Fixes alterations of newlines inside a call to the WYSIWYG plugin.
Far from clean, this even modifies a built-tin CKEditor plugin (divarea). Changes to ParserLib's parse_data_process_maketoc() are partly done by r62950, in Tiki 18.
Without this, changing nothing in "{WYSIWYG()}\n\n\n2 empty lines before, 0 after.\n{WYSIWYG}" would still cause it to become "{WYSIWYG()}\n\n2 empty lines before, 0 after.\n\n{WYSIWYG}", so 1 line missing before, 1 extra after.
Index: MERN/lib/ckeditor_tiki/tiki-ckeditor.js
===================================================================
--- MERN.orig/lib/ckeditor_tiki/tiki-ckeditor.js
+++ MERN/lib/ckeditor_tiki/tiki-ckeditor.js
@@ -238,7 +238,13 @@ $.fn.wysiwygPlugin = function (execution
 
 											var data = editor.getData();
 											data = data.replace(/<\/p>\n\n<p/g, "</p>\n<p");	// remove cke4 extra linefeeds
-											data = data.replace(/\n\n\s*?$/m, "\n");
+											/* 
+											r55910 by Jonny Bradley replaced the first line with the second.
+											He does not know if the new line is a new version of the old line, or if these are 2 separate changes.
+											Second line commented as it appears to be a workaround, compensated by changes to parserlib.php. Chealer 2018-03-14 */
+											// data = data.replace(/<\/p>\n$/g, "</p>");
+											//data = data.replace(/\n\n\s*?$/m, "\n");
+											
 											var height, params = {};
 											if (editor.plugins.divarea) {
 												height = editor.ui.space("contents").getClientRect().height;
Index: MERN/lib/parser/parserlib.php
===================================================================
--- MERN.orig/lib/parser/parserlib.php
+++ MERN/lib/parser/parserlib.php
@@ -2326,7 +2326,7 @@ if ( \$('#$id') ) {
 		$in_paragraph = 0;
 		$in_empty_paragraph = 0;
 
-		foreach ($lines as $line) {
+		foreach ($lines as $lineIndex => $line) {
 			$current_title_num = '';
 			$numbering_remove = 0;
 
@@ -2748,6 +2748,10 @@ if ( \$('#$id') ) {
 									if ($in_paragraph && ((empty($tline) && !$in_empty_paragraph) || $contains_block)) {
 										// If still in paragraph, on meeting first blank line or end of div or start of div created by plugins; close a paragraph
 										$this->close_blocks($data, $in_paragraph, $listbeg, $divdepth, 1, 0, 0);
+										
+										if ($add_brs) {
+											$data .= '<br>';
+										}
 									} elseif (!$in_paragraph && !$contains_block && !$contains_br && (!empty($tline) || $add_brs)) {
 										// If not in paragraph, first non-blank line; start a paragraph; if not start of div created by plugins
 										$data .= "<p>";
@@ -2765,13 +2769,20 @@ if ( \$('#$id') ) {
 									  // }
 								}
 							} else {
-								$line .= "<br />";
+								// Add newlines between lines
+								if ($lineIndex + 1 < count($lines)) {// Exclude the first line
+									$line .= "<br />";
+								}
 							}
 						}
 					}
 				}
 			}
-			$data .= $line . "\n";
+			// Add newlines between lines
+			if ($lineIndex + 1 < count($lines)) {// Exclude the first line
+				$line .= "\n";
+			}
+			$data .= $line;
 		}
 
 		if ($this->option['is_html']) {
Index: MERN/vendor/ckeditor/ckeditor/plugins/divarea/plugin.js
===================================================================
--- MERN.orig/vendor/ckeditor/ckeditor/plugins/divarea/plugin.js
+++ MERN/vendor/ckeditor/ckeditor/plugins/divarea/plugin.js
@@ -31,7 +31,17 @@ CKEDITOR.plugins.add( 'divarea', {
 					};
 				} );
 
-			editor.setData( editor.getData( 1 ), callback );
+			// Set the editor's contents to its contents... some unfortunately needed hack to populate contents
+			var currentData = editor.getData( 1 ); // If 0, the hack has no effect; if 1, contents are properly populated.
+			// Hack the hack; call setData() without (indirectly) calling toHtml() (toHtmlFormat()), otherwise the contents are parsed for a second time by an AJAX call to edit's tohtml action. data is already parsed at this point. A second parse alters formatting, typically adding or removing newlines.
+			{
+				var saveToHtml = editor.dataProcessor.toHtml; // Save handler
+				editor.dataProcessor.toHtml = function (data) {return data;}; // Set a dummy handler
+				
+				editor.setData( currentData , callback );
+				editor.dataProcessor.toHtml = saveToHtml; // Restore handler
+			}
+			
 			editor.fire( 'contentDom' );
 		} );
 	}
Index: MERN/lib/ckeditor_tiki/plugins/tikiwiki/plugin.js
===================================================================
--- MERN.orig/lib/ckeditor_tiki/plugins/tikiwiki/plugin.js
+++ MERN/lib/ckeditor_tiki/plugins/tikiwiki/plugin.js
@@ -24,7 +24,10 @@ CKEDITOR.plugins.add('tikiwiki',{
 
 		var oldToDataFormat = editor.dataProcessor.toDataFormat ;
 		editor.dataProcessor.toDataFormat 	= function ( html, fixForBody ) {
-			return twplugin.toWikiFormat( editor, oldToDataFormat.call( editor.dataProcessor, html, fixForBody ) ); };
+			// return twplugin.toWikiFormat( editor, oldToDataFormat.call( editor.dataProcessor, html, fixForBody ) )
+			// Don't fire toDataFormat event handlers, which convert to DOM then back to HTML altering the HTML in the process, to preserve whitespace.
+			return twplugin.toWikiFormat( editor, html )
+			};
 		editor.dataProcessor.toHtml			= function ( data, fixForBody ) { return twplugin.toHtmlFormat( editor, data ); };
 
 		// data in the clipboard is html, the input format is expected to be wiki
