Chapter Three LLC

Drupal HOWTOs

HOWTO: Utilize Drupal 6-style "preprocess" theme architecture in Drupal 5

Josh Koenig

Once of the biggest advances “under the hood” in Drupal 6 is the addition of the preprocess architecture to the theme layer. This is part and parcel with the deeper embedding of template files, and together they render Drupal 6 the most flexible and powerful release yet in terms of theme and design.

For those of us who still do a fair amount of work with the 5.x branch, it’s easy to be envious of those lucky enough to have these new tools at their disposal. But resist that cardinal sin! This quick HOWTO explains how to quickly turn your theme into a node-preprocessing machine, which has great benefits in terms of elegant architecture, and also future-proofing your work for the eventual Drupal 6.0 migration.

Bulding off _phptemplate_vars()

Possibly the most powerful programmatic tool in the Drupal themer’s toolkit in 5.0 is the _phptemplate_vars() function. We’ve talked before about to use this to use different template files under different circumstances. Overall, this function is a great way to make all those minor changes that are needed so that a site can have truly top-notch appearance and user-interface.

However, once your theme gets to be very complex, this function can easily become an overloaded beast of logical branches. Each new node type or special case creating new complexity, and maintaining that as your site grows can quickly become untenable.

Fear not, though. You can also use this function to implement a simple preprocessing architecture that will help you customize the data in all your node types without creating a mass of template files, and set the table for 6.0. Here’s how:

<?php
function _phptemplate_variables($hook, $vars = array()) {
  switch (
$hook) {
    case
'node':
     
$node = $vars['node']; // handy shorthand
     
$preprocess = 'phptemplate_'. $node->type .'_node_vars';
      if (
function_exists($preprocess)) {
       
call_user_func($preprocess, $vars);
      }
      break;
    case
'page':
    

 
}
}

function
phptemplate_blog_node_vars(&$vars) {
 
// your custom preprocessing here
 
$node = $vars['node']; // handy shorthand
 
drupal_add_css($vars['directory']. '/custom_blog_style.css'); 
 
$vars['submitted'] = t('Blogged by !name on !date', array('!name' => l($node->name, 'user/'. $node->uid), '!date' => format_date($node->created, 'custom', 'm-d-Y')));
}
?>

Note that you don’t need to use phptemplate_ as the prefix here; indeed it may be advisable to use your theme_name.

What this function does is quickly check for the existence of a node-specific preprocessing function, and if it exists passes through the $vars array by reference.

In this case we detect that a blog node is being rendered, and take the opportunity to include a final custom stylesheet form our theme, as well as altering the standard $submitted var.

The possibilities here are endless, and in “enterprise theming” situations where you may be dealing with upwards of 25 (or even 100!) node types, having this kind of programatic structure in your theme is invaluable for keeping things clean, elegant and extensible.

Good luck, and happy drupal theming!

HOWTO: Upgrade an SVN Managed Drupal Installation (without CVS)

Matt Cheney

At Chapter Three we use the Subversion Version Control System to manage our client and internal Drupal projects. When we kick off a new project we roll out the latest version of Drupal, stick it in the SVN repository, and start developing.

As a matter of best practices it is usually a good idea to check Drupal directly out of the Drupal CVS repository which makes upgrading as simple as "cvs update -dP -r DRUPAL-5--X". However, we have a number of sites that were not checked out in this way and this makes updating Drupal sort of a pain. Our SVN management system wants us to update each file individually (so the changes can be versioned), but individually updating each of Drupal core's 300+ files is a little bit tedious.

However, with a little command line wizardry we can quickly download a copy of Drupal and generate a command to copy the new version of each Drupal core file on top of our installation in a way that can be committed up to SVN. To do this we need to wget a copy of Drupal and then use the all powerful find command to detect and copy the relevant files.

# Download a Copy of Drupal, Extract it, and Enter its Directory
wget http://ftp.drupal.org/files/projects/drupal-5.9.tar.gz
gzip -d drupal-5.9.tar.gz
tar xf drupal-5.9.tar
cd drupal-5.9

# Use Find to Detect Each Local File in Drupal Core and Execute a
# Command to Copy the File to the Live Version of the Website
find * -type f -exec echo cp {} /path/to/www/{} \;   # this just echos the  commands
find * -type f -exec cp {} /path/to/www/{} \;  # this actually runs the commands

To make sure the copy worked we can use the same find command do an individual diff on each file. This will assure us that we successfully updated our website with the version of code we downloaded from Drupal. This command can also be used prior to updating to compare different versions of Drupal to see what core changes are going to be (or have been) made.

find * -type f -exec diff {} /path/to/www/{} \;

HOWTO: Use TinyMCE in a Panel Pane Popup

Matt Cheney

The magic of Panels 2 is just the sort of thing you might expect from a wizard. Users can create pages with flexible and customizable layouts, they can populate those pages through an extensible block system, and they can configure and drag-and-drop those blocks around the page. Check out the demo page.

Sadly, the panels system does not allow its textareas to be used as TinyMCE WYSIWYG areas because of the way javascript and javascript events are handled. The basic problem is that TinyMCE runs on page load and is not set up to be activated on the Panel pane textareas that are created after the fact. This is a problem that hopefully the Drupal 6 version of Panels can resolve, but for Drupal 5.x the following hook_form_alter solution is possible.

First you need to set up a hook_form_alter callback as part of a new custom module or as part of an existing module you are modifying.

function my_module_form_alter($form_id, &$form) {
  switch($form_id) {

Second you need to render a hidden TinyMCE field on each panels editing page. This is not a particular clean way to proceed, but it will ensure that all of the appropriate TinyMCE .js is loaded on each page.

    case 'panels_edit_display':
      $form['tinymce_hidden'] = array(
        '#type' => 'fieldset',
        '#attributes' => array('style' => 'display: none'),
      );
      $form['tinymce_hidden']['tinymce_prerender'] = array(
        '#type' => 'textarea',
      );
      break;

Third you need to assign a special submit handler javascript call to convert all TinyMCE content back into its normal textarea content so it can be appropriately saved when the Panel pane is submitted.

     case 'panels_content_config_form':
       $form['next']['#attributes'] = array('onclick' => 'tinyMCE.triggerSave(true,true);');

Finally each of the textareas that are being rendered on the panel pane page need to have a special enable/disable TinyMCE link assigned to them. This allows users to turn on the TinyMCE functionality if they want. The code belows assumes your default TinyMCE state is off. I am sure there is a better and more generalized way to add these links, but this is a first step.

       // Load a disable or enable link below each textarea
       global $user;
       $enable  = t('enable rich-text');
       $disable = t('disable rich-text');
       $user = user_load(array('uid' => $user->uid));
       $profile = tinymce_user_get_profile($user);
       $status = tinymce_user_get_status($user, $profile);
       $link_text = $status == 'true' ? $disable : $enable;
       foreach($form['configuration'] as $index_raw => $value) {
         $index = str_replace('_','-', $index_raw);
         if ($value['#type'] == 'textarea') {
           $form['configuration'][$index_raw]['#description'] .= "<div><a href=
\"javascript:mceToggle('edit-configuration-$index', 'wysiwyg4-configuration-$index');\" class=\"wysiwyg-editor\" title=\"edit-configuration-\"" . $index . "\" id=\"wysiwyg4-configuration-$index\">$link_text</a></div>";
         } else {
           if (is_array($value)) {
             foreach($form['configuration'][$index_raw] as $index2_raw => $value2) {
               $index2 = str_replace('_', '-', $index2_raw);
               if ($value2['#type'] == 'textarea') {
                 $form['configuration'][$index_raw][$index2_raw]['#description'] .= "<div><a href=\"javascript:mceToggle('edit-configuration-$index-$index2', 'wysiwyg4-configuration-$index-$index2'); \"  class=\"wysiwyg-editor\" title=\"edit-configuration-\"" . $index . '-' . $index2 . "\" id=\"wysiwyg4-configuration-$index-$index2\">$link_text</a></div>";
               }
             }
           }
         }
       }
      break;

And you should be good to go.

  }
}

HOWTO: Quick jQuery Usability Tip: Automatically Clear/Restore Useful Default Values

Josh Koenig

Just wanted to post this quick trick I’ve been using lately to automagically hide/show useful default text field values (e.g. “Search” in the search box) using jQuery and the ultra-handy Drupal.settings() object.

Here’s the short and sweet copy/pastable jQuery code:

$(document).ready(function(){
  Drupal.settings.inputDefaults = {}
  $("input:text").focus(function() {
    var element = $(this);
    Drupal.settings.inputDefaults[element.attr("id")] = element.val();
    element.val('');
  });
  $("input:text").blur(function() {
    var element = $(this);
    if (element.val() == '') {
      element.val(Drupal.settings.inputDefaults[element.attr("id")]);
    }
  });
});

Basically this quick snippit will add a blank array object (ahh, the joys of moving between js and PHP) to the Drupal.settings object — which is useful for all sorts of great javascript functionality, and is integral to Drupal 6.0’s extended AHAH features; if you don’t already know it, do your self a favor and study up — and automatically fill it with any textarea’s default values when a user clicks/tabs it into focus. This lets us clear the default value, but replace it quickly if the user moves on to another element.

As listed, you probably don’t want this on your site, as it will affect things like editing nodes (e.g. title inputs will go blank when you click on them… not what you necessarily want), but it’s easy to tune this to only hit elments within certain forms since every form in Drupal has a unique #id.

Thinking about this, I decided to tune it up and actually make an extended jQuery function for this so it could be more easily applied to speecific elements like so:

$(document).ready(function(){
  // handle hide/show for text field default values in only one form
  Drupal.settings.input_defaults = {};
  $("#specific-form input:text").clearDefaultText();
});

jQuery.fn.clearDefaultText = function() {
  return this.each(function(){
    var element = $(this);
    Drupal.settings.inputDefaults[element.attr("id")] = element.val();
    element.focus(function() {
      if (element.val() == Drupal.settings.input_defaults[element.attr("id")]) {
        element.val('');
      }
    });
    element.blur(function() {
      if (element.val() == '') {
        element.val(Drupal.settings.inputDefaults[element.attr("id")]);
      }
    });
  });
}

This is a pretty nice little plugin, I think, and it shows just how easy it can be to add nice/reusable UI functionality. Happy Drupaling, and go get ‘em jQuery!

(updated w/slight improvement to jQuery fn)
(updated again w/object style improvements from comments)

HOWTO: Fully Theme and Customize the Drupal User Registration Form

Matt Cheney

Just a little to the left please. Flip it around. Put that on top of this. Call it by a different name. It is the little changes, that seem trivial and small, that often end up being real headaches to make and support our clients in making. Do we really want to try to build capacity with clients by teaching them to adjust #weight in hook_form_alter?

The Drupal Theming System is pretty powerful and, when done right, can offer a good avenue for our clients and their staff to edit, modify, and change their own website content. Its a lot easier to modify HTML files than Drupal module files.

A good example of where this kind of process is needed is on the user registration page. There are a lot of little bits of language and ordering to change and add, but to do so in Drupal module code can get a little hairy. Observe our technique to abstract the user/register form into a flat template file (while maintaing most of the other good Drupal goodness).

Step One: Create a theme override in your module code for the user/register form that executes a _phptemplate_callback to use a separate template file.

<?php
function theme_user_register($form) {
 
$vars = array();
 
$output _phptemplate_callback('user_registration_form', $vars);
 
$output .= drupal_render($form);
  return
$output;
}
?>

Step Two: Expand the theme override function made in step one to remove the titles and descriptions Drupal provides for the form elements. We do this in the theme function (instead of in a hook_form_alter) to preserve the original field titles so they can be used as part of any error messages coming out of form validation.

<?php
 
foreach($form as $key => $value) { // loop through top level
   
if (is_array($form[$key])) {
     
$form[$key]['#title'] = '';
     
$form[$key]['#description'] = '';
      foreach(
$form[$key] as $key2 => $value2) { // loop through second level
       
if (is_array($form[$key][$key2])) {
         
$form[$key][$key2]['#title'] = '';
         
$form[$key][$key2]['#description'] = '';
        }
      }
    }
  }
?>

Step Three: Create "rendered" versions of each of the form elements and set them as variables that can be passed to the template file.

Note: This can also be done with a generic foreach loop (similar to the one in step two) that renders each form element automatically.

<?php
 
// Set up the Vars Array
 
$vars = array();

 
// Render Specific Fields You Want on Your Registration Form
  // note - the specific location of the element in the form array varies
 
$vars['name_element'] = drupal_render($form['account']['name']);
 
$vars['mail_element'] = drupal_render($form['account']['mail']);
 
// continue for each field you want...

  // Don't Forget the Submit Button 
 
$vars['submit_button'] = drupal_render($form['submit']);

?>

Step Four: Create a template file in your site's theme directory to build the user/register form with the customized variables we defined in step three.

Note: This file needs to be the same name as specified in the _phptemplate_callback (example: user_registration_form.tpl.php).

<div class="user-register-element">
  <label>Enter a screen name:</label>
  <div class="user-register-element-input">
    <?php print $name_element; ?>
  </div>
  <div class="user-register-element-description">
    Screen names can be up to 13 characters in length.
  </div>
</div>

<div class="user-register-element">
  <label>Enter an Email:</label>
  <div class="user-register-element-input">
    <?php print $mail_element; ?>
  </div>
  <div class="user-register-element-description">
    Emails must be valid.
  </div>
</div>

<?php // continue on for each rendered form element ?>

The drupal magic here is that the user registration form is now uniquely customizable by anyone who can edit the theme template. This allows for customized "prompts" for each profile field element, without changing the site-wide field name in admin/user/profile, and it allows for customization of the username and email titles and descriptions.

This technique will need to be modified to support external modules that modify the user/register form like LoginToboggan. It also needs to take into account things like "required" fieldstates.

HOWO: Use Drupal For HTTP Authentication

Josh Koenig

Very often, a Drupal website is just one of many tools being deployed on a complex project. For instance, on Chapter Three’s development servers, we keep our own SVN repositories to track custom modules and theme development.

Also often, miscellanious web services like this will want to use the standard HTTP Authentication system. Most simply this is the familiar pair a .haccess and .htpasswd file protecting a directory. Easy to set up, but it requires an admin to keep yet another list of usernames and passwords somewhere on the system which over time becomes quite a pain.

Today, while noodling with some authentication scripts for the Drupal Dojo, I decided to see if Drupal’s own user table could be used as an authentication source for these tasks. Turns out it can, and it’s pretty useful too.

Drupal User Authentication
First off, this requires mod_auth_mysql to be set up in your Apache server. There are packages for most systems, as this is a common and widely used Apache module. Once this is done, use the following code in a .htaccess file or Apache <Directory> or <Location> directive:

AuthName "Use Your Drupal Login"
AuthType Basic
AuthMySQLEnable On
AuthMySQLHost <hostname>
AuthMySQLDB <database>
AuthMySQLUser <user>
AuthMySQLPassword <password>
AuthMySQLUserTable users
AuthMySQLNameField name
AuthMySQLPasswordField pass
AuthMySQLPwEncryption md5
require valid-user

Replace the hostname, database, user and pass values just as you would when configuring your drupal installation’s setting.php file. This will let Apache access the same users table from Drupal and authenticate against it!

Limiting Access By Drupal User Role
For extra credit, you can restrict valid logins to a particular user role by replacing the AuthMySQLUserTable directive above with these two lines:

AuthMySQLUserTable "users, users_roles"
AuthMySQLUserCondition "users.uid = users_roles.uid AND users_roles.rid = 3"

The above assumes that your “admin” role has role id (rid) 3. Your mileage may vary here, and savvy SQL query writers will immediately see how you can use these two directives to limit access in all sorts of ways.

For admins with a lot of experience with mod-auth-mysql, this is all pretty obvious, but I hadn’t seen documentation specific to Drupal anywhere on the web. Hopefully this will simplify your life as much as it’s already simplifying mine!

HOWTO: Keeping Drupal on Your Keychain

Matt Cheney

I am sure it’s a common problem. You are a rocking Drupal software engineer and you are talking to a particular cute guy or girl at a pretty awesome party. Naturally, the conversation turns to open source software projects and you boast that you work on Drupal - the coolest content management system out there. Since this boast is bound to be followed up with questions like “what is Drupal?” or “why is Drupal cool?” - wouldn’t it be grand (instead of trying to explain just how cool the garland color picker is) to whip out a portable USB key, stick it in an available computer, and show them the wonders of Drupal right then and there?

Install Ubuntu onto a USB Key

  • Download Ubuntu and mount [mount -o loop ] the image
  • Use fdisk [fdisk /dev/sda] to delete any existing partitions [fdisk: d], add a new partition [fdisk: n,p,1,*enter*,+700M], set its type to FAT16 [fdisk: t,6], and make it active [fdisk: a, 1], add another partition [fdisk: n,p,2,*enter*,*enter*], and save all the changes [fdisk: w]
  • Install the FAT16 filesystem [mkfs.vfat -F 16 -n usb /dev/sda1] and the ext2 filesystem [mkfs.ext2 -b 4096 -L casper-rw /dev/sda2]
  • Install the Linux System Tools [syslinux -sf /dev/sda1]
  • Mount the USB Key [mount /dev/sda1 /mnt] and copy over Ubuntu [cp -rf casper disctree dists install pics pool preseed .disk isolinux/* md5sum.txt README.diskdefines ubuntu.ico casper/vmlinuz casper/initrd.gz install/mt86plus /mnt]
  • Copy this special file to the USB key [tar xf usyslinux.tar ; cp syslinux.cfg /mnt]
  • Run Lilo [lilo -M /dev/sda]

These instructions and system file are adapted from this tutorial. For the purposes of these directions the USB drive is assumed to be at /dev/sda.

Install and Configure the LAMP Stack

  • Install the stack [apt-get install php5-mysql mysql-server php5 apache2]
  • Enable Apache’s mod-rewrite [ln -s /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled/rewrite.load]
  • Allow .htaccess overrides in apache’s configuration file [vim /etc/apache2/sites-available/default] by changing all “AllowOverride None” configurations to “AllowOverride All”
  • Edit your /etc/rc.local file [vim /etc/rc.local] to add the following line [mount /dev/sda2 /mnt], run the command on the command line [mount /dev/sda2 /mnt], and add a web root directory [mkdir /mnt/webroot]
  • Edit the Apache configuration file to point to your new webroot [vim /etc/apache2/sites-available/default] to change all references to /var/www to /mnt/webroot. ** Note - its important to setup a separate webroot on the ext2 system since apache is not a fan of the FAT16 filesystem **

Install and Configure Drupal

  • Create your MySQL database [mysql -u root], set the appropriate permissions, and copy over your Drupal database (or install a new one)
  • Copy over the Drupal code files to your webroot at /mnt/webroot
  • Do any other Drupal configuration needed

Set up “Kiosk Mode” in Linux

  • Create a shell script [vim /home/ubuntu/kiosk.sh] to execute [/usr/bin/firefox —fullscreen http://127.0.0.1] ** Note - sometimes it takes a second for apache to load and the script may need “sleep 30” at the beginning to give apache time to load **
  • Configure Ubuntu at (System —> Preferences —> Sessions) to run the kiosk.sh script at Startup
  • Install the AutoHide Firefox Extension
  • Add a line [rm /home/ubuntu/.ICE*] to your GDM runtime to remove ICE Authority File Locking Issues [vi /etc/gdm/PreSessions/Default]

To boot off of the USB key, insert the USB key into a computer and set its BIOS to boot from the USB key. Wait a couple of minutes for it to boot up and enjoy the Drupal.

HOWTO: Use Different Node Templates by Node Variables (nid, type, view)

Farsheed Hamidi-Toosi

With node template files you are often limited to something like node.tpl.php and node-blog.tpl.php. Often times it’d be nice to make a different template for just one specific node or a different template for teaser/list view and full node view.

Using the PHP code below, Drupal will look for these template files, split by page or no page view. This gives more fine grained control over your node tpl.php files.

Page view:

1) node-[nid]-page.tpl.php
   Node by itself on a page, specific NID
2) node-[type]-page.tpl.php
   Node by itself on a page, specific type
3) node-default-page.tpl.php
  Node by itself on a page, default

Listing/Teaser view:

4) node-[nid].tpl.php
   Node in list/teaser, specific NID
5) node-[type].tpl.php
   Node in list/teaser, specific type
6) node.tpl.php
   Node in list/teaser, default.

*UPDATE* Earl Miles has shown this can be done much simpler than what I had previously. Revised code below.

Place this code in your template.php file in your theme’s directory.

<?php
function _phptemplate_variables($hook, $vars = array()) {
  switch (
$hook) {
    case
'node':
     
// Here is the way to switch to a different node-<something> template based on node properties.
     
if ($vars['page']) {
       
// This is LIFO (Last In First Out) so put them in reverse order, i.e
        // most important last.
       
$vars['template_files'] = array('node-default-page', 'node-'. $vars['node']->type .'-page', 'node-'. $vars['node']->nid .'-page');
      }
      else {
       
$vars['template_files'] = array('node-'. $vars['node']->nid);
      }
      break;
  }

  return
$vars;
}
?>

HOWTO: Write Cleaner tpl.php Files

Farsheed Hamidi-Toosi

The PHPTemplate system in Drupal is a powerful theming system. However, because it is written in PHP it is easy to abuse since it is possible to directly inject PHP logic into the templates. This often creates the effect of HTML-IN-PHP which is not good.



HTML-IN-PHP:

<?php
print '<h2 class="title">'. $title .'</h2>';
?>

PHP-IN-HTML:

<h2 class="title">
<?php print $title ?>
</h2>

Which do you think a themer who understands HTML/CSS will understand better? Of course the second, because it is mostly HTML and the themer can modify the HTML tags quite easily.

Conditional Statements

Another example of this is with logic statements.

HTML-IN-PHP:

<?php
global $user;
if (
$user->uid) { ?>


<h2 class="title">You are now logged in!</h2>

<?php } ?>

PHP-IN-HTML

<?php global $user; ?>
<?php if ($user->uid): ?>

<h2 class="title">You are now logged in!</h2>

<?php endif; ?>

See how the second example is easier to read? It’s also broken up into small pieces that a themer can move around quite easily. Having open and closing braces for an if statement is really hard to follow. But if(conditional): and endif; statements are easy to read, and “chunkify” or “modularize” the text in a clear way.

<?php if ($test == TRUE): ?>

<!— Block of HTML to printout if TRUE —>

<?php endif; ?>

PHPTemplate variables

The last thing that can make your life and the themer’s life easier is to pass variables to the template files using phptemplate_variables. A tpl.php really should be mostly simple conditional statements and print statements. If you have PHP code spanning multiple lines or are working with arrays or something, you can probably pull that code out of the tpl.php and put it in template.php.

Example Node.tpl.php with too much PHP

<?php
if ($node->field_related[0]['nid']) {
 
$related_cck_node = node_load($node->field_related[0]['nid']);
  print
'<div class="related-cck-link">';
  print
l($related_cck_node->title, 'node/' . $related_cck_node->nid);
  print
'</div>';
}
?>

Why is all that logic in the tpl.php? You can move that out into template.php.

Using Template.php to add variables to your tpl.php files

<?php
function _phptemplate_variables($hook, $vars = array()) {
  switch(
$hook){
    case
'node':
      if (
$vars['node']->field_related[0]['nid']) {
       
$related_cck_node = node_load($vars['node']->field_related[0]['nid']);
       
$vars['related_cck_link'] = l($related_cck_node->title, 'node/' . $related_cck_node->nid);
      } 
      break;
  }
  return
$vars;
}
?>

Now the node.tpl.php file will get a new variable called $related_cck_link which you can easily print out.

Example Node.tpl.php file with logic removed

<?php if ($related_cck_link): ?>
  <div class="related-cck-link">
    <?php print $related_cck_link ?>
  </div>
<?php endif; ?>

HOWTO: Quickly Truncate a Block of Text

Farsheed Hamidi-Toosi

When theming things I run into situations where a block of text is too long and I need a really quick way to truncate text and append an ellipses or custom trailing text. The built in drupal teaser truncates text in a much more logical manner (watches out for html tags and the like) while this php snippet is simpler and meant to run on pure text. You can do strip_tags() if you want to remove all the html tags before running this code on your piece of text. I often just drop this into my template.php and use it in various spots in the theme.

<?php
/**
* Truncate the string if it is beyond a certain $length and append with an ellipses or custom text
* $length is the number of characters allowed before truncating
* $append is appended to the truncated string
*/
function your_theme_custom_truncate($string = '', $length = 30, $append = '&#8230;') {
  return
strlen($string) > $length ? trim(substr($string, 0, $length)) . $append : $string;
}
?>

Before:

Suspendisse potenti. Ut tempus auctor libero. Aliquam molestie dolor quis lectus. Curabitur et erat eget lorem nonummy ultrices. Mauris interdum. Etiam imperdiet viverra purus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Mauris sem mauris, feugiat at, dictum vitae, placerat nec, odio. Nulla fringilla. Morbi justo nulla, commodo quis, ultricies a, eleifend eu, ante. Morbi eget erat eu ante tincidunt interdum. Nullam at est. Nulla ultrices pede vitae sapien bibendum bibendum. Quisque turpis enim, ullamcorper at, fermentum quis, vulputate quis, libero. In facilisis, dui eget accumsan molestie, justo metus tempor quam, eu tempor ipsum eros a urna. Donec aliquet. Curabitur condimentum volutpat augue. Praesent bibendum commodo enim.

After:

Suspendisse potenti. Ut tempus auctor libero. Aliquam molestie dolor quis lectus. Curabitur
et erat eget lorem nonummy ul…