Jump to content
darrenc

undesirable: two typed spaces become space+ 

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.

Share this post


Link to post
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

Share this post


Link to post
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!

Share this post


Link to post
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...

Share this post


Link to post
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...

Share this post


Link to post
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

Share this post


Link to post
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; 
}

Share this post


Link to post
Share on other sites

As of February last year there was this workaround in TinyMCE itself: http://blog.room34.com/archives/5075

But since that would get removed every time the core TinyMCE is upgraded in ProcessWire then the solutions in the two previous posts would be preferable as they will stay forever.

Share this post


Link to post
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.

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Moritz Both
      Greetings,
      when I give users the user-admin-* permission to administer users who have a certain role, they can indeed see and edit those users. However the filter / column panel does not show in the admin interface. How can I enable the filter functionality for user-admin-* members?
      ProcessWire 3.0.123
      Moritz
    • By DooM
      Hello,
      I'm working on something like "structure generator" for my own needs which is run after clean installation of PW to create basic structure, fields, install modules, remove unnecessities, etc.
      I'm trying to remove site/templates/scripts and site/templates/styles folders, but I'm out of ideas already. When I try PHP's unlink function, it says that the path doesn't exists, which is obvious, because it will try to delete those folders under FileCompiler folder. This is probably because PW compilation process? I'm initializing this mine "structure generator" in ready.php.
      Do any of you guys have any idea how to get rid of those folders? My styles and scripts folders are separated, so I don't need those two inside templates folder.
      Thanks for every advice. 🙂
    • By Robin S
      Remove Blocks
      A textformatter module for ProcessWire that removes blocks of text/markup between configurable delimiters from output. This allows you to "comment out" blocks of text/markup so they remain present in the field but are not shown in the front-end output.
      This can be handy if content needs to be removed temporarily and will later be reinstated. Or you could use a commented block as a placeholder to indicate to an editor where some content should be added.
      Installation
      Install the Remove Blocks module.
      Configure the open and close delimiters if needed. The default open delimiter is {{ and the default close delimiter is }}. Tip: don't use delimiter characters that CKEditor will encode to HTML entities, e.g. >.
      Usage
      Add the Remove Blocks textformatter to one or more fields.
      Add the open and close delimiters around any content that you want to be removed from output.

       
      https://github.com/Toutouwai/TextformatterRemoveBlocks
      http://modules.processwire.com/modules/textformatter-remove-blocks/
    • By j00st
      Hi all,

      I've set up a filter on my product-page, which I then use to...filter my products!
      – I've got pagination set up, and 30 items per page.
      – When I active the filter it works perfectly (in my opinion).
       
      Here's what I'm struggling with though:
      When I'm on another page (filtered as well/or the total overview) and I put my GET request in for the filter,
      it gives back the result, but still with the page-number there. In some cases, this is no problem – like a A-Z or Z-A filter,
      but others (say, per location) I might have less pages.
      Visual/code ref: (I DO have 3 pages of authors, but I don't have 3 pages from London)
      url: books/page3?author=ascending url: books/page3?studio=london  
      The current setup for my pages that get rendered are as follows:
      $allbooks = $pages->find("template=book, sort=$sort, $q, $tagged, $select_studio, start=0, limit=$limit"); As you can see I have the start=0 in there, but I read that's for the start of the pagination, not so much where it'll drop me in the search results.
      $q, $tagged and $select_studio are all empty values, unless they're returned from the GET request
      To repeat it, in it's most simplest form:
      When I click a filter, and a GET request is done, I want to 'reset' the page-number to 0, and get my results...
      Perhaps I'm missing something obvious, but I'd be really grateful to have your input.
    • By Vigilante
      This is a pretty typical thing. Open a page, it does a $pages query, finds 112 things and I list them on the page. There is pagination too, 20 per page.
      I want a sort dropdown box so the visitor can change alpha sort or whatever other sorts and filters I eventually use.
      My first thought is to just refresh the page with a url query like "page/?sort=az" and then adjust the query in the template code. But to do this, it will require a page refresh, which means the sort box goes back to its default, and not sure how it effects pagination.
      If I do a page refresh, I'll have to keep the sort settings in the session or something, to make sure I always apply correct sort on page load.
      But at the same time, I've already got the $pages array, it would be much nicer to shuffle it and update the page without a page refresh, rather than run the query over and over again.
      But then again, the pagination buttons already cause page refreshes, so that is already happening anyway, unless I convert the pagination buttons to also be no-refresh somehow.
       
      I figure this is a very common problem, to paginate results and give users a sorting/filtering option. What is the common methods for handling it? Session, url query, ajax? If I just add the sort to the url query, how do I make that work in the pagination links?
×
×
  • Create New...