Recent Topics

1 May 03, 2007 22:29    

My b2evolution Version: 1.9.x

I put this in the skins forum because a few skins use dynamic text replacement, and it creates a bit of a problem.

So here's the deal: if you link the title of your post to something b2evolution is supposed to make the title to your post be a link to that site. Generally it does, but not if your skin uses dynamic text replacement. I currently use the basin skin, which uses DTR. I decided to take advantage of that trick to dynamically replace my post titles with an image using the Agent Orange font. Works fine, except for when you link something.

I don't have a link to my linkblog publicly available, but check out http://wonderwinds.com/linkblog.php and you'll see my linkblog. Problem is you won't see any titles linked to anywhere if you're using a browser with javascript automagically enabled. If you're using FF with the NoScript add-on and have not 'trusted' my site you'll see regular text for titles, but they won't be linked anywhere.

I don't understand the javascript enough to figure it out, so I'm asking in the hope the someone hip to javascript (or specifically DTR) will find a solution. I also have an idea to take advantage of the cache and replace the text server-side before delivering the page to the visitor. I believe that will cure this problem because of how the if ... else statement will work. Basically I'm thinking of something like this:

if( title is already converted to a cached image ) {
make the title with the image including linking it if appropriate
} else {
make the title the way it is normally made and allow DTR to convert it
}


I have made NO progress down this path, other than to think "this would be smarter".

So any help in either direction would be greatly appreciated.

EDIT: oddly enough, it works on the blog title as one would hope: the dynamically replaced text is linked back to where it belongs. Therefore it's gotta be something about how b2evolution makes post titles with links versus how it does it for blog links in the head section of the page.

2 May 03, 2007 23:45

The link <a> is nested within the header <h1>. The DTR replaces the <h1> and basically ignores any tag within. Can you try changing the link in a way the header is contained within, like <a href="bla bla"><h1>title</h1></a>. This would be a hack and I trust you more to that than I trust myself ;)

The cache thing is done in plain old php, look for _heading_main_title.php.

3 May 04, 2007 00:54

H2 actually, and I'm pretty sure the skin originally used H3 tags for post titles. The page header uses H1, but they work as expected because, as you noted the anchor tag is outside the span tag. Inside the H1 but outside the span that gets dynamically replaced. But yeah that's the correct place for me to be looking - getting the anchor out of the span.

So for anyone interested in using DTR on post titles here is a solution that seems to work. First find where your post titles are coming from. It'll look something like this:

<h2 class="bTitle"><span><?php $Item->title(); ?></span></h2>

Originally the basin skin did not have the span tag in that bit. You use spans to help DTR understand what it's supposed to replace. Anyway the thing to do is tell it "if there is a url in the post then make the title a special way, else do it like normal. This does that:

<?php if( $Item->url != '' ) { ?>
<h2 class="bTitle"><a href="<?php echo $Item->url; ?>" title="<?php echo $Item->url; ?>"><span><?php $Item->title( '', '', false ); ?></span></a></h2>
<?php } else { ?>
<h2 class="bTitle"><span><?php $Item->title(); ?></span></h2>
<?php } ?>

The secondary part of my mission, and not really a problem but still not quite right, is to replace the title with the image from the cache before the server delivers the page. In other words, to make the javascript do nothing for anyone other than the first person to see the post. So like currently it goes like this:

  • server makes a page and sends it to the browser. it has span tags for dtr.

  • browser, with javascript enabled, executes the javascript that calls the extra php file.

  • the extra php file looks in the cache for the right image, or makes a new one.

  • dtr replaces the text with the image.[/list:u]

  • That's kinda sloppy to me. Especially when I view my page in IE because it seems to take forever for the page to load. It's loading then reloading is why. So I'm thinking I should make the server ask if a cached image exists, and if so use it instead of sending span tags. If I do that then I'll be hurting those who don't allow images, so I would have to change the code above to echo $Item->title for the "title" attribute of the link, which is not how I like to title my links. Anyway it should be a total no-brainer to do it for blog titles because they rarely change. For my installation anyway, but it's best to plan on not remembering tomorrow what I hack up today. I'll therefore have to look at how the extra php file names the cached image and use the same technique to say "if you have a file called this then serve it as an image else use the span tagged text title". Or something like that. Never a dull moment eh? I'm gonna do a search cloud and be happy. Happier is what I mean, because I'm happy I got prodded in the right direction (thanks for that!) and found a solution. I'll be happier when I have a search cloud, and I'll be REALLY happy when I actually go search the bottom of a cloud on my own. I'll be wetting my pants with joy when I bring a camera on a flight and take pictures of clouds up close and personal. Oh and for those not into checking out the basin skin to find out what DTR is just go to http://www.stewartspeak.com/projects/dtr/ and be thrilled. (now I can finish up my gun porn post :D )

4 May 04, 2007 01:19

EdB wrote:

I'll therefore have to look at how the extra php file names the cached image and use the same technique to say "if you have a file called this then serve it as an image else use the span tagged text title". Or something like that.

$hash = md5(basename($font_file) . $font_size . $font_color .
            $background_color . $transparent_background . $text) ;
$cache_filename = $cache_folder . '/' . $hash . $extension ;


But this gets you nowhere because it basically takes all the steps to generate the image and then looks if it already exists. It starts with the JS part, you need it to trigger the change. It's designed that way.

Still, I do like the effect. I used it in a skin. Afterwards I found a method that was based on AJAX for triggering and communicating with code and generating a swf (flash) file containing the font. The latter was done on the fly after checking if a cache was available. See if I can find it.

Edit: found it. It's called [url=http://www.mikeindustries.com/sifr/]sIFR[/url]

5 May 14, 2007 00:57

Okay I got it. Actually hashing up the file name doesn't use the resources required to generate the image so it's cool. Assuming you enable the image cache (a parameter in _heading-main-title.php and chmod the cache directory) it'll make each image only once. Ever after it will hash up the name and see if it has that file, and if so use it.

So what I just did was to tell it the very first time it generates the page to look for the cached image and if it exists then make a plain old fashioned image tag. Basically that means the _heading-main-title.php file will get called only once for any give blog title. After that since the image exists _main.php will use the image tag.

Oh and this won't work if you have a space in your blog title. Since I don't I figured it's good enough for now. Eventually I'll figure out how to deal with spaces so I can apply the same trick to my post titles. Anyway here's how you do it, if you want this slight performance improvement. I started with the "basin" skin, but any skin using DTR to replace the blog title this should also work. Open skins/yourskin/_main.php and look for something like this:

<div class="pageHeader">
<h1 id="pageTitle"><a href="<?php bloginfo('url'); ?>"><span><?php $Blog->disp( 'name', 'htmlbody' ) ?></span></a></h1>
<div class="pageSubTitle"><?php $Blog->disp( 'tagline', 'htmlbody' ) ?></div>
</div>


It's the span tags that will trigger the DTR, so all you gotta do is find out if you have the image in cache, and if so use it without span tags. Like this:

<div class="pageHeader">
<?php // use the cached image for the blog title if it already exists
$text = $Blog->get('name');
if(get_magic_quotes_gpc()) {
	$text = stripslashes($text);
	}
$title_hash = md5('Raceway.TTF32#FF0000#0000001'.$text.' '); // the extra space after $text makes it work
$image_name = 'cache/'.$title_hash.'.png' ;
if( file_exists(dirname(__FILE__).'/'.$image_name) ) {
	$size = getimagesize( dirname(__FILE__).'/'.$image_name );
	$width = $size[0];
	$height = $size[1];
	 ?>
	<h1 id="pageTitle"><a href="<?php bloginfo('url'); ?>"><img src="<?php echo $image_name ?>" title="<?php echo $text ?>" alt="<?php echo $text ?>" width="<?php echo $width ?>" height="<?php echo $height ?>" /></a></h1>
	<?php } else { // make the title tag using span tags so DTR can do it's thing ?>
	<h1 id="pageTitle"><a href="<?php bloginfo('url'); ?>"><span><?php $Blog->disp( 'name', 'htmlbody' ) ?></span></a></h1>
	<?php } ?>
<div class="pageSubTitle"><?php $Blog->disp( 'tagline', 'htmlbody' ) ?></div>
</div>

Next step will be to figure out how to break a string of text into individual words, then check the cache for each word's image file, then put them all together in a line, with linking if it's a linked post title.

What fun!

6 May 14, 2007 10:20

EdB wrote:

Oh and this won't work if you have a space in your blog title. Since I don't I figured it's good enough for now. Eventually I'll figure out how to deal with spaces so I can apply the same trick to my post titles.

DTR breaks lines with spaces into words and generates an image for every single word. I have a seperate _heading-main-title.php that triggers on <h3> for the post titles. It works like a dream. But you got this far already.

What happens if you force an escape to generate the spaces in the headers? It will probably generate a space character before DTR does it's job, but if you manage to reverse that order, that will do.

Regarding this matter I posted a while ago about the build-in function to generate static html as output, replacing the more dynamically built php. The static html is something like a cache, with the everything prerendered. But this is manually done in B2e. That's a drawback. Probably something for a feature request: a completely automatically static output of the blog. Refreshed every xx minutes.

EdB wrote:

Okay I got it. Actually hashing up the file name doesn't use the resources required to generate the image so it's cool.

You found a way to bypass the start of the JS. Well done.

To save some time you should delete the part in DTR that checkes for the existing image. :)

7 May 14, 2007 10:40

I thought for sure you were gonna bust me on an error, or at least an explanation-required in my code :)

$title_hash = md5('Raceway.TTF32#FF0000#0000001'.$text.' '); // the extra space after $text makes it work


That line works, but it'll only work for me. Rather than define the variables that DTR uses then use them only once I plugged the values straight into the hasher. The original line looks like this:

$hash = md5(basename($font_file) . $font_size . $font_color . $background_color . $transparent_background . $text);


So all I did was took the values for those variables and made a text string out of them. If I change any of the variables in my DTR it'll change the file name it makes, and I'll have to change the same bit in this little hack. Oh and first I echoed all the variables the original hasher used to see what I would see. That's why "$transparent_background" is replaced with a "1" instead of a "true" even though in DTR the value is "true" without quotation marks.

Yeah the space thing shouldn't be too hard. Why DTR does it that way I dunno yet, but it does. Maybe so you can get line breaks in the middle of what would otherwise be a really long image file? That would also explain the need for the blank space at the end of the "rebuilt hash" above, perhaps. Anyway I sort of decided to not mess with the actual DTR files and see if I could pick the cached image before sending the page. So far it works, and I get both title and alt tags. Figuring out the space thing shouldn't be too hard. Gotta be doable with regular expression stuff, or maybe a function that splits strings into array elements based on matching a character? No time to look at php.net, but that thought just popped into my head. Something to look at after work I guess.

Kinda fun actually. DTR is neat, but when I noticed how long it sometimes takes to finish loading my page - and especially what happens in IE7 - I think getting this mission accomplished will be a great improvement.

8 May 14, 2007 11:41

EdB wrote:

I thought for sure you were gonna bust me on an error, or at least an explanation-required in my code :)

Just one thing: this works on the one occurance of the main title. If you want the many occurances of the post title, or more general, the <h3>tag (post title and side bar item title) you need to come with many occurances of the same code. And you need to insert the if else statement approximately above the tag it is affecting. This JS stuff does it all in one.
That's what I meant with triggering in a previous post.

How often do you plan to change the title of your blog? :>
I used it for my skin where blog owners need to generate the title for the first time (and probably for the first time only). But for posts it's a totally different matter.

9 May 14, 2007 12:17

For a laugh try this in your _main.php:-

<body>
<?php
ob_start();
?>
.....

</body>
<?php
$all_content = ob_get_clean();
$all_content = preg_replace_callback( '#<([\w]+?)([^>]+?)class="img_me"([^>]*?)>(.+?)</\1>#', 'check_images', $all_content );

echo $all_content;

function check_images( $matches )
{
	$matches[4] = callback_on_non_matching_blocks( $matches[4], '#<[^>]+?>#', 'the_string' );
	return '<'.$matches[1].$matches[2].'class="img_me"'.$matches[3].'>'.$matches[4].'</'.$matches[1].'>';
}

function the_string( $the_string )
{
	$font_file = 'foo';
	$font_size = 'bar';
	$font_color = 'yellow with red dots';
	$background_color = 'green';
	$transparent_background = true;
	$words = explode( ' ', $the_string );
	$foo = array();
	foreach( $words as $word )
	{
		$image_name = 'cache/'.md5(basename($font_file) . $font_size . $font_color . $background_color . $transparent_background . $word ).'.png';
		$foo[] = '<img src="'.( is_file( dirname(__FILE__).'/'.$image_name ) ? $image_name: 'heading.php?text='.$word).'" />';
	}
	return implode( ' ', $foo );
}
?>

Then anything you want text replacement for just add :

class="img_me"

¥

*edit*
code correction

10 May 14, 2007 16:01

Interesting Y. I *might* play with it but I dunno. Right now DTR does what I need almost, so I'm more inclined to just tweak it to be happier.

Afwas one instance of the code will do for the blog title, and one other instance will do for every post title. For me the hashed string will change because I use a different font and size and color (though I've never tried "yellow with red dots" as a color code), and I've got to deal with the space thing (which explode-space-text will do nicely so thanks Y), but after that it'll be just another thing the post loop will loop through. I'm thinking that'll be good enough.

ob_start is weird. I sort of think I once thought I basically understood what it does, but ... I dunno. It's too not normal is the thing.

OT: last night sucked. I wanna sell ice cream out of an ice cream truck on the beach. That'd be way cool.

11 May 15, 2007 01:13

¥åßßå I think I understand. As the page is generated it's not delivered because that's what ob_start does - it buffers the output. You then search the page for a specific class and use images from the cache (if they exist) for those words.

So the place to use the special class attribute would be, for example, the span tag that currently triggers the DTR javascript.

If the image is not found in the cache you won't need the javascript to make the images because the image tag will call the extra file that dynamically generates (and caches) the image.

So it'd be DTR without javascript. That'd be one step better than I am working on because getting rid of the script entirely is a good idea. To me. I'm thinking that the place I'm going will allow me to say "if is_logged_in() include the javascript", meaning no one other than me would have to trust my web with scripts.

Close?

12 May 15, 2007 09:59

That's pretty much it, although you could add the class to the parent <h3> as well as it'll only convert words. ( <h3 class="img_me"><a href="http://foo.bar" title="go visit foo's bar"><span>Foo</span></a></h3> )

If you wanted to be extra clever you could tweak it so that you could pass the font face|colour|size etc as part of the style ( you'd also need to amend heading.php so that it gets the values as well ). In which case you'd have one script that does all.

¥

13 May 15, 2007 11:21

Yeah so the span tags won't be needed because that's what gets the javascript going. I think. Anyway the whole idea of using a javascript goes out the window if I do it with ob_start.

And the "one function to handle it all" is what I would need because I'm using 2 extra php files for blog title and post titles.

I'm going to put good effort into making this work. If it can do multiple fonts & sizes & such it'll be quite the treat.

14 May 15, 2007 12:18

Ok, try this :-

_main.php

function check_images( $matches )
{
	global $font_face, $font_size, $font_color, $background_color;
	// set defaults for styles
	$font_face = 'foo';
	$font_size = 'bar';
	$font_color = 'yellow with red dots';
	$background_color = 'green';

	preg_match( '#style=("|\')([^\1]+?)\1#', $matches[2].' '.$matches[3], $styles );
	if( !empty( $styles[2] ) )
	{
		preg_replace_callback( '#(font-[^:]+?|color|background-color):([^;]+?);#', 'get_stuff', $styles[2] );
	}

    $matches[4] = callback_on_non_matching_blocks( $matches[4], '#<[^>]+?>#', 'the_string' );
    return '<'.$matches[1].$matches[2].'class="img_me"'.$matches[3].'>'.$matches[4].'</'.$matches[1].'>';
}

function the_string( $the_string )
{
	global $font_face, $font_size, $font_color, $background_color;
    $transparent_background = true;
    $words = explode( ' ', $the_string );
    $foo = array();
    foreach( $words as $word )
    {
        $image_name = 'cache/'.md5(basename($font_face) . $font_face . $font_color . $background_color . $transparent_background . $word ).'.png';
        $foo[] = '<img src="'.(
        		is_file( dirname(__FILE__).'/'.$image_name ) ?
        				$image_name :
        				'heading.php?text='.$word.'&amp;font_face='.$font_face.'&amp;font_size='.$font_size.'&amp;color='.$font_color.'&amp;background_color='.$background_color
        				).'" />';
    }
    return implode( ' ', $foo );
}

function get_stuff( $stuff )
{
	//pre_dump( $stuff );
	global $font_face, $font_size, $font_color, $background_color;
	switch( $stuff[1] )
	{
		case 'color' :
			$font_color = $stuff[2];
			break;

		case 'background-color' :
			$background_color = $stuff[2];
			break;

		case 'font-face' :
			$font_face = substr( $stuff[2], 0, strpos( $stuff[2], ',' ) );
			break;

		case 'font-size' :
			$font_size = $stuff[2];
			break;
	}
}
?>

heading.php

<?php
/*
    Dynamic Heading Generator
    By Stewart Rosenberger
    http://www.stewartspeak.com/headings/    

    This script generates PNG images of text, written in
    the font/size that you specify. These PNG images are passed
    back to the browser. Optionally, they can be cached for later use. 
    If a cached image is found, a new image will not be generated,
    and the existing copy will be sent to the browser.

    Additional documentation on PHP's image handling capabilities can
    be found at http://www.php.net/image/    
*/


$font_file  = $_GET['font_face'].'.ttf' ;
$font_size  = settype( $_GET[ 'font_size'], 'integer' );
$font_color = $_GET['font_color'];
$background_color = $_GET[ 'background_color' ];

Usage :-

<h4 style="font-face:font_file, serif;font-size:100px;color:#0f0;background-color:#00f;" class="img_me">hello world</h4>

*note* All your styles must end with a ; so the regex can trap them, also after your font file you need to add one of the w3c standard ones otherwise you won't validate ;)

¥


Form is loading...