Jump to content

undesirable: two typed spaces become space+ 


darrenc
 Share

Recommended Posts

Hi I don't exactly know how to approach this issue. I don't love how tinymce seems to input a space and an   when a user types two consecutive spaces into the editor of, for example, the body field (textarea). I'm not exactly sure where the translation from two spaces to "  " happens, but since I've noticed that wordpress does a similar thing I assume it is tinyMCE that is the culprit.

Doing some googling for tinyMCE and this issue is somewhat of a mess. I was wondering if perhaps it would be better solved in a processwire module, filter, hook, or something else.

Ultimately the goal would be to simply keep them as actual plain spaces, or to remove the double spaces after periods and before additional text. 

I'd appreciate some thoughts on the matter. I should probably do a bit of due dilligance myself and see whether it gets stored in the db or whether the transition happens when processwire outputs the data.

Link to comment
Share on other sites

The problem is that double spaces in html are meaningless - they are ignored completely. With good reason too - if whitespace in html code had meaning, you couldn't indent elements without impacting on the end result.

Explanation here: http://stackoverflow.com/questions/433493/why-do-multiple-spaces-in-an-html-file-show-up-as-single-spaces-in-the-browser

Why do you need to keep double spaces (without conversion to the html entity)?

--EDIT--

Untested, but try something like this:

<?php

/**
 * If it works, Copyright Tiago Roldao
 * If it doesn't, I have no idea who made this 
 */

class NonBreakingSpaceRemover extends Textformatter { 

	public static function getModuleInfo() { 
		return array( 
			'title' => 'Non Breaking Space Remover', 
			'version' => 100, 
			'summary' => "Converts html non breaking spaces back to normal spaces. ", 
		); 
	} 

	public function format(&$str) { 
		$str = trim($str); if(!strlen($str)) return; 
		$str = $value.preg_replace('/ /', ' '); 
	} 
}

Install it as a module, try it out, change it if it doesn't work. Again, completely untested, but a simple variant of the Newlines to List Textformatter, so it should work fine  :rolleyes:

  • Like 1
Link to comment
Share on other sites

Why do you need to keep double spaces

I don't want to keep double spaces. When writing content, people tend to put two spaces after a period. Something makes the assumption that they indeed want to keep the double (or more) spaces and thus converts them ones into a   in order to maintain that spacing. and when that happens it affects how the text wraps http://i.imgur.com/yWC91eH.png (lines 4&6). instead of a plain space that would normally be ignored, the browser forces the   and indents the line.

I wouldn't say that I am losing sleep over the issue, but it would be nice if I had some control over this at the field-level in order to prevent this kind of potential whitespace mangling (maybe a client puts 5 spaces after every period, cringe).

I'll try your code out tomorrow morning to see if it works. I checked the database and the entities are not being stored as  . Perhaps they are being stored as a separate type of whitespace character that gets converted later?

Either way i'll be sure to report back. Thanks!

Link to comment
Share on other sites

Maybe just a php line like

$content = str_replace(" ", "", $content);

in the template file before outputting the db content would do the trick here?

EDIT: => But it is obviously a cleaner approach to filter the content before writing it to the db...

Link to comment
Share on other sites

Okay, after checking the database it seems that the spaces get stored as u+0020 (a normal space) and u+00A0 (a non-breaking space character), as a repeating sequence as necessary depending on the number of spaces pressed. Here is sublime text revealing the nbsp character http://i.imgur.com/76S7cwT.png

tiagoroldao, your code definitely didn't work (and in very interesting ways that i don't yet understand). However, after some looking at wire/modules/textformatter, I do understand where you were coming from. Clearly these modules are what I'm looking for as a base for my own. I'll try to figure something out based on what I know now.

Joe, that's not a bad idea either actually and I hadn't thought of that. Thank you for the suggestion.

Still working on it...

Link to comment
Share on other sites

class TextformatterNBSPstripper extends Textformatter {

	public static function getModuleInfo() {
		return array(
			'title' => 'Unicode nbsp Stripper', 
			'version' => 100, 
			'summary' => "Replaces the Unicode non-breaking space character with a regular space. This prevents browser rendering of multiple consecutive spaces within text content.", 
		); 
	}

	public function format(&$str) {
		if( !preg_match('/\x{00A0}/u', $str) ) return;
		$str = trim( preg_replace('/\x{00A0}/u', " ", $str) ); 
	}
}

The above is the module I made. Obviously very basic but this is all new to me so hopefully I did it right. Happy to hear any pointers. I think I'll give it some testing and then submit a module addition on the off chance anyone else wants something similar.

  • Like 1
Link to comment
Share on other sites

It would be ideal if there were some TinyMCE setting that could be used to disable this behavior. I'm guessing that there must be, but I don't know what it is. Beyond that, I think your solution is just fine. Though it looks to me like you could use a strpos rather than a preg_match, and a str_replace rather than a preg_replace here, as you are just matching a character rather than a pattern. Regular expression functions like the preg_* functions should generally be avoided unless you need to match a pattern. That's because they are relatively slow. Though it's unlikely there would be any perceptible difference by switching it.

If you wanted to fix the value before it is stored in the DB, another strategy you could take would be to hook into InputfieldTinyMCE::processInput and fix the value right after processing occurs. 

/site/templates/admin.php

<?php
wire()->addHookAfter('InputfieldTinyMCE::processInput', null, 'hookFixNBSP');
function hookFixNBSP($event) {
  $value = $event->object->value; 
  if( !preg_match('/\x{00A0}/u', $value) ) return;  $value = trim( preg_replace('/\x{00A0}/u', " ", $value) );
  $event->object->value = $value; 
}
Link to comment
Share on other sites

Ryan/Pete thanks for following up.

Seeing the hook solution is interesting. When looking into the issue I also ran across the room34.com solution. 

In the end I think it was better served by making a module due to the nice benefits it affords in the admin: mainly, being able to apply it on a field-by-field basis as desired.

Link to comment
Share on other sites

  • 2 months later...

I also wanted a solution on a site that kinda has this issue with lots of these, instead I created a hook on what Ryan mentions.

Also I changed it to replace only those preceded with a whitspace, so those that actually make sense between two words intact.

https://gist.github.com/10330802

<?php

/**
 * TinyMCE replace nbsp with regular whitespace
 *
 * Only nbsp preceeded with a whitespace will get replaced, this leaves
 * single non breaking space only bewtween words
 *
 * ProcessWire 2.x
 * Copyright (C) 2012 by Ryan Cramer
 * Licensed under GNU/GPL v2, see LICENSE.TXT
 *
 * http://www.processwire.com
 * http://www.ryancramer.com
 *
 */

class TextareaStripNbsp extends WireData implements Module{

    public static function getModuleInfo() {
        return array(
            'title' => 'Unicode   (x00a0) Stripper',
            'version' => 100,
            'summary' => "Replaces the Unicode non-breaking space character /\s\x{00a0}/u with a regular space for all InputfieldTinyMCE when saving.",
            'autoload' => true
        );
    }

    public function init(){
        $this->addHookAfter('InputfieldTinyMCE::processInput', $this, 'hookFixNBSP');
    }

    public function hookFixNBSP(HookEvent $event){
        $value = $event->object->value;
        // replace only nbsp with a preceeding space
        // this ensures nbsp to not wrap words still works
        $value = trim( preg_replace('/\s\x{00a0}/siu', " ", $value) );
        $event->object->value = $value;
    }
}
  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...