Web Wash: How to Control Summary Text using Smart Trim in Drupal 7

Planet Drupal - Tue, 2015/03/31 - 10:36am

The "Long text and summary" field has a pretty handy formatter called "Summary or trimmed". This will display a summary, if one is supplied, or Drupal will simply trim the text and display it.

The problem with this formatter is that you can't trim the summary. For example, if an editor adds three paragraphs into the summary section, then the whole summary is shown. But sometimes you may need control over how much of the summary is displayed. This is especially true if your design requires the teaser to have a consistent height.

What's the best way of offering a summary to your editors that also trims it? Enter Smart Trim.

The Smart Trim module is an improved version of the "Summary or Trimmed" formatter and a whole lot more. It does a lot of useful stuff, but the one we want to discuss is the ability to trim summaries.

Categories:

Drupal core announcements: Drupal 7 core release on Wednesday, April 1

Planet Drupal - Tue, 2015/03/31 - 8:32am
Start:  2015-04-01 (All day) America/New_York Online meeting (eg. IRC meeting) Organizers:  David_Rothstein

The monthly Drupal core bug fix/feature release window is this Wednesday, April 1, and since it has been a while since the last one, I plan to release Drupal 7.36 on that date.

The final patches for 7.36 have been committed and the code is frozen (excluding documentation fixes and fixes for any regressions that may be found in the next couple days). So, now is a wonderful time to update your development/staging servers to the latest 7.x code and help us catch any regressions in advance.

There are three relevant change records for Drupal 7.36 which are listed below. This is not the full list of changes, rather only a list of notable API additions and other changes that might affect a number of other modules, so it's a good place to start looking for any problems:

You might also be interested in the tentative CHANGELOG.txt for Drupal 7.36 and the corresponding list of important issues that will be highlighted in the Drupal 7.36 release notes.

If you do find any regressions, please report them in the issue queue. Thanks!

Upcoming release windows after this week include:

  • Wednesday, April 15 (security release window)
  • Wednesday, May 6 (bug fix/feature release window)

For more information on Drupal core release windows, see the documentation on release timing and security releases, and the discussion that led to this policy being implemented.

Categories:

Chen Hui Jing: Drupal 101: Mapping with Leaflet and IP Geolocation

Planet Drupal - Tue, 2015/03/31 - 2:00am

Store locators are a useful functionality for businesses who have multiple outlets. Drupal has a number of map rendering modules that allow us to provide store locator functionality. This article will cover the basics of setting up a simple store locator with proximity search functionality.

Create and setup location content type

Required modules

  1. Install the required modules. drush dl addressfield geocoder geofield geophp ctools -y
  2. Enable the required modules. drush en addressfield geocoder geofield geofield_map...
Categories:

Drupal for Government: Govermenty forms even more governmenty with FillPDF and Rules

Planet Drupal - Mon, 2015/03/30 - 9:08pm

When working with government agencies the sacred form may raise it's fugly formatted head now and again.  Despite attempts at logic "Wouldn't an XLS spreadsheet be easier for everyone?" it sometimes comes down to what's simpler - gettin' er done vs doin' it right.... and if no one really cares about doin' it right, gettin' er done becomes the (sloppy) way, (half)truth, and (dim) light....

So yeah - I had a form that needed to be pixel perfect so that a state-wide agency could print the forms up and store them in a manilla folder... I started working with Views PDF.  This did generate pdf's... and along with mimemail and rules we were sending PDF's out... but they just weren't looking like folks wanted them... FillPDF - thank you.

To use FillPDF we started by installing pdftk (apt-get install pdftk on ubuntu) and then installing the module as per usual....  here's the rest step-by-step 

Categories:

Drupal Association News: Clever Ways to Raise Funds for D8 Accelerate

Planet Drupal - Mon, 2015/03/30 - 6:53pm

What’s the most clever way to raise funds for Drupal? Ask Ralf Hendel of Comm Press in Hamburg Germany.

The Drupal Association is working with the Drupal 8 branch maintainers to provide $250,000 in Drupal 8 Acceleration Grants that will be awarded to individuals and groups, helping them get Drupal 8 from beta to release.

Now The Association needs to raise the funds to support the grants and we are working with the Association Board to kick off a D8 Accelerate fundraiser. We are asking community members to help out and donate here. We all want to get D8 released so we can enjoy all the launch parties!

The good news is that we only need to raise $125,000 as a community because all donations will be matched! The Association contributed $62,500 and the Association Board raised another $62,500 from Anchor Donors: Acquia, Appnovation, Drupalize.me by Lullabot, Palantir.net, Phase2, PreviousNext, and Wunderkraut.

Having Anchor Partners means…
Every dollar you donate is matched, doubling your impact.

Ralf Hendel, CEO of Comm Press, heard the call and took action in the most creative way. Over the last few years, Ralf learned how to play the piano (very well I might add) and he recently held a benefit recital where he played Bach, Schubert, and Skrjabin. Those attending were asked to donate to D8 Accelerate and together they raised €345. Of course, with the matching funds from our Anchor Partners, that contribution is €690.

At The Drupal Association, we are always amazed at the many talents our community has and we are especially thankful to Ralf for sharing his passion for music and Drupal with others and raising these funds.

There’s so many clever ways to raise funds to help D8 get across the finish line. What ideas do you have? Or if feel like going the traditional route, you can donate here.

Thanks for considering this opportunity to get Drupal 8 released sooner. If you would like to learn more about how D8 Accelerate grants are being given out, please read Angie Byron’s blog post.

Categories:

Drupalpress, Drupal in the Health Sciences Library at UVA: equipment booking system — managing reservation conflicts with field validation and EntityFieldQuery()

Planet Drupal - Mon, 2015/03/30 - 4:26pm

The first requirement of a registration system is to have something to reserve.

The second requirement of a registration system is to manage conflicting reservations.

Setting up validation of submitted reservations based on the existing reservation nodes was probably the most complex part of this project. A booking module like MERCI has this functionality baked in — but again, that was too heavy for us so we had to do it on our own. We started off on a fairly thankless path of Views/Rules integration. Basically we were building a view of existing reservations, contextually filtering that view by content id (the item that someone was trying to reserve) and then setting a rule that would delete the content and redirect the user to a “oops that’s not available” page. We ran into issues building the view contextually with rules (for some reason the rule wouldn’t pass the nid …) and even if we would have got that wired up, it would have been clunky.

Scrap that.

On to Field Validation.

The Field Validation module offers client-side form validation (not to be confused with Clientside Validation or Webform Validation based on any number of conditions at the field level. We were trying to validate the submitted reservation on length (no longer than 5 days) and availability (no reservations of the same item during any of the days requested).

The length turned out to be pretty straightforward — we set the “Date range2″ field validator on the reservation date field. The validator lets you choose “global” date format, which means you can input logic like “+ X days” so long as it can be converted by the strtotime() function.

 

Field Validation also gives you configurations to bypass the validation criteria by role — this was helpful in our case given that there are special circumstances when “approved” reservations can be made for longer than 5 days. And if something doesn’t validate, you can plug in a custom error message in the validator configuration.

 

With the condition set for the length of the reservation, we could tackle the real beast. Determining reservation conflicts required us to use the “powerfull [sic] but dangerous” PHP validator from Field Validation. Squirting custom code into our Drupal instance is something we try to avoid as much as possible — it’s difficult to maintain … and as you’ll see below it can be difficult to understand. To be honest, a big part of the impetus for writing this series of blog posts was to document the 60+ lines of code that we strung together to get our booking system to recognize conflicts.

The script starts by identifying information about the item that the patron is trying to reserve  (item = $arg1, checkout date = $arg2, return date = $arg3) and then builds an array of dates from the start to finish of the requested reservation. Then we use EntityFieldQuery() to find all of the reservations that have dates less than or equal to the end date request. That’s where we use the fieldCondition() with <= to the $arg3_for_fc value. What that gives us is all of the reservations on that item that could possibly conflict. Then we sort by descending and trim the top value out of the list to get the nearest reservation to the date requested. With that record in hand, we can build another array of start and end dates and use array_intersetct() to see if there is any overlap.

I bet that was fun to read.

I’ll leave you with the code and comments:

<?php //find arguments from nid and dates for the requested reservation $arg1 = $this->entity->field_equipmentt_item[und][0][target_id]; $arg2 = $this->entity->field_reservation_date[und][0][value]; $arg2 = new DateTime($arg2); $arg3 = $this->entity->field_reservation_date[und][0][value2]; $arg3 = new DateTime($arg3); $arg3_for_fc = $arg3->format("Ymd"); //build out array of argument dates for comparison with existing reservation $beginning = $arg2; $ending = $arg3; $ending = $ending->modify( '+1 day' ); $argumentinterval = new DateInterval('P1D'); $argumentdaterange = new DatePeriod($beginning, $argumentinterval ,$ending); $arraydates = array(); foreach($argumentdaterange as $argumentdates){ $arraydates []= $argumentdates->format("Ymd"); } //execute entityfieldquery to find the most recent reservation that could conflict $query = new EntityFieldQuery(); $fullquery = $query->entityCondition('entity_type', 'node') ->entityCondition('bundle', 'reservation') ->propertyCondition('status', NODE_PUBLISHED) ->fieldCondition('field_equipmentt_item', 'target_id', $arg1, '=') ->fieldCondition('field_reservation_date', 'value', $arg3_for_fc, '<=') ->fieldOrderBy('field_reservation_date', 'value', 'desc') ->range(0,1); $fetchrecords = $fullquery->execute(); if (isset($fetchrecords['node'])) { $reservation_nids = array_keys($fetchrecords['node']); $reservations = entity_load('node', $reservation_nids); } //find std object for the nearest reservation from the top $reservations_test = array_slice($reservations, 0, 1); //parse and record values for dates $startdate = $reservations_test[0]->field_reservation_date[und][0][value]; $enddate = $reservations_test[0]->field_reservation_date[und][0][value2]; //iterate through to create interval date array $begin = new DateTime($startdate); $end = new DateTime($enddate); $end = $end->modify( '+1 day' ); $interval = new DateInterval('P1D'); $daterange = new DatePeriod($begin, $interval ,$end); $arraydates2 = array(); foreach($daterange as $date){ $arraydates2 []= $date->format("Ymd"); } $conflicts = array_intersect($arraydates, $arraydates2); if($conflicts != NULL){ $this->set_error(); } ?>
Categories:

Yuriy Babenko: Adding custom contexts to UDFs in Acquia Lift

Planet Drupal - Mon, 2015/03/30 - 3:55am

Within the Lift ecosystem, "contexts" can be thought of as pre-defined functionality that makes data available to the personalization tools, when that data exists in the current state (of the site/user/environment/whatever else).

Use cases

The simplest use of contexts is in mapping their data to UDF fields on /admin/config/content/personalize/acquia_lift_profiles. When the context is available, its data is assigned to a UDF field and included with Lift requests. For example, the Personalize URL Context module (part of the Personalize suite) does exactly this with query string contexts.

First steps

The first thing to do is to implement hook_ctools_plugin_api() and hook_personalize_visitor_contexts(). These will make the Personalize module aware of your code, and will allow it to load your context declaration class.

Our module is called yuba_lift:

/**
 * Implements hook_ctools_plugin_api();
 */
function yuba_lift_ctools_plugin_api($owner, $api) {
  if ($owner == 'personalize' && $api == 'personalize') {
    return array('version' => 1);
  }
}

/**
 * Implements hook_personalize_visitor_contexts();
 */
function yuba_lift_personalize_visitor_context() {
  $info = array();
  $path = drupal_get_path('module', 'yuba_lift') . '/plugins';

  $info['yuba_lift'] = array(
    'path' => $path . '/visitor_context',
    'handler' => array(
      'file' => 'YubaLift.inc',
      'class' => 'YubaLift',
    ),
  );

  return $info;
}

The latter hook tells Personalize that we have a class called YubaLift located at /plugins/visitor_context/YubaLift.inc (relative to our module's folder).

The context class

Our context class must extend the abstract PersonalizeContextBase and implement a couple required methods:

<?php
/**
 * @file
 * Provides a visitor context plugin for Custom Yuba data.
 */

class YubaLift extends PersonalizeContextBase {
  /**
   * Implements PersonalizeContextInterface::create().
   */
  public static function create(PersonalizeAgentInterface $agent = NULL, $selected_context = array()) {
    return new self($agent, $selected_context);
  }

  /**
   * Implements PersonalizeContextInterface::getOptions().
   */
  public static function getOptions() {
    $options = array();

    $options['car_color']   = array('name' => t('Car color'),);
    $options['destination'] = array('name' => t('Destination'),);

    foreach ($options as &$option) {
      $option['group'] = t('Yuba');
    }

    return $options;
  }
}

The getOptions method is what we're interested in; it returns an array of context options (individual items that can be assigned to UDF fields, among other uses). The options are grouped into a 'Yuba' group, which will be visible in the UDF selects.

With this code in place (and cache cleared - for the hooks above), the 'Yuba' group and its context options become available for mapping to UDFs.

Values for options

The context options now need actual values. This is achieved by providing those values to an appropriate JavaScript object. We'll do this in hook_page_build().

/**
 * Implements hook_page_build();
 */
function yuba_lift_page_build(&$page) {
  // build values corresponding to our context options
  $values = array(
    'car_color' => t('Red'),
    'destination' => t('Beach'),
  );

  // add the options' values to JS data, and load separate JS file
  $page['page_top']['yuba_lift'] = array(
    '#attached' => array(
      'js' => array(
        drupal_get_path('module', 'yuba_lift') . '/js/yuba_lift.js' => array(),
        array(
          'data' => array(
            'yuba_lift' => array(
              'contexts' => $values,
            ),
          ),
          'type' => 'setting'
        ),
      ),
    )
  );
}

In the example above we hardcoded our values. In real use cases, the context options' values would vary from page to page, or be entirely omitted (when they're not appropriate) - this will, of course, be specific to your individual application.

With the values in place, we add them to a JS setting (Drupal.settings.yuba_lift.contexts), and also load a JS file. You could store the values in any arbitrary JS variable, but it will need to be accessible from the JS file we're about to create.

The JavaScript

The last piece of the puzzle is creating a new object within Drupal.personalize.visitor_context that will implement the getContext method. This method will look at the enabled contexts (provided via a parameter), and map them to the appropriate values (which were passed via hook_page_build() above):

(function ($) {
  /**
   * Visitor Context object.
   * Code is mostly pulled together from Personalize modules.
   */
  Drupal.personalize = Drupal.personalize || {};
  Drupal.personalize.visitor_context = Drupal.personalize.visitor_context || {};
  Drupal.personalize.visitor_context.yuba_lift = {
    'getContext': function(enabled) {
      if (!Drupal.settings.hasOwnProperty('yuba_lift')) {
        return [];
      }

      var i = 0;
      var context_values = {};

      for (i in enabled) {
        if (enabled.hasOwnProperty(i) && Drupal.settings.yuba_lift.contexts.hasOwnProperty(i)) {
          context_values[i] = Drupal.settings.yuba_lift.contexts[i];
        }
      }
      
      return context_values;
    }
  };

})(jQuery);

That's it! You'll now see your UDF values showing up in Lift requests. You may also want to create new column(s) for the custom UDF mappings in your Lift admin interface.

You can grab the completed module from my GitHub.

Tagsdrupal planetdrupaldrupal 7liftpersonalization
Categories:

Chen Hui Jing: The one without sleep

Planet Drupal - Mon, 2015/03/30 - 2:00am

So I recently participated in my first ever hackathon over the weekend of March 28. Battlehack Singapore to be exact (oddly, there was another hackathon taking place at the same time). A UX designer friend of mine had told me about the event and asked if I wanted to join as a team.
Me: Is there gonna be food at this thing?
Her: Erm…yes.
Me: Sold!
Joking aside, I’d never done a hackathon before and thought it’d be fun to try. We managed to recruit another friend and went as a team of three.

The idea

The theme of the hackathon was to solve a local...

Categories:

Paul Rowell: My journey in Drupal, 4 years on

Planet Drupal - Sun, 2015/03/29 - 10:38pm

I’m approaching the 4 year mark at my agency and along with it my 4 year mark working with Drupal. It’s been an interesting journey so far and I’ve learned a fair bit, but, as with anything in technology, there’s still a great deal left to discover. This is my journey so far and a few key points I learned along the way.

Categories:

Victor Kane: Getting Started with a Real World Application on platform.sh

Planet Drupal - Sun, 2015/03/29 - 8:20pm

This is the second in a series of articles involving the writing and launching of my DurableDrupal Lean ebook series website on platform.sh. Since it's a real world application, this article is for real world website and web application developers. If you are starting from scratch but enthusiastic and willing to learn, that means you too. I'm fortunate enough to have their sponsorship and full technical support, so everything in the article has been tested out on the platform. A link will be edited in here as soon as it goes live.

Diving in

Diving right in I setup a Trello Kanban Board for Project Inception as follows:

Both Vision (Process, Product) and Candidate Architecture (Process, Product) jobs have been completed, and have been moved to the MVP 1 column. We know what we want to do, and we're doing it with Drupal 7, based on some initial configuration as a starting point (expressed both as an install profile and a drush configuration script). At this point there are three jobs in the To Do column, constituting the remaining preparation for the Team Product Kickoff. And two of them (setup for continuous integration and continuous delivery) are about to be made much easier by virtue of using platform.sh, not only as a home for the production instance, but as a central point of organization for the entire development and deployment process.

Beginning Continuous Integration Workflow

What we'll be doing in this article:

read more

Categories:

Drupal @ Penn State: Improve User Experience by Ajaxing Your Drupal Forms

Planet Drupal - Sun, 2015/03/29 - 1:02pm

Drupal's Form API has everything that we love about the Drupal framework. It's powerful, flexible, and easily extendable with our custom modules and themes. But lets face it; it's boooorrrrriinnnnggg. Users these days are used to their browsers doing the heavy lifting. Page reloads are becoming fewer and fewer, especially when we are expecting our users to take action on our websites. If we are asking our visitors to take time out of their day to fill out a form on our website, that form should be intuitive, easy to use, and not distracting.

Categories:

Code Karate: Module Investigator: Fixing an issue in the Drupal Subuser module

Planet Drupal - Sun, 2015/03/29 - 4:09am
Episode Number: 199

In the last episode, we learned about the Drupal Subuser module. In this episode, we continue where we left off but take a look under the hood at the module code of the Drupal Subuser module.

By following along with this episode you will learn some things such as:

Tags: DrupalDrupal 7Module DevelopmentModule InvestigatorDrupal Planet
Categories:

Blue Drop Shop: Camp Record Beta Test Three: MidCamp 2015

Planet Drupal - Sat, 2015/03/28 - 9:08pm

After my #epicfail that was BADCamp, to say that I was entering MidCamp with trepidation would be the understatement of the year. Two full days of sessions and a 1-and-1 track record was weighing heavily upon my soul. Add to the mix that I was coming directly off of a 5-day con my company runs, and responsible for MidCamp venue and catering logistics. Oh right, and I ran out of time to make instructions and train anyone else on setup, which only added to my on-site burden.

Testing is good.

After BADCamp, I added a powered 4-port USB hub to the kits, as well as an accessory pack for the H2N voice recorder, mainly for the powered A/C adapter and remote. All total, these two items bring the current cost of the kit to about $425.

In addition, at one of our venue walk-throughs, I was able to actually test the kits with the projectors UIC would be using. The units in two of the rooms had an unexplainable random few-second blackout of the screens, but the records were good and the rest of the rooms checked out.

Success.

After the mad scramble setting up three breakout rooms and the main stage leading up to the opening keynote, I can't begin to describe the feeling in the pit of my stomach after I pulled the USB stick after stopping the keynote recording. I can’t begin to describe the elation I felt after seeing a full record, complete with audio.

We hit a few snags with presenters not starting their records (fixable) and older PCs not connecting (possibly fixable), and a couple sessions that didn’t have audio (hello redundancy from the voice recorder). Aside from that, froboy and I were able to trim and upload all the successful records during the Sunday sprint.

A huge shout out also goes to jason.bell for helping me on-site with setups and capture. He helped me during Fox Valley’s camp, so I deputized him as soon as I saw him Friday morning.

Learnings.

With the addition of the powered USB hub, we no longer need to steal any ports from the presenter laptop. For all of the first day, we were unnecessarily hooking up the hub’s USB cable to the presenter laptop. Doing this caused a restart of the record kit. We did lose a session to a presenter laptop going to sleep, and I have to wonder whether we would have still captured it if the hub hadn’t been attached.

The VGA to HDMI dongle is too unreliable to be part of the kit. When used, either there was no connection, or it would cycle between on and off. Most, if not all, machines that didn’t have mini display port or direct HMDI out had full display port. I will be testing a display port to HDMI dongle for a more reliable option.

Redundant audio is essential. The default record format for the voice recorders is a WAV file. These are best quality, but enormous, which is why I failed at capturing most of BADCamp’s audio (RTFM, right?). By changing the settings to 192kbs MP3, two days of session audio barely made a dent in the 2GB cards that are included with the recorders. Thankfully, this saved three session records: two with no audio at all (still a mystery) and one with blown out audio.

Trimming and combining in YouTube is a thing. Kudos again to froboy for pointing me to YouTube’s editing capabilities. A couple sessions had split records (also a mystery), which we then stitched together after upload, and several sessions needed some pre- or post-record trimming. This can all be done in YouTube instead of using a video editor and re-encoding. Granted, YouTube takes what seems like forever to process, but it works and once you do the editing, you can forget about it.

There is a known issue with mini display port to HDMI where a green tint is added to the output. Setting the external PVR to 720p generally fixed this. There were a couple times where it didn’t, but switching either between direct HDMI or mini display port to HDMI seemed to resolve most of the issues. Sorry for the few presenters that opted for funky colors before we learned this during the camp. The recording is always fine, but the on-site experience is borked.

Finally, we need to tell presenters to adjust their energy saver settings. I take this for granted, because the con my company runs is for marketing people who present frequently, and this is basically just assumed to be set correctly. We are a more casual bunch and don’t fret when the laptop sleeps or the screen saver comes up during a presentation. Just move the cursor and roll with it. But that can kill a record...even with the Drupal Association kits. I do plan to test this, now that I’ve learned we don’t need any power at all from the presenter laptop, but it’s still an easy fix with documentation.

Next steps.

Documentation. I need to make simple instructions sheets to include with the kits. Overall, they are really easy to use and connect, but it’s completely unfamiliar territory. With foolproof instructions, presenters can be at ease and room monitors can be tasked with assisting without fear.

Packaging. With the mad dash to set these up — combined with hourly hookups — these were a hot mess on the podium. I’ll be working to tighten these up so they look less intimidating and take up less space. No idea what this entails yet, so I’ll gladly accept ideas.

Testing. As mentioned, I will test regular display port to HDMI, as well as various sleep states while recording.

Shipping. Because these kits are so light weight, part of the plan is to be able to share them with regional camps. There was a lot of interest from other organizers in these kits during the camp. Someone from Twin Cities even offered to purchase a kit to add to the mix, as long as they could borrow the others. A Pelican box with adjustable inserts would be just the ticket.

Sponsors. If you are willing to help finance this project, please contact me at kthull@bluedropshop.com. While Fox Valley Camp owns three kits and MidCamp owns one, wouldn’t it be great to have your branding on these as they make their way around the camp circuit? The equipment costs have (mostly) been reimbursed, but I’ve devoted a lot of time to testing and documenting the process, and will be spending more time with the next steps listed above.

Tags:
Categories:

Amazee Labs: Drupal Camp Johannesburg 2015

Planet Drupal - Sat, 2015/03/28 - 8:52pm
Drupal Camp Johannesburg 2015

Today I had the pleasure to attend Johannesburg's Drupal Camp 2015.

The event was organized by DASA that is doing a stunning job in gathering and energizing South Africa's Drupal Community. From community subjects to Drupal 8, we got to see a lekker variety of talks including those by Michael and me on "Drupal 8" and "How to run a successful Drupal Shop".

Special thanks to the organizers Riaan, Renate, Adam, Greg and Robin. Up next will be Drupal Camp Cape Town in September 2015.

Categories:

DrupalOnWindows: Adding native JSON storage support in Drupal 7 or how to mix RDBM with NoSQL

Planet Drupal - Sat, 2015/03/28 - 6:45pm
Language English

I rencently read a very interesting article of an all time .Net developer comparing the MEAN stack (Mongo-Express-Angluar-Node) with traditional .Net application design. (I can't post the link because I'm unable to find the article!!).

Among other things he compared the tedious process of adding a new field in the RDBM model (modifying the database, then the data layer, then views and controllers), whereas in the MEAN stack it was as simple as adding two lines of code to the UI.

More articles...
Categories: