Four Kitchens: the Drupal experts - Drupal

FastClick Drupal module removes 300ms tap delay

Howdy perfers! This week is just a quick note to let you know about a new release for the FastClick Drupal module which provides integration for the FastClick JS library by FTLabs. Drop it on your sites and feel the difference on touch phones!

300ms tap delay makes for slower browsing

Have you ever noticed a delay between when you tap a link or other UI element and when it finally reacts? This is a solution to remove that delay! It is natively removed in newer versions of Chrome on Android, but for all browsers in iOS this library provides a very noticeable improvement. You might have noticed that tapping around our own site feels faster than it used to. We’re already running this module in production.

You can read about the history, watch a video that demonstrates the effect, and read the rationale for iOS’s continued use of 300ms delay in this HTML5 Rocks article.

Drupal module provides integration

The Drupal module is slim, but it makes for easy integration by downloading a copy of the library to sites/all/libraries/fastclick and adding the script into the footer area instead of up top in the <head>. The maintainer, Pere Orga, is very responsive to issues and open to discussion for improvements.

Code can be found at https://drupal.org/project/fastclick

Commenting on this Blog post will be automatically closed on May 11, 2014.

Submit your User Experience Design sessions for DrupalCon Austin

DrupalCon Austin is coming to our hometown June 2-6, 2014 and we could not be more excited. This year, myself and Ken Woodworth are curating the User Experience Design track for the con.

The User Experience Design (UXD) track is the place to learn about everything related to research, content strategy, prototyping, user testing, and more for Drupal.

We’re inviting community members to submit 60-minute sessions on the following topics:

  • Prototyping for Drupal
  • Content strategy
  • Authoring experience
  • User testing
  • Design process
  • Visual design

The rise of mobile-first design and importance of content strategy has caused the discipline of UX to explode. Additionally, the Drupal CMS offers us unique opportunities to improve authoring experience and hone our design processes. With the UXD track, we want you to share your knowledge and stories for achieving success in Modern Drupal projects.

Submit a session today!

The call for sessions is open until March 7, 2014 at 11:59pm CET.

Commenting on this Blog post will be automatically closed on April 20, 2014.

Theme it once

The popularity of front-end JavaScript frameworks, driven largely by improvements in JavaScript performance, is skyrocketing. One of their strongest features is allowing developers to build extremely rich applications that will work the same way on most modern platforms. So it comes as no surprise that backbone.js found its way into Drupal 8 as a core JavaScript library. If you haven’t worked with a rich JavaScript application yet, you can be certain you will soon.

A key component of any rich JavaScript application, be it built on a framework or not, is templating. Each templating engine behaves slightly differntly but there’s one thing that they, and in fact all templating engines, have in common: scaffolding markup has placeholders which are later replaced with variables, like this:

That should look relatively familiar, in Drupal we’re used to seeing things like this:

Front end templating is great – it’s flexible and allows you to offload some of the processing power required to render a page to the client. There are some gotchas though, users without JavaScript support (or minimal JavaScript support) is an obvious one. A less obvious case that front end templating isn’t ideal is when you need to be able to render a page both on the client and server side. Dan Webb (@danwrong) from Twitter wrote extensively about Twitter’s move from an exclusively front-end rendered site to a mix of front-end and back-end rendered pages. In their case, and in many cases, a webpage can be delivered and ready for user interaction much faster when it’s been rendered on the server.

So, what am I getting at, and how does it relate to Drupal? Using either of the front-end templating gotchas from above, you can see that we’d need to have a template for both the frontend and backend source. That obviously sucks because now we have twice the markup that we need to deal with.

It doesn’t have to be that way though. By relying on Drupal’s rendering pipeline we can use one set of markup for both our front-end and back-end templates. Consider this simple module. In the theme_it_once() function we’re constructing an array of items to theme. Simple enough, but there’s something different about this page callback:

return array(
   'items' => array(
     '#theme' => 'item_list',
     '#items' => $items
   ),
   'template' => array(
     '#theme' => 'example_item',
     '#name' => '{name}',
     '#description' => '{description}',
     '#prefix' => '<script id="example-template" type="text/template"><li>',
     '#suffix' => '</li></script>',
   ),
 );

This render array has an additional element – template – which adds the markup from our PHP template to the page, wrapped in a script tag so it won’t be displayed. The resulting markup, which should look very familiar, will look like this (with some extra whitespace added for readability):

<script id="example-template" type="text/template">
  <li>
   <h4 class="item-name">{name}</h4>
   <p>{description}</p>
  </li>
</script>

Now let’s move to the front end and see how we can take advantage of this. In our example we’re going to use dust.js for the front-end templating engine, but the concept will be the same regardless of what you choose. Consider this script:

Notice that we’re grabbing the HTML from our template and compiling it into dust. We’re then rendering the template with a name and description variable and appending the result to the list generated by Drupal. Yes, it really is that simple to write your markup once and use it everywhere!

Beyond Examples

One of the biggest problems with this example for a rich application is the overhead associated with compiling the templates and the access to the DOM to fetch the template in the first place. In our example we only have one template, so the hit we take isn’t that great, but if we had many templates we’d want to precompile them. This obviously means adding a build task to create the generated templates file as needed. A drush command would be a great way to still keep everything in PHP templates. Your command would pass the front-end placeholders into your theme function in exactly the same way as I’ve shown here, but would then pass the resulting markup off to a child process – possibly grunt.js – to compile that markup.

A functional example of this code can be downloaded from the gist.

Commenting on this Blog post will be automatically closed on April 20, 2014.

Submit a session for DevOps at DrupalCon Austin

Austin

With DrupalCon Austin fast approaching, the call for submissions is already open! With the impending release of Drupal 8, Austin will be an important event to help us push the DevOps mindset into the forefront with Drupal 8.

Have you been automating the deployment or maintaining Drupal across a large number of systems, testing your code for performance and functional regressions, or architecting Drupal as a service layer? Consider submitting a session!

The DevOps track is interested and seeking topics relating to:

  • Automated development / deployment of environments
  • Emerging best practices for Drupal 8 continuous integration
  • Changes in deployment and testing best practices from Drupal 7 to Drupal 8
  • Emerging best practices for Drupal 8 hosting and performance
  • Frontend automated regression/performance testing
  • Distributed Drupal development (Docker, Vagrant, etc)
  • Architectures with Drupal as a service
  • Performance best practices
  • Configuration management
  • Testing best practices throughout the development workflow

See you in June!

Photo credit: alex de carvalho on Flickr

Commenting on this Blog post is closed.

Responsive tables with field collections and field formatters

Recap and remix

In my last post I discussed the challenges inherent in modeling fields when you are unable to achieve a complete understanding of a data set. Much of that post was based on a flexible field model for content that was semantically tabular. To bring you up to speed but also show some of the content editing experience, let us take a look again at our model, but this time in Drupal.

We have a nested field collection situation which can be described as:

Field Group {
  Field Collection for Table (1 or more / set to 1 initially) {
  Header 1  - text field (provided with default heading values)
  Header 2 - text field (provided with default heading values)
    Field Collection for Table Data (1 or more / set to 1 initially) {
      Row data 1 - text long (w/ WYSIWYG editing)
      Row data 2 - text long (w/ WYSIWYG editing)
    }
  }
}

The containing table field collection looks something like this:

Containing field collection screen shot

Our nested row data field collection in the containing table field collection looks something like this:

Nested field collection

Initially the number of values the site will allow for either of the field collections was configured as 1. This setting (Number of values) is available in the Global settings for your field collection in its field settings screen - available as the edit link from your field collection listing on /admin/structure/field-collections.

Field collection number of items setting

Thanks to a table field formatter, discussed at length a little later in this post, some CSS and a few tweaks made to widgets and field settings the content contributor experience for our field model is pretty streamlined at that point. It looks something like this:

Single table single row field collection table

We can increase that box to any number of values by setting the “Number of values” setting to unlimited.

Field collection number of items set to unlimited

If we do that for the rows field collection that will allow content contributors to add multiple rows to the table:

Single table multi row field collection table

If we make the number of values unlimited for both the top containing field collection and the nested row data field collection, content contributors can add multiple rows and multiple tables.

Multi table multi row field collection table

So yeah, tables. After so much misuse in the early 2000s and the resultant disdain, I really enjoy the semantically appropriate return of our erstwhile markup pal, the table. Rejoice, the table has returned!

Presenting the table! <…cricket chirps… >

Well, as it turns out, that in the present age of responsive design, the table still has issues. The limited real estate of our handhelds and even tablet computers can pose a real challenge to the often wide space requirements of tabular data. There are plenty of shortcuts to presenting data like this responsively, throw the content in some containers like divs, plug some percentage widths in there, add some media queries, and hey, it looks like a table, yay, we are done, right?

While responsive, that’s not very responsible and hardly semantic. Would you doom the table to misrepresentation knowing fully its storied but grim past? What about assistive technologies like screen readers? Visitors without the benefit of vision don’t know that your content looks like a table. They only know what it sounds like. A bunch of divs doesn’t sound like a table. What about automatic content consumption technologies of today and the future, crawlers, scrapers, and other utilities. They only know your content as its markup indicates and content in containers like divs isn’t content in table rows and columns. Making incorrect semantic choices is not only poor form, it is exclusionary. We didn’t build the web for that, did we? No, no we didn’t.

Responsible responsivity

Luckily many people have been hard at work on solutions to this issue. There is a really great recap with working code of responsive table approaches from Simon Elvery at http://elvery.net/demo/responsive-tables/. Each of these solutions responds to the small screen real estate problem in a different way. The results have different feels and so one size is not going to fit all. In “The Unseen Column” approach by Stuart Curry, as the screen size shrinks, columns are omitted from display. So, while not all columns are represented, the main gist of the information is communicated. In the “Flip Scroll” approach by David Bushell, rows are columns are switched, it allows for a complete understanding of one row, and depending on your screen orientation, possible comparison.

This brings us back to our field model from last week. After examining these different responsive table approaches it was time to decide the best fit for our content and to figure out our approach for translating that data model into an responsive table on the presentation layer. The solution we chose was the “no-more-tables” solution, or rather, a slightly modified version of the “no-more-tables” solution. Before you call ‘shennanigans’, don’t worry, “no-more-tables” is in quotes for a reason, they actually ARE tables.

The “no-more-tables” approach as described and developed by Chris Coyier (http://css-tricks.com/responsive-data-tables) uses CSS media queries to detect screen size, and when the table loses visible viability it basically overrides the typical table display by forcing table cells to display as block items. {example} Additionally, column headers, which might get lost as the content grows vertically, are brought to the content they reference through a CSS content “:before” approach. This approach was further refined by Simon Elvery in his demo example using the super flexible HTML 5 custom data attributes. These attributes are intended for specific custom data that are private to the page or application. The attributes allow us to take the content out of CSS and keep it in the markup, thats easily doable with a CMS like Drupal and as an approach feels correct. Basically, we are taking the column headings and putting them into these attributes for each of the cells. This allows the markup to stay as a table but have a presentation that really honors mobile form factors.

For our specific content, the content filling out that flexible field model I discussed in my last post, it was well suited for no-more-tables because it had a small number of columns. This meant that the transition from having that information displayed horizontally for comparisons to displayed vertically for comparisons actually provided a similar experience. The purpose of this particular content was to allow comparisons, users would need to compare columns in the same row and then understand the next row as another grouped but separate concern in the same format. Some of the other responsive table approaches would have been overkill and so the “no-more-tables” approach was the goldilocks approach, not too much or too little change when going from screen to screen.

Responsive table field formatters

The flexible field model we settled on was a series of nested field collections. One way to get our field collection into the “no more tables” approach could have been through a template (tpl.php) solution. However, I like the flexibility and empowerment of field formatters. Being able to switch presentation approaches on a field by field level at the click of a mouse is very powerful indeed. This ability is very useful for demos, prototypes, and letting site builders make and experience different options. Given the high degree of flexibility we already knew we needed from our content — leaving things open seemed like the right choice.

Field formatters aren’t terribly difficult to put together, they can be as easy as filling out hook_field_formatter_info to tell Drupal about your formatter and hook_field_formatter_view to spit out your field correctly. However, field collection field formatters aren’t terribly fun. There is a lot going on here, especially with the nested sets.

Luckily and thankfully there already is a table field formatter for field collections called Field Collection Table, seriously, way to go Tim Plunkett! This saved me hours and hours. Let’s take a look at the few changes that were needed to shape the existing solution to our responsive table needs.

The main changes come in hook_field_formatter_view where we deal with the variable headings for the tables, add in the data attribute to the table cells and deal with extracting row and table information from the nested field collections. Additional changes are made in hook_form_alter to accommodate nested field collections made possible by this patch from rooby on drupal.org https://drupal.org/node/1438266. Finally there was a small bit of work to eliminate the sticky headers in hook_theme and theme.inc.

Ok, the most important bit is getting the data attributes into the cells. This is actually pretty easy to do - the cell data is being assembled via a render array, td attributes can be added to the existing render array at ln 69:

$column[] = array(
  'data' => $content[$field_name],
  'class' => $field_name,
);

like this:

$column[] = array(
  'data' => $content[$field_name],
  'class' => $field_name,
  'data-title' =>  $your_header_variable,
);

So, this leaves you to populate the variable, $your_header_variable. To do so you’ll need to pull that out of the data from the field collections. Because we had a pretty complicated data structure with nested field collections that could have multiple tables and multiple rows it got fairly complicated quickly, if you don’t need that level of complication you can still extract what you need for a responsive table solution. In ln 51 there is an foreach loop to go through each field collection - what maps to a row in our table. For each of the items we get the field collection entity through the field_collection provided function: field_collection_field_get_entity. Probably the best place is in line 59 in yet another foreach loop, which relates to the columns in your table, grab the field name or english version of your field name as the attribute.

For our data structure we needed to create two sets of for each loops to deal with the nested field collections and the variable table row headings. Essentially setting up some arrays to store header information for each table instance in the field collection and then another array structure to hold the rows within that structure, and again, so much gratitude to Tim Plunkett, whose code this is built upon:

/**
 * Implements hook_field_formatter_view().
 */
function field_collection_responsive_table_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();
  $settings = $display['settings'];
 
  switch ($display['type']) {
    case 'field_collection_responsive_table_view':
      // This is going to hold our table header information
      $header_field_names = array();
      $data_field = '';
      $table_fields = array();
 
      // We are essentially going to run a loop of loops to extract out table header
      // and field names within the field collections into the arrays that we need.
      // After we have that information we'll run a similar
      // algorithm to work with the field collections and nested field collections.
      foreach (field_info_instances('field_collection_item', $field['field_name']) as $field_collection_item) {
      $field_info = field_info_field($field_collection_item['field_name']);
        // Check to see if this is a field collection field. We do this because we have two text fields
        // representing the headings and the nested field collection.
        if ($field_info['type'] == 'field_collection') {
          // If this is a field collection field, then lets store its name for later use.
          $data_field = $field_info['field_name'];
          // get the field names within this field collection.
          // These are our nested field collection fields.
          foreach (field_info_instances('field_collection_item', $data_field) as $field_collection_2_item) {
            $field_info_2 = field_info_field($field_collection_2_item['field_name']);
            // Our model used text long as cells, this isn't very flexible, but it is what we needed.
            if ($field_info_2['type'] == 'text_long') {
              // This is a field within the encompassed table.
              // get its field_name for use later.
              $weight = $field_collection_2_item['widget']['weight'];
              $table_fields[$weight] = $field_collection_2_item['field_name'];
            }
          }
        }
        elseif($field_info['type'] == 'text') {
          // This is going to be one of the variable headers.
          // We'll record the weight as it relates to the ordering of the columns
          // and then we'll use it as the array key.
          $weight = $field_collection_item['widget']['weight'];
          $header_fields[$weight] = $field_collection_item['field_name'];
        }
      }
      // We have the data we need, lets make sure it is in the correct order.
      // Put header fields in order in a numeric array
      // which works because of the weights.
      ksort($header_fields);
      $header_field_names = array_values($header_fields);
      // Put internal field collection field names in order
      // that relates to the column order.
      ksort($table_fields);
      $table_field_names = array_values($table_fields);
      $rows = array();
 
      // Ok, now that we have that column and header information in some easy
      // to access data structures we can now work with putting the data into
      // responsive tables, there could be multiple, so we'll start up a
      // for each loop for the tables.
      foreach ($items as $delta => $item) {
        $header = array();
        $rows = array();
        $row_items = array();
        $field_collection = field_collection_field_get_entity($item);
        // Get the headers for this table
        $variable_column_names = array();
        $lang = language_default();
        $count = count($header_field_names);
        $column_header = array();
 
        for ($i=0; $i < $count ; $i++) {
          $field_name = $header_field_names[$i];
 
          if (!empty($field_collection->$field_name)) {
            $value = current(reset($field_collection->$field_name));
            $value = $value['value'];
          }
          else {
            $value = '';
          }
          // Our table headings for this table.
          $header[$i] = array(
            'data' => $value,
            'class' => $field_name,
          );
          $column_header[$i] = $value;
        }
        $data_rows = $field_collection->$data_field;
 
        if (isset($data_rows[$lang])) {
          if (count($data_rows[$lang])) {
            $row_items = reset($data_rows);
          }
        }
        else {
          return;
        }
        // Ok, now another foreach loop for the actual rows.
        foreach ($row_items as $delta => $item) {
          // Get field collection entity for each row of data.
          $field_collection = field_collection_field_get_entity($item);
 
          if (empty($field_collection)) {
            continue;
          }
          $view = $field_collection->view();
 
          $content = $view['field_collection_item'][$field_collection->identifier()];
 
          $column = array();
          // This will tell us how many columns we need to iterate through.
          $count = count($table_field_names);
 
          for ($i=0; $i < $count; $i++) {
            $field_name = $table_field_names[$i];
            $data_title = $column_header[$i];
 
            if (isset($content[$field_name])) {
              $content[$field_name]['#label_display'] = 'hidden';
            }
            else {
              $content[$field_name] = array(
                '#markup' => '<span class="empty_field"></span>',
                '#empty' => TRUE,
              );
            }
            // We'll add our columns to a data array for each row.
            $column[] = array(
              'data' => $content[$field_name],
              'class' => $field_name,
              'data-title' =>  $data_title,
            );
          }
          // Now add that column data to the render array for rows
          $rows[] = array(
            'data' => $column,
            'class' => array('field_collection_item'),
          );
        }
        if (count($rows) == 0) {
          return;
        }
        // Finally we will add all or our rows and headers to render array.
        $element[] = array(
          '#theme' => 'table',
          '#header' => $header,
          '#rows' => $rows,
          '#sticky' => FALSE,
        );
        if (!empty($settings['empty'])) {
          $element[0]['#theme'] = 'table__field_collection_responsive_table';
          $element[0]['#settings']['empty'] = TRUE;
        }
      }
      break;
  }
 
    field_collection_field_formatter_links($element, $entity_type, $entity, $field, $instance, $langcode, $items, $display);
 
    return $element;
 
}

As a final improvement to help us get even closer to simpler markup for these responsive tables we employed the Fences module to assist us in removing markup cruft. Fences (https://drupal.org/project/fences) is a great module that simplifies default Drupal div based layouts.

The finished product on desktop:

Desktop field collection as a table

The finished product shrunk for mobile devices with the “no more tables” approach:

Responsive no-more-tables field collection as a table

Your local mileage may vary depending on how you’ve implemented the field collection. I have this work available as a Drupal sandbox if you’d like to take a deeper look or even modify the code for your own.

Commenting on this Blog post is closed.

A flexible field model for tables

Part 1: Modeling Ambiguity

When you are developing data models for fields in Drupal sometimes the only thing you can count on is that there will be exceptions to the model. Thankfully, with Drupal, you can incorporate a lot of flexibility into your data model. Typically that flexibility comes at the cost of complexity for you, the developer or site builder, and likely, for your content contributors. It gets even more difficult when those fields are irregular in format, need to be responsive, and are a part of a time sensitive content launch involving content experts with little to no Drupal experience.

Recently, we were faced with a situation just like this - we needed a high degree of field flexibility for tabular data that ultimately needed to be responsive and the content contributor experience had to be dead simple. Thankfully the effort spent to develop this solution was rewarded the very first time we were able to reconfigure the field data model on the fly. I’d like to share our approach to the field model and the responsive no-tables end result. In the first part of this two-part series I’ll walk you through the process of modeling fields with a lot of flexibility and in the second part we’ll focus on how to represent that model in responsive design with a “no-tables” strategy.

The problem at hand

Let’s start with a brief overview of the problem. A client was launching a new site with a deadline that required a large content entry effort from a number of Drupal novices. The scale and pacing made it necessary to simplify the entry process as much as possible. In fact, development and content entry needed to occur simultaneously to complete the site by the launch date. Our efforts as a development team were to enable content entry at the earliest date possible and fill out improvements and other functionality after. While much of the content was tabular in nature, individual tables varied occasionally but significantly and there simply was too much of it to audit so that detail was cataloged. Heavy tablet and mobile device use was predicted and so all of the content, including the tables, needed to be responsive.

In summary we needed to:

  1. preserve and enable content idiosyncrasies
  2. keep entry as simple as possible, and
  3. follow best practices on the presentation layer for responsive tables.

Field modeling with Rumsfeld: Known unknowns in your content

I love saying the phrase “modeling ambiguity”. It has a nice mouth feel and its a lot nicer than saying “nobody knows all the details just yet”. I used to say this phrase a lot when I was building database schemas from scratch for applications without frameworks, yuck. The reality of that phrase hurt a lot more back then. Well, thank goodness those dark days are gone. I haven’t had to pull this phrase out all that often with Drupal especially given all of the options that a site-builder has at their finger-tips for multi-value fields, field collections, field groups, field formatters and the powerful context surfacing and evaluation from CTools. However, my old friend reared his ugly head on this problem, and it was just in the nick of time.

Through our discovery phase we uncovered a number of similar fields for several content types. The fields had a heading, with one or more tables. Each table had two columns with one or more rows and a header. Each header had two column headings which may or may not have specific and unique headings per table. Table content had light formatting such as bolds, italics, bullets, and underlines, as well as html links.

In the end it looked something like this - desktop on the left and mobile on the right:

Desktop and mobile mockup of tabular data showing fields and optional repeating structures

You can have anything you want… for a price

The real problem in all of this was that each time we thought we had nailed down when a particular instance of this field model had a particular set of these variations — another survey of the actual content demonstrated that it was a little different. This is where all that experience with “modeling ambiguity” came in handy. I knew from experience that we could accommodate all of those variations. I knew that while it would be nice, we really didn’t need to know all of the variations before hand. So far that is a pretty rosy picture.

Ah, but I also knew that with ambiguity comes a price. Usually a developer’s blood, sweat, and tears and sometimes a site’s users. Things get complex quickly when you don’t have a lot of things nailed down. You have to think through all of the options and provide ways for contributors to self select at entry time. Both of those can cause pain. I brainstormed a number of ways we might try and accommodate this variability programmatically but I knew it was going to take some time to get all the pieces in place. Since time was a real concern there were really two options - create a fast solution that would almost certainly require rework and a lot of band aids but enable quicker entry or step back and create a more novel solution that was truly flexible. Both the client and I agreed that a longer term, flexible solution was in the best interest of the site, timely delivery, and cost.

So I worked backwards from the most complex combination of all of these elements and understood that content contributors would ultimately need to:

  • add or remove any number of tables beneath a heading
  • allow editable headers on a per table basis with default column headers
  • add or remove any number of rows to each table,
  • utilize a wysiwyg editor to manage light formatting for each table cell

Scaling with Variability

The obvious choice for tabular data is a table field, right? Right, er, no, not here. Don’t get me wrong, its a great solution for most tabular data needs, please use it. However, it didn’t hit the right notes here. Mainly because it simply doesn’t scale with variability. This is another important concept in successfully modeling ambiguity. “Scaling with variability” means that you should only introduce the additional complexity of handling the variations when needed. With all of the fields set as table fields there is no more-or-less difficult version, it is tables all of the time. Its not particularly flexible for rich editing, nor the heading variability, and to top it off, storage for table fields is fairly unique, which means there would certainly be data migration if the fields needed to be modified further when something new comes up or if no further complexity is introduced to some instances - there is no opportunity to devolve into a simpler state.

What we were really looking for was a nested multi-value field structure that could withstand on the fly changes. Significant field type changes are often disabled after there is data in a field but what we were relying on in this case is that the gradual process of content entry would reveal the need for these variations on particular instances of this field in the content types. So, what field type comfortably accepts a single or delta value without significantly altering the storage? What field type accommodates a multi-field grouping approach? What multi-field type can nest inside itself? What options do we have for rich editing experiences for the table cells?

Arriving at a Model

The field model that answered all of these questions looked something like this:

Field Group {
  Field Collection for Table (1 or more / set to 1 initially) {
  Header 1  - text field (provided with default heading values)
  Header 2 - text field (provided with default heading values)
    Field Collection for Table Data (1 or more / set to 1 initially) {
      Row data 1 - text long (w/ WYSIWYG editing)
      Row data 2 - text long (w/ WYSIWYG editing)
    }
  }
}

How it works

Let’s discuss how this structure works. The field group is the parent structure which will accommodate the field heading for all tables below. Then we have our nested field collection structure - one field collection that contains another field collection as a child. The first field collection structure allows us to have multiple or single tables underneath the heading and the second field collection gives us multiple or single rows of table data for the parent table field collection. By default we’d start with the simplest configuration of a single table and a single row value which results in a very plain content entry experience. The Row data columns are text fields with wysiwyg field editors allowing our content entry team access to light formatting options with familiar tools. Additionally, if the fields change significantly we have a little more flexibility from the storage perspective. Our variable table headings can be accounted for in the text header 1 and header 2 fields.

The nested field collection approach lets us leverage the strengths of individual field types editing interfaces and their storage. It also gives us the flexibility to add in the option for a multi-value field only when needed. When not in play, as a single value, each field looks just like a single WYSIWYG text field. If at any point during the content entry a content contributor discovers that a particular instance of this field needs to have multiple tables or multiple rows we can enable that variation without fear of having to reroll the field. We simply make tht change on the content type configuration screen. If we need a single multiple row table we can do that, if we need multiple tables with multiple rows with default or empty headings that are required we can do that too. Its a much more configurable solution that lets us dial each instance in at its required complexity.

Hopefully I’ve given you some tools and terms to think about the next time you need to model ambiguity. In the next part of this two part series we’ll take a look at how we translated this field structure into responsive table content with a “no-tables” approach.

Read Part 2 of this post here.

Commenting on this Blog post is closed.

Multilingual CSS generated content in Drupal

CSS generated content is cool. You can make those little triangles everyone seems to love, but its real purpose is to let you add presentational words that would otherwise be a pain to generate in markup for some situations.

a:before {
  content: 'Download item';
}

It can do other neat things like output the contents of another attribute on your element. This feature was originally created to allow print stylesheets to display URLs inline for printed documents:

a:after {
  content: ' (' attr(href) ')';
}

But what happens when you need to bring multilingual into the mix? We occasionally build multilingual sites, and typically there is translatable content at every level of the stack: Drupal nodes, template files, CSS, JS, you name it. When I was originally tasked with solving this it seemed like a big problem, but it turns out to be relatively simple.

My initial thought was to use the language attribute of html tag and make individual, static content properties, but that leads to code bloat as you accommodate each new language. Furthermore, in Drupal’s case, it leaves your strings stranded in CSS and inaccessible to translators which have an interface built into Drupal’s admin UI.

Solution: Dynamically generate attributes

We had a client who wanted the links to be big CTAs accompanied by the instructions “Download item.” So instead of hardcoding the English words into my stylesheet, I added a data-attribute into the DOM via JavaScript (you could also do this in Drupal by creating or modifying the appropriate field.tpl.php, but I did some other things with JS so it was simpler to keep it all in one file).

$('.my-field').attr('data-cta-msg', Drupal.t('Download item'));

Notice Drupal.t in there? t is for translate, and it is the standard mechanism for localizing JS-powered UI components in Drupal 6, Drupal 7, and Drupal 8. There’s a bit of background magic that happens, but in a nutshell once a page containing your new Drupal.t() string has been loaded, you can access it in the Translate interface in the Drupal admin UI:

Drupal 7 interface for translating non-content/UI strings

Now you can grab a translator, add the appropriate text, and your stylesheet will always supply the correct translation in your CSS generated content! Look at the minor modification to CSS content property (compare to the very first example in this article)

a:before {
  content: attr(data-cta-msg);
}

And here’s the result in English and Arabic respectively:

English download button with CSS generated content

Arabic download button with CSS generated content

Update: Down in the comments Dan Mouyard pointed out how any CSS generated content is less accessible than real markup. Just a heads up for general use of CSS content that is intended to be read aloud on the page, not just the multilingual method described in this article.

Commenting on this Blog post is closed.

A better way to theme Field Collections

Field collections are at the same time one of my most favorite and least favorite aspects of working with Drupal 7. Since they are entities they can be extremely powerful and flexible site building tools, and I see lots of unrealized potential in that, on the other hand theming can be tricky and, for lack of better word, generally feels “icky.” There is little documentation online about best practices with almost all links pointing back to this thread on how to theme field collections. The proposed solutions in this thread are a mixed bag — mostly bad — but some that may work, but they certianly don’t follow any best practices in drupal theming. I’ll admit I have shipped field collection theming that, while working, did make me feel “dirty.” Below was a clean solution that — while simple — is maintainable and, hopefully easy to follow.

I created a quick function that pulled out the themed items from the field collection and organized them into an easy to theme array. The theming then felt a lot more natural, like working with a views rows template.

<?php
/**
 * Creates a simple text rows array from a field collections, to be used in a
 * field_preprocess function.
 *
 * @param $vars
 *   An array of variables to pass to the theme template.
 *
 * @param $field_name
 *   The name of the field being altered.
 *
 * @param $field_array
 *   Array of fields to be turned into rows in the field collection.
 */
 
function rows_from_field_collection(&$vars, $field_name, $field_array) {
  $vars['rows'] = array();
  foreach($vars['element']['#items'] as $key => $item) {
    $entity_id = $item['value'];
    $entity = field_collection_item_load($entity_id);
    $wrapper = entity_metadata_wrapper('field_collection_item', $entity);
    $row = array();
    foreach($field_array as $field){
      $row[$field] = $wrapper->$field->value();
    }
    $vars['rows'][] = $row;
  }
 }
}

In this function we pull in the “variables” array from the field template, the field name and an array of fields that we want to extract, and then load them into our own rows array which gets attached to the variables array for use in our template. It uses the entity_metadata_wrapper that is like a swiss army knife of sanity and clean code for Drupal 7. If you aren’t familar with it, start with this documentation page about entity metadata wrappers, and follow up with some quick googling. It’ll make you and your code happy.

Below is the function being called and our custom field template being established. One thing that keeps our code simple is that all fields in the field collection are required eliminating the need to check for the variables existence in the template.

<?php
function THEME_preprocess_field(&$vars, $hook){
  if ($vars['element']['#field_name'] == 'field_achievements') {
    $vars['theme_hook_suggestions'][] = 'field__achievements_collected';
 
    $field_array = array('field_award', 'field_award_presenter','field_year');
    rows_from_field_collection($vars, 'field_achievements', $field_array);
  }
}

Finally below is the field template.

<?php
/**
 *  Field formatter for the field_achievements field collection.
 */
?>
<dl>
  <?php foreach($rows as $row): ?>
    <dt><?php print $row['field_award']; ?></dt>
    <dd><?php print $row['field_award_presenter']; ?></dd>
    <dd><?php print $row['field_year']; ?></dd>
  <?php endforeach; ?>
</dl>

We had a number of fields that were just sets of text data that needed to be output in definition lists. The function could be easily modifed to render the fields instead of just the values by using entity_view(). Next steps for this approach would be to refactor to use entity info to get the fields so that it can be generic and would no longer require the need to pass in the fields that you want.

There is hope for theming within the module itself. There is a promising issue in the queue that looks like it makes the native theming more sane. Since it’s such a big change it doesn’t look likely that it’ll make it into the 1.0 branch, so we may need to wait for the next version before it drops. Perhaps there is space for an add-on contrib module that cleans up the theming.

Commenting on this Blog post is closed.

Magic: Frontend Performance for all themes

Howdy perfers!

This week’s Webperf Wednesday is short and sweet, just like your page loads when you install this new module that enhances any Drupal theme. Magic is a set of frontend performance and development workflow tools for themers. Previously many themes had their own advanced settings — many of which did the same things as other themes, but they all did it a little differently — no more with Magic.

Built by Web Chef Ian Carrico and Sam Richard (of Aurora) with contributions from Sebastian Siemssen (of Omega), Magic was built by the desire to work together to make all themes better, instead of siloing improvements within specific themes.

What’s inside?

Performance features:

  • Enhancements to CSS Aggregation
  • Exclude CSS files from being included
  • Option to move JavaScript to the footer
  • Backport of Drupal 8 JavaScript handling
  • Exclude JS files from being included

Development goodies

  • Rebuild Theme Registry on Page Reload
  • Display a Viewport Width indicator
  • Display an indicator with classes applied to the HTML. Useful when used in conjunction with Modernizr
  • Export theme settings

That last one is super important, as it makes Drupal themes a little more DRY. With Magic, you can take your settings from one theme to another — or to another site completely — because they’re fully exportable. Have two different projects, and want similar asset output despite one being Omega and one being Zen? No problem, just export!

Note: the full import process has yet to land, but it’s coming very soon.

If you have an awesome trick that you always rely on during theming, open an issue and propose it to Magic. They’d love to hear from you.

Give it a shot today! Go to drupal.org/project/magic

Commenting on this Blog post is closed.

DrupalCon Portland: Mobile Roundup

DrupalCon is coming! In just a little over a month, our Drupal community will meet in Portland to learn what’s new in the web and Drupal. I have already begun checking out the schedule to find some of the best frontend talks.

Sessions

Sam Richard (@snugug) and Mason Wendell (@codingdesigner) are giving a talk on how to develop a responsive site with Sass and Breakpoint. I have had the pleasure of working with both of these guys with the work for Team Sass, and look forward to their session about the changes with Breakpoint.

Josh Riggs (@joshriggs) will be showing the Zen of HTML Prototyping and Designing in the Browser. This is especially important for ensuring the proper mobile design is ready for the client. We have been designing within the browser over the past year at Four Kitchens and are excited to see what other companies have been doing with it.

Vadim Mirgorod (@dealancer) has a session to Integrate Backbone.js into Drupal 7 and 8. We have already begun to use Backbone.js to create some awesome mobile and responsive apps at Four Kitchens, and I am exited to learn new ways to integrate it into a Drupal site.

Jared Ponchot (@jponch) of Lullabot will have a session about Designing for the responsive age we live in. I look forward to seeing some tips and tricks I can apply to our design process here at Four Kitchens, and possibly better ways of thinking of responsive design.

Training

Want to start DrupalCon off running, and get a full-day responsive training? Chris Ruppel, Sam Richard and I are offering Advanced Responsive Web Design with Sass + Compass on May 20th. This shouldn’t be missed for anybody who wants to learn about how to properly implement a responsive design, and the tools to use to make your life easier.

Commenting on this Blog post is closed.