Feature request: 'csssafe' CSS Safe keyword modifier


(Evan Wills) #1

Hi there
(I'm posting this here because I can't find a better place to put it.)



I'm building the designs for a new site (10,000+ pages) and I had an idea to minimize the number of design customizations.



I'm using the "asset_lineage" design area along with a couple of keyword modifiers to make the asset's lineage form CSS classes which allow me to control colours, backgound images etc. in various parts of the site. It's also a technique I've used for newsletters with standard stories with some success. Unfortunately the 'replace' keyword modifier is very broken so I can't use it to clean up the %asset_name%s adequately. What I'd like is a keyword modifier that makes a matrix keyword safe to use as an ID or class name.



Below are two versions of a PHP function that would do the required sanitizing of the keyword making it safe to use as a class or ID name. The first allows you to specify whether the separator character is a hyphen or an underscore and what the prefix will be for strings that start with a number.


    
    /**
     * @function css_safe() takes a string and makes it safe to use as an
     * HTML class or ID.
     *
     * css_safe() is intended to be used as a matrix keyword modifyer to
     * allow use of matrix keywors (e.g. %asset_name%) as an HTML class
     * or ID, which in turn can be used as a CSS selector.
     *
     * EXAMPLE:	%asset_name^csssafe%
     * EFFECT:	'9 good uses for Regular Expressions' > 'A_9_good_uses_for_Regular_Expressions'
     * EXAMPLE:	%asset_name^csssafe:ID%
     * EFFECT:	'9 good uses for Regular Expressions' > 'ID_9_good_uses_for_Regular_Expressions'
     * EXAMPLE:	%asset_name^csssafe:ClasS%
     * EFFECT:	'9 good uses for Regular Expressions' > 'ClasS_9_good_uses_for_Regular_Expressions'
     *
     * EXAMPLE:	%asset_name^csssafe%
     * EFFECT:	'John Smith speeks: "Life is good!"' > 'What_can_go_wrong_saying_too_much'
     * EXAMPLE:	%asset_name^csssafe::-%
     * EFFECT:	'John Smith speeks: "Life is good!"' > 'What-can-go-wrong-saying-too-much'
     *
     * EXAMPLE:	%asset_name^csssafe%
     * EFFECT:	'John Smith speeks: "Life is good!"' > 'John_Smith_speeks_Life_is_good'
     *
     * EXAMPLE:	%asset_name^csssafe%
     * EFFECT:	'Bighting the hand that feeds you - don't let'm get too hungry' > 'Bighting_the_hand_that_feeds_you_don_t_let_m_get_too_hungry'
     *
     * @param string $input text (from matrix keyword) to be made safe
     *		 for use as an HTML class or ID
     * @param string $prefix an alphabetical character (or characters) to
     *		 prefix strings that start with numbers so they are
     *		 valid HTML class or ID names
     * @param string $separator underscore or hyphen use to replace
     *		 single (and multiple consecutive) non alpha-numeric
     *		 characters within the input text
     *
     * @return string text suitable for use as an HTML class or ID name
     */
    function css_safe( $input , $prefix = 'A' , $separator = '_' )
    {
    	// ensure separator character is valid
    	if( $separator != '-' ) $separator = '_';
    	
    	// ensure prefix character is valid
    	if( !preg_match( '/^[a-z]+$/i' , $prefix ) ) $prefix = 'A';
    
    	// Find all the bad characters
    	$find = array(
    		'/(?:^[^a-zA-Z0-9]+|[^_a-zA-Z0-9-]+$)/' // find bad characters from begining and end of string
    							// (Note: in this version, strings cannot start with a 
    							// hyphen or underscores ('-', '_') as these are generally
    							// reserved for browser specific selectors)
    		,'/^(?=[0-9])/'	// find numbers at the start of the string
    		,'/[^_a-zA-Z0-9-]+/' // find all bad characters within string
    		,'/[_-]{3}/' // cleaning up
    	);
    
    	// Replace all the bad characters
    	$replace = array(
    		'' // strip bad characters from begining and end of string
    		,$prefix.$separator.'\1' // add underscore to strings starting with a number
    		,$separator // replace multiple bad chars with a single underscore (or separator char)
    		,$separator // cleaned up
    	);
    
    	return preg_replace( $find , $replace , $input );
    }
    
    
    /**
     * @function css_safe_simple() takes a string and makes it safe to
     * use as an HTML class or ID.
     *
     * css_safe_simple() works in an identical way to css_safe() but
     * without the ability to control the prefix character(s) or
     * separator character.
     *
     * EXAMPLE:	%asset_name^csssafe%
     * EFFECT:	'5 ways to skin a cat' > 'A_5_ways_to_skin_a_cat'
     *
     * EXAMPLE:	%asset_name^csssafe%
     * EFFECT:	'John Smith speeks: "Life is good!"' > 'John_Smith_speeks_Life_is_good'
     *
     * EXAMPLE:	%asset_name^csssafe%
     * EFFECT:	'Bighting the hand that feeds you - don't let'm get too hungry' > 'Bighting_the_hand_that_feeds_you_don_t_let_m_get_too_hungry'
     *
     * @param string $input text (from matrix keyword) to be made safe
     *		 for use as an HTML class or ID
     *
     * @return string text suitable for use as an HTML class or ID name
     */
    function css_safe_simple( $input )
    {
    	// Find all the bad characters
    	$find = array(
    		'/(?:^[^a-zA-Z0-9]+|[^_a-zA-Z0-9-]+$)/' // find bad characters from begining and end of string
    							// (Note: in this version, strings cannot start with a 
    							// hyphen or underscores ('-', '_') as these are generally
    							// reserved for browser specific selectors)
    		,'/^(?=[0-9])/'	// find numbers at the start of the string
    		,'/[^_a-zA-Z0-9-]+/' // find all bad characters within string
    		,'/[_-]{3}/' // cleaning up
    	);
    
    	// Replace all the bad characters
    	$replace = array(
    		'' // strip bad characters from begining and end of string
    		,'A_' // add underscore to strings starting with a number
    		,'_' // replace multiple bad chars with a single underscore (or separator char)
    		,'_' // cleaned up
    	);
    
    	return preg_replace( $find , $replace , $input );
    }

(Stuart W) #2

Hi there,


I’m afraid I’m not experienced enough to comment on the code in your post, but you can submit feature requests at http://bugs.matrix.squiz.net/ - your idea would get fully evaluated and considered there.



Cheers

Stu


(Nic Hubbard) #3

[quote]
I’m afraid I’m not experienced enough to comment on the code in your post, but you can submit feature requests at http://bugs.matrix.squiz.net/ - your idea would get fully evaluated and considered there.

[/quote]



Yep, this will guarantee that the devs take a look at the feature request and the code. :slight_smile:


(Charlotte Westney) #4

Hi Evan,


Have you tried another forms of keyword modifiers, and what effects have you got?

Just thinking that there are a few that might clean up the asset name enough to use as a css class. Like ^lowercase and ^underscore and ^trim that you could use in combination;



%asset_name^trim^lowercase^underscore% EG: [This is my asset name ] > [this_is_my_asset_name]



%asset_name^trim^lowercase^underscore^replace:_:-% EG: [This is my asset name ] > [this-is-my-asset-name]



But I like the idea for that keyword modifier, so you should definetly submit it!



Charlie.


(Evan Wills) #5

[quote]
Hi Evan,



Have you tried another forms of keyword modifiers, and what effects have you got?

Just thinking that there are a few that might clean up the asset name enough to use as a css class. Like ^lowercase and ^underscore and ^trim that you could use in combination;



%asset_name^trim^lowercase^underscore% EG: [This is my asset name ] > [this_is_my_asset_name]



%asset_name^trim^lowercase^underscore^replace:_:-% EG: [This is my asset name ] > [this-is-my-asset-name]



But I like the idea for that keyword modifier, so you should definetly submit it!



Charlie.

[/quote]

Hi Charlie



Yeah I have tried the modifiers you suggested (and currently use them until I something like I've suggested is implemented) and they work fine until your string has a non alpha numeric character



%asset_name^trim^lowercase^underscore% EG: [apples, oranges & pairs ] = [apples,oranges&pairs] - commas and ampersands or any other non alpha numeric characters are not legal in CSS class or ID names)



%asset_name^trim^lowercase^underscore% EG: [5km from home] > [5km_from_home] - this looks OK but as a CSS class or ID it's illegal because classes and IDs cannot start with a number)



I've also tried using the ^replace modifier but this seems to have some bugs when using a regex (otherwise this would be the answer)

%asset_name^trim^lowercase^underscore^replace:[^a-zA-Z0-9
-]:% EG: [don't like this one] > [apples,oranges&_pairs] - for some reason when I've tried replace with a regex it just renders all the keywords in the asset with the same string.

When I encountered the problem, I couldn't work out where to post the bug report for it. Now I know the bug URL I can file a bug for it. (could also be that we're running an old version of matrix)


(Nic Hubbard) #6

Couldn't you just use the asset ID instead of trying to use the page name? Just have a letter before it to make it a legal class…


(Evan Wills) #7

[quote]
Couldn't you just use the asset ID instead of trying to use the page name? Just have a letter before it to make it a legal class…

[/quote]

Hi Nic



I started with the asset ID that and it worked fine until I created a newsletter with regular stories (i.e. same story name across all issues). The regular stories needed css defined background images that were consistent across all issues. In this case, using an asset ID is impractical because the asset ID changes with every issue but the story name stays the same. Currently I have a work around, using special metadata field for the class, but it's an extra step for the editors, some of whom struggle with using the WYSIWYG let alone applying custom metadata to a particular story to make it look right.



Also while asset IDs are simple to implement they don't make for easy, long term management of CSS. In the CSS file, they just look like random numbers rather that understandable style selectors.


(Lyndon) #8

Did this ever get implemented?


(Nic Hubbard) #9
Also while asset IDs are simple to implement they don't make for easy, long term management of CSS. In the CSS file, they just look like random numbers rather that understandable style selectors.

 

Did you ever post this to the Matrix bugs site?


(Evan Wills) #10

Lyndon & Nick Hubbard

 

I'm very excited. Yes!!! This got implemented in 4.15.0 (see http://bugs.matrix.squiz.net/view_bug.php?bug_id=5886 & http://manuals.matrix.squizsuite.net/keyword-replacements/chapters/keyword-modifiers). We only upgrade a week ago so I haven't had a chance to play with it. But at the squiz conference in Canberra I heard others are using it with good results.


(Evan Wills) #11

I've finally had a chance to implement ^css_safe in our parse file and it works a treat. We use the asset_lineage design area to add classes to the body tag. So now any page with a non alpha numeric character in the page name translates nicely to a class name. Even if the page name starts with a number.