View source
<?php
define('RECIPE_BLOCK_SUMMARY', 1);
function recipe_help($path, $arg) {
switch ($path) {
case 'admin/structure/recipe':
$output = '<p>' . t('You can enable/disable bulk export formats on the <a href="@modules-page">modules page</a> in the recipes section.', array(
'@modules-page' => url('admin/modules', array(
'fragment' => 'edit-modules-recipe',
)),
)) . '</p>';
return $output;
case 'admin/structure/recipe/import_multi':
$output = '<p>' . t('You can enable/disable bulk import formats on the <a href="@modules-page">modules page</a> in the recipes section.', array(
'@modules-page' => url('admin/modules', array(
'fragment' => 'edit-modules-recipe',
)),
)) . '</p>';
return $output;
case 'admin/config/content/recipe':
return t('Configure the management and display of recipes.');
}
}
function recipe_theme($existing, $type, $theme, $path) {
return array(
'recipe_landing_page' => array(
'file' => 'recipe.landing.page.inc',
),
'ingredients_form' => array(
'render element' => 'form',
),
'recipe_summary' => array(
'function' => 'theme_recipe_summary',
'variables' => array(
'node' => NULL,
'show_title' => TRUE,
),
),
'recipe_duration' => array(
'variables' => array(
'duration' => 0,
),
),
'recipe_ingredient' => array(
'variables' => array(
'name' => NULL,
'quantity' => 0,
'unit' => array(),
'note' => '',
'link' => 0,
),
),
);
}
function recipe_permission() {
return array(
'export recipes' => array(
'title' => t('Export recipes'),
'description' => t('Export recipes in various formats.'),
),
'import recipes' => array(
'title' => t('Import recipes'),
'description' => t('Import recipes in various formats.'),
),
);
}
function recipe_load($nodes) {
$result = db_query('SELECT * FROM {recipe} WHERE nid IN (:nids)', array(
':nids' => array_keys($nodes),
));
foreach ($result as $record) {
$nodes[$record->nid]->recipe_yield = $record->yield;
$nodes[$record->nid]->recipe_yield_unit = $record->yield_unit;
}
}
function recipe_node_info() {
return array(
'recipe' => array(
'name' => t('Recipe'),
'base' => 'recipe',
'description' => t('Share your favorite recipes with your fellow cooks.'),
),
);
}
function recipe_insert($node) {
db_insert('recipe')
->fields(array(
'nid' => $node->nid,
'yield' => $node->recipe_yield,
'yield_unit' => $node->recipe_yield_unit,
))
->execute();
}
function recipe_update($node) {
db_update('recipe')
->fields(array(
'yield' => $node->recipe_yield,
'yield_unit' => $node->recipe_yield_unit,
))
->condition('nid', $node->nid)
->execute();
}
function recipe_node_update($node) {
if ($node->type == 'ingredient') {
db_query("UPDATE {recipe_ingredient} SET link = :link WHERE LOWER(name) = :name", array(
':link' => $node->nid,
':name' => trim(strtolower($node->title)),
));
}
}
function recipe_node_insert($node) {
if ($node->type == 'ingredient') {
recipe_node_update($node);
}
}
function recipe_load_ingredient($iid) {
$result = db_query("SELECT id AS iid, name, link FROM {recipe_ingredient} WHERE id = :iid", array(
':iid' => $iid,
))
->fetchObject();
return $result;
}
function recipe_delete($node) {
db_query("DELETE FROM {recipe} WHERE nid = :nid", array(
':nid' => $node->nid,
));
}
function recipe_form($node, &$form_state) {
$form['title'] = array(
'#type' => 'textfield',
'#title' => t('Title'),
'#required' => TRUE,
'#default_value' => !empty($node->title) ? $node->title : '',
'#maxlength' => 255,
);
$form['recipe_yield'] = array(
'#type' => 'textfield',
'#title' => t('Yield'),
'#default_value' => !empty($node->recipe_yield) ? $node->recipe_yield : '',
'#size' => 4,
'#maxlength' => 4,
'#description' => t('The number of servings the recipe will make (whole number integer, ie 5 or 6).'),
'#required' => TRUE,
);
$form['recipe_yield_unit'] = array(
'#type' => 'textfield',
'#title' => t('Yield Units'),
'#default_value' => empty($node->recipe_yield_unit) ? t('Servings') : $node->recipe_yield_unit,
'#size' => 16,
'#maxlength' => 64,
'#description' => t('The units for the yield field(ie servings, people, cans, cookies, etc).'),
'#required' => FALSE,
);
return $form;
}
function recipe_menu() {
$items['node/add/recipe/std'] = array(
'title' => 'Standard entry',
'weight' => 0,
'file path' => drupal_get_path('module', 'node'),
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['node/add/recipe/import'] = array(
'title' => 'Recipe Import',
'description' => 'Allows you to create a recipe by pasting various formats into a big text box.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'recipe_import_form',
),
'access callback' => 'recipe_import_myaccess',
'access arguments' => array(
'import recipes',
),
'file' => 'recipe.admin.inc',
'weight' => 1,
'type' => MENU_LOCAL_TASK,
);
$items['recipe'] = array(
'title' => 'Recipes',
'page callback' => 'recipe_landing_page',
'access arguments' => array(
'access content',
),
'file' => 'recipe.landing.page.inc',
);
$items['recipe/ingredient/autocomplete'] = array(
'title' => 'Ingredient autocomplete',
'page callback' => 'recipe_autocomplete_page',
'type' => MENU_CALLBACK,
'access arguments' => array(
'access content',
),
'file' => 'recipe.admin.inc',
);
$items['recipe/export'] = array(
'page callback' => 'recipe_export',
'type' => MENU_CALLBACK,
'access arguments' => array(
'access content',
),
'file' => 'recipe.pages.inc',
);
$items['admin/config/content/recipe'] = array(
'title' => 'Recipe',
'description' => 'Settings that control how the recipe module functions.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'recipe_admin_settings',
),
'access arguments' => array(
'administer site configuration',
),
'type' => MENU_NORMAL_ITEM,
'file' => 'recipe.admin.inc',
'weight' => 0,
);
$items['admin/structure/recipe'] = array(
'title' => 'Recipe bulk import/export',
'description' => 'Export/Import all recipes from this site to/from a supported format.',
'page callback' => 'recipe_export_multi',
'access callback' => 'recipe_export_multi_myaccess',
'access arguments' => array(
'administer site configuration',
),
'type' => MENU_NORMAL_ITEM,
'file' => 'recipe.admin.inc',
);
$items['admin/structure/recipe/export_multi'] = array(
'title' => 'Recipe bulk export',
'description' => 'Export all recipes from this site into a supported output format.',
'type' => MENU_DEFAULT_LOCAL_TASK | MENU_LOCAL_TASK,
);
$items['admin/structure/recipe/import_multi'] = array(
'title' => 'Recipe bulk import',
'description' => 'Import all recipes from this site into a supported output format.',
'page callback' => 'recipe_import_multi',
'access callback' => 'recipe_import_multi_myaccess',
'access arguments' => array(
'administer site configuration',
),
'type' => MENU_LOCAL_TASK,
'file' => 'recipe.admin.inc',
);
return $items;
}
function recipe_block_info() {
$blocks = array();
$blocks['summary'] = array(
'info' => t('Recipe summary'),
);
return $blocks;
}
function recipe_block_view($delta = '') {
$block = array();
switch ($delta) {
case 'summary':
if (user_access('access content')) {
if (arg(0) == 'node' && is_numeric(arg(1)) && (arg(2) == '' || arg(2) == 'view')) {
$node = node_load(arg(1));
if ($node->type == 'recipe') {
$block['subject'] = variable_get('recipe_summary_title', t('Summary'));
$block['content'] = theme('recipe_summary', array(
'node' => $node,
'show_title' => FALSE,
'show_yield_form' => TRUE,
));
return $block;
}
}
}
break;
}
}
function recipe_view($node, $view_mode) {
drupal_add_css(drupal_get_path('module', 'recipe') . '/recipe.css');
if ($view_mode == 'full' && node_is_page($node)) {
$breadcrumb = array();
$breadcrumb[] = l(t('Home'), NULL);
$breadcrumb[] = l(t('Recipes'), 'recipe');
drupal_set_breadcrumb($breadcrumb);
}
recipe_node_sanitize($node);
$node->recipe_yield = intval($node->recipe_yield);
$node->recipe_factor = 1;
if ($node->recipe_yield != 0 && isset($_POST['op'])) {
if ($_POST['op'] == t('Change')) {
$node->recipe_factor = $_POST['custom_yield'] / $node->recipe_yield;
$node->recipe_yield = $_POST['custom_yield'];
$_POST = array();
}
elseif ($_POST['op'] == t('Halve')) {
$node->recipe_factor = $_POST['custom_yield'] / 2 / $node->recipe_yield;
$node->recipe_yield = $_POST['custom_yield'] / 2;
$_POST = array();
}
elseif ($_POST['op'] == t('Double')) {
$node->recipe_factor = $_POST['custom_yield'] * 2 / $node->recipe_yield;
$node->recipe_yield = $_POST['custom_yield'] * 2;
$_POST = array();
}
elseif ($_POST['op'] == t('Reset')) {
$_POST = array();
}
}
elseif (isset($node->recipe_custom_yield)) {
$node->recipe_factor = $node->recipe_custom_yield / $node->recipe_yield;
$node->recipe_yield = $node->recipe_custom_yield;
}
if ($view_mode == 'teaser') {
return $node;
}
if (isset($node->in_preview) && $node->in_preview == 1) {
$node->recipe_show_yield_form = FALSE;
}
$node->content['recipe_summary_box'] = array(
'#markup' => theme('recipe_summary', array(
'node' => $node,
'show_yield_form' => isset($node->recipe_show_yield_form) ? $node->recipe_show_yield_form : TRUE,
)),
);
return $node;
}
function recipe_node_view($node, $view_mode) {
if (isset($node->in_preview) && $node->in_preview == 1) {
return;
}
if ($node->type == 'recipe' && $view_mode != 'rss' && $view_mode != 'teaser') {
$formats = module_invoke_all('recipeio', 'export_single');
$links = array();
foreach ($formats as $key => $format) {
$perm = isset($format['access arguments']) ? $format['access arguments'] : 'export recipes';
if (user_access($perm)) {
$links[$key] = array(
'title' => $format['format_name'],
'href' => "recipe/export/{$key}/{$node->nid}/" . $node->recipe_yield,
'attributes' => array(
'title' => $format['format_help'],
),
);
}
}
if (!empty($links)) {
array_unshift($links, array(
'title' => '<br/>' . t('Export to') . ':',
'html' => TRUE,
));
$node->content['links']['recipe'] = array(
'#theme' => 'links__recipe__node',
'#links' => $links,
'#attributes' => array(
'class' => array(
'links',
'inline',
),
),
);
}
}
}
function recipe_field_info() {
return array(
'ingredient_reference' => array(
'label' => t('Ingredient reference'),
'description' => t('This field stores a reference to a recipe ingredient.'),
'default_widget' => 'recipe_ingredient_autocomplete',
'default_formatter' => 'recipe_ingredient_default',
'settings' => array(
'ingredient_name_normalize' => 0,
),
'property_type' => 'ingredient_reference',
'property_callbacks' => array(
'recipe_metadata_field_ingredient_property_callback',
),
),
);
}
function recipe_field_settings_form($field, $instance, $has_data) {
$settings = $field['settings'];
$form = array();
switch ($field['type']) {
case 'ingredient_reference':
$form['ingredient_name_normalize'] = array(
'#type' => 'radios',
'#title' => t('Ingredient name normalization'),
'#default_value' => $settings['ingredient_name_normalize'],
'#options' => array(
t('Leave as entered'),
t('Convert to lowercase'),
),
'#description' => t('When recipes are entered, should ingredient names be converted to lowercase?'),
'#required' => TRUE,
);
break;
}
return $form;
}
function recipe_field_widget_info() {
return array(
'recipe_ingredient_autocomplete' => array(
'label' => t('Autocomplete ingredient widget'),
'field types' => array(
'ingredient_reference',
),
'settings' => array(
'default_unit' => '',
),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
'default value' => FIELD_BEHAVIOR_NONE,
),
),
);
}
function recipe_field_widget_settings_form($field, $instance) {
$settings = $instance['widget']['settings'];
$form['default_unit'] = array(
'#type' => 'select',
'#title' => t('Default unit type for ingredients'),
'#default_value' => $settings['default_unit'],
'#options' => recipe_unit_options(),
'#description' => t('The default unit for new ingredients on the recipe edit screen.'),
);
return $form;
}
function recipe_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
drupal_add_css(drupal_get_path('module', 'recipe') . '/recipe.css');
switch ($instance['widget']['type']) {
case 'recipe_ingredient_autocomplete':
$quantity = isset($items[$delta]['quantity']) ? preg_replace('/\\⁄/', '/', recipe_ingredient_quantity_from_decimal($items[$delta]['quantity'], '{%d} %d⁄%d', TRUE)) : '';
$element['quantity'] = array(
'#type' => 'textfield',
'#title' => t('Quantity'),
'#default_value' => $quantity,
'#size' => 8,
'#maxlength' => 8,
'#attributes' => array(
'class' => array(
'recipe-ingredient-quantity',
),
),
);
$element['unit_key'] = array(
'#type' => 'select',
'#title' => t('Unit'),
'#default_value' => isset($items[$delta]['unit_key']) ? $items[$delta]['unit_key'] : $instance['widget']['settings']['default_unit'],
'#options' => recipe_unit_options(),
'#attributes' => array(
'class' => array(
'recipe-ingredient-unit-key',
),
),
);
$ingredient = isset($items[$delta]['iid']) ? recipe_load_ingredient($items[$delta]['iid']) : array();
$element['name'] = array(
'#type' => 'textfield',
'#title' => t('Name'),
'#default_value' => isset($ingredient->name) ? $ingredient->name : '',
'#size' => 25,
'#maxlength' => 128,
'#autocomplete_path' => 'recipe/ingredient/autocomplete',
'#attributes' => array(
'class' => array(
'recipe-ingredient-name',
),
),
);
$element['note'] = array(
'#type' => 'textfield',
'#title' => t('Note'),
'#default_value' => isset($items[$delta]['note']) ? $items[$delta]['note'] : '',
'#size' => 40,
'#maxlength' => 255,
'#attributes' => array(
'class' => array(
'recipe-ingredient-note',
),
),
);
$element['#element_validate'] = array(
'recipe_ingredient_autocomplete_validate',
);
break;
}
return $element;
}
function recipe_ingredient_autocomplete_validate($element, &$form_state) {
if (empty($element['unit_key']['#value']) && !empty($element['name']['#value'])) {
form_error($element['unit_key'], t('You must choose a valid unit.'));
return;
}
$value = array();
if ($name = $element['name']['#value']) {
$field = field_widget_field($element, $form_state);
if ($field['settings']['ingredient_name_normalize'] == 1 && !preg_match('/®/', $name)) {
$name = trim(strtolower($name));
}
$value = array(
'quantity' => $element['quantity']['#value'],
'unit_key' => $element['unit_key']['#value'],
'iid' => recipe_ingredient_id_from_name($name),
'name' => $name,
'note' => $element['note']['#value'],
'_weight' => $element['_weight']['#value'],
);
}
form_set_value($element, $value, $form_state);
}
function recipe_field_is_empty($item, $field) {
if (!is_array($item) || empty($item['name'])) {
return TRUE;
}
return FALSE;
}
function recipe_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
switch ($field['type']) {
case 'ingredient_reference':
foreach ($items as $delta => $item) {
$items[$delta]['quantity'] = round(recipe_ingredient_quantity_from_fraction($item['quantity']), 6);
}
break;
}
}
function recipe_field_formatter_info() {
return array(
'recipe_duration' => array(
'label' => t('Recipe duration'),
'field types' => array(
'number_integer',
),
),
'recipe_ingredient_default' => array(
'label' => t('Default'),
'field types' => array(
'ingredient_reference',
),
'settings' => array(
'fraction_format' => t('{%d }%d⁄%d'),
'unit_abbreviation' => 0,
),
),
);
}
function recipe_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$element = array();
if ($display['type'] == 'recipe_ingredient_default') {
$element['fraction_format'] = array(
'#type' => 'textfield',
'#title' => t('Fractions display string'),
'#default_value' => $settings['fraction_format'],
'#size' => 35,
'#maxlength' => 255,
'#description' => t('How fractions should be displayed. Leave blank to display as decimals.<br />Each incidence of %d will be replaced by the whole number, the numerator, and the denominator in that order.<br />Anything between curly braces will not be displayed when the whole number is equal to 0.<br />Recommended settings are "{%d }%d&frasl;%d" or "{%d }<sup>%d</sup>/<sub>%d</sub>"'),
);
$element['unit_abbreviation'] = array(
'#type' => 'radios',
'#title' => t('Ingredient unit display'),
'#default_value' => $settings['unit_abbreviation'],
'#options' => array(
t('Abbreviation'),
t('Full name'),
),
'#description' => t('Display ingredient units like Tbsp or Tablespoon.'),
'#required' => TRUE,
);
}
return $element;
}
function recipe_field_formatter_settings_summary($field, $instance, $view_mode) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$summary = '';
if ($display['type'] == 'recipe_ingredient_default') {
$summary = t('Fractions display string: @fraction_format', array(
'@fraction_format' => $settings['fraction_format'],
)) . '<br />';
$summary .= t('Ingredient unit display: @unit_abbreviation', array(
'@unit_abbreviation' => $settings['unit_abbreviation'],
));
}
return $summary;
}
function recipe_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
drupal_add_css(drupal_get_path('module', 'recipe') . '/recipe.css');
$iids = array();
$ingredients = array();
$unit_list = recipe_get_units();
foreach ($entities as $id => $entity) {
if ($displays[$id]['type'] == 'recipe_ingredient_default') {
foreach ($items[$id] as $delta => $item) {
if (!isset($item['name']) && isset($item['iid'])) {
$iids[$item['iid']] = $item['iid'];
}
}
}
}
foreach ($iids as $iid) {
$ingredients[$iid] = recipe_load_ingredient($iid);
}
foreach ($entities as $id => $entity) {
$rekey = FALSE;
if ($displays[$id]['type'] == 'recipe_ingredient_default') {
foreach ($items[$id] as $delta => $item) {
if (isset($item['name'])) {
$items[$id][$delta]['link'] = '';
$items[$id][$delta]['unit'] = isset($unit_list[$item['unit_key']]) ? $unit_list[$item['unit_key']] : array();
}
elseif (isset($ingredients[$item['iid']])) {
$ingredient = $ingredients[$item['iid']];
$items[$id][$delta]['name'] = $ingredient->name;
$items[$id][$delta]['link'] = $ingredient->link;
$items[$id][$delta]['unit'] = isset($unit_list[$item['unit_key']]) ? $unit_list[$item['unit_key']] : array();
}
else {
unset($items[$id][$delta]);
$rekey = TRUE;
}
}
}
if ($rekey) {
$items[$id] = array_values($items[$id]);
}
}
}
function recipe_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
$elements = array();
switch ($display['type']) {
case 'recipe_duration':
foreach ($items as $delta => $item) {
$elements[$delta] = array(
'#theme' => $display['type'],
'#duration' => $item['value'],
);
}
break;
case 'recipe_ingredient_default':
$fraction_format = $display['settings']['fraction_format'];
foreach ($items as $delta => $item) {
$name = filter_xss($item['name'], array());
$note = filter_xss($item['note'], array());
if ($item['quantity'] > 0) {
$item['quantity'] *= isset($entity->recipe_factor) ? $entity->recipe_factor : 1;
$formatted_quantity = recipe_ingredient_quantity_from_decimal($item['quantity'], $fraction_format);
}
else {
$formatted_quantity = ' ';
}
$unit_display = '';
if (!empty($item['unit']['abbreviation'])) {
$title = $item['quantity'] > 1 ? $item['unit']['plural'] : $item['unit']['name'];
if ($display['settings']['unit_abbreviation'] == 0) {
$unit_display = '<abbr ' . drupal_attributes(array(
'title' => $title,
)) . '>' . $item['unit']['abbreviation'] . '</abbr>';
}
else {
$unit_display = $title;
}
}
$elements[$delta] = array(
'#theme' => 'recipe_ingredient',
'#name' => $name,
'#quantity' => $formatted_quantity,
'#unit' => $unit_display,
'#note' => $note,
'#link' => $item['link'],
);
}
break;
}
return $elements;
}
function recipe_metadata_field_ingredient_property_callback(&$info, $entity_type, $field, $instance, $field_type) {
$property =& $info[$entity_type]['bundles'][$instance['bundle']]['properties'][$field['field_name']];
$property['getter callback'] = 'entity_metadata_field_verbatim_get';
$property['setter callback'] = 'entity_metadata_field_verbatim_set';
unset($property['query callback']);
$property['type'] = $field['cardinality'] != 1 ? 'list<struct>' : 'struct';
$property['getter callback'] = 'entity_metadata_field_verbatim_get';
$property['setter callback'] = 'entity_metadata_field_verbatim_set';
$property['property info'] = array(
'ingredient' => array(
'type' => 'text',
'label' => t('Ingredient'),
'getter callback' => 'recipe_metadata_field_ingredient_name_get',
'setter callback' => 'recipe_metadata_field_ingredient_name_set',
'required' => TRUE,
),
'quantity' => array(
'type' => 'decimal',
'label' => t('Quantity'),
'setter callback' => 'entity_property_verbatim_set',
),
'unit' => array(
'type' => 'token',
'label' => t('Quantity units'),
'options list' => 'recipe_metadata_field_ingredient_units',
'getter callback' => 'recipe_metadata_field_ingredient_unit_get',
'setter callback' => 'recipe_metadata_field_ingredient_unit_set',
),
'note' => array(
'type' => 'text',
'label' => t('Preparation notes'),
'setter callback' => 'entity_property_verbatim_set',
),
);
}
function recipe_metadata_field_ingredient_name_get($data, array $options, $name, $type, $info) {
return recipe_load_ingredient($data['iid'])->name;
}
function recipe_metadata_field_ingredient_name_set(&$data, $name, $value, $langcode, $type, $info) {
$data['iid'] = recipe_ingredient_id_from_name($value);
}
function recipe_metadata_field_ingredient_units() {
$units = array();
foreach (recipe_get_units() as $key => $unit_data) {
$units[$key] = $unit_data['name'];
}
return $units;
}
function recipe_metadata_field_ingredient_unit_get($data, array $options, $name, $type, $info) {
return recipe_metadata_field_ingredient_units()[$data['unit_key']];
}
function recipe_metadata_field_ingredient_unit_set(&$data, $name, $value, $langcode, $type, $info) {
$data['unit_key'] = $value;
}
function theme_recipe_duration($variables) {
$duration = $variables['duration'];
$hours = floor($duration / 60);
$minutes = $duration % 60;
$output = array();
if ($hours > 0) {
$output['hours'] = format_plural($hours, '1 hour', '@count hours');
}
if ($minutes > 0 || $duration == 0) {
$output['minutes'] = format_plural($minutes, '1 minute', '@count minutes');
}
return implode(', ', $output);
}
function theme_recipe_ingredient($variables) {
$quantity = $variables['quantity'];
$name = $variables['name'];
$link = $variables['link'];
$unit = $variables['unit'];
$note = $variables['note'];
if (!empty($link)) {
$name = l($name, 'node/' . $link);
}
if (!empty($note)) {
$name .= ' (' . $note . ')';
}
$output = '<span class="quantity-unit" property="schema:amount"> ' . $quantity . ' ' . $unit . '</span> <span class="ingredient-name" property="schema:name">' . $name . '</span>';
return $output;
}
function theme_recipe_summary($variables) {
$node = $variables['node'];
$show_title = isset($variables['show_title']) ? $variables['show_title'] : FALSE;
$show_yield_form = isset($variables['show_yield_form']) ? $variables['show_yield_form'] : TRUE;
$output = '<div class="recipe-summary">';
if ($show_title) {
$output .= '<h2 class="title">' . t('Summary') . '</h2>';
}
$output .= '<table>';
$yield_form = drupal_get_form('recipe_yield_form', $node, $show_yield_form);
$output .= '<tr><th class="summary-title">' . t('Yield') . '</th><td class="summary-data">' . drupal_render($yield_form) . '</td></tr>';
if (isset($node->recipe_cook_time[LANGUAGE_NONE][0]['value']) && isset($node->recipe_prep_time[LANGUAGE_NONE][0]['value'])) {
$duration = $node->recipe_cook_time[LANGUAGE_NONE][0]['value'] + $node->recipe_prep_time[LANGUAGE_NONE][0]['value'];
$_text = theme('recipe_duration', array(
'duration' => $duration,
));
if (!empty($node->rdf_mapping['recipe_totaltime'])) {
$attributes = rdf_rdfa_attributes($node->rdf_mapping['recipe_totaltime']);
$attributes['content'] = array(
recipe_duration_iso8601($duration),
);
$_text = theme('rdf_template_variable_wrapper', array(
'content' => $_text,
'attributes' => $attributes,
'inline' => FALSE,
));
}
$output .= '<tr><th>' . t('Total time') . '</th><td>' . $_text . '</td></tr>';
}
$output .= '</table>';
$output .= '</div>';
return $output;
}
function recipe_unit_options() {
static $options;
if (!isset($options)) {
$units = recipe_get_units(variable_get('recipe_preferred_system_of_measure_limit', 0));
$options = array(
'' => '',
);
foreach ($units as $unit_key => $unit) {
$text = $unit['name'];
if (!empty($unit['abbreviation'])) {
$text .= ' (' . $unit['abbreviation'] . ')';
}
$options[$unit_key] = $text;
}
}
return $options;
}
function recipe_ingredient_id_from_name($name) {
static $cache;
if (!isset($cache[$name])) {
$ingredient_id = db_query("SELECT id FROM {recipe_ingredient} WHERE LOWER(name) = :name", array(
':name' => trim(strtolower($name)),
))
->fetchField();
if (!$ingredient_id) {
global $active_db;
$node_link = db_query("SELECT nid FROM {node} n WHERE type = 'ingredient' && title = :title;", array(
':title' => $name,
))
->fetchField();
if (!$node_link) {
$node_link = 0;
}
db_insert('recipe_ingredient')
->fields(array(
'name' => $name,
'link' => $node_link,
))
->execute();
$ingredient_id = db_query("SELECT id FROM {recipe_ingredient} WHERE LOWER(name) = :name", array(
':name' => trim(strtolower($name)),
))
->fetchField();
}
$cache[$name] = $ingredient_id;
}
return $cache[$name];
}
function recipe_ingredient_quantity_from_decimal($ingredient_quantity, $fraction_format = '{%d} %d⁄%d', $edit_mode = FALSE) {
if (strpos($ingredient_quantity, '.')) {
$decimal = abs($ingredient_quantity);
$whole = floor($decimal);
$numerator = 0;
$denominator = 1;
$top_heavy = 0;
$power = 1;
$flag = 0;
while ($flag == 0) {
$argument = $decimal * $power;
if ($argument == floor($argument)) {
$flag = 1;
}
else {
$power = $power * 10;
}
}
$overrides = array(
'3333' => array(
1,
3,
),
'6666' => array(
2,
3,
),
'9999' => array(
3,
3,
),
'1666' => array(
1,
6,
),
'8333' => array(
5,
6,
),
'1111' => array(
1,
9,
),
'2222' => array(
2,
9,
),
'4444' => array(
4,
9,
),
'5555' => array(
5,
9,
),
'7777' => array(
7,
9,
),
'8888' => array(
8,
9,
),
'0833' => array(
1,
12,
),
'4166' => array(
5,
12,
),
'5833' => array(
7,
12,
),
'9166' => array(
11,
12,
),
);
$conversionstr = substr((string) ($decimal - floor($decimal)), 2, 4);
if (array_key_exists($conversionstr, $overrides)) {
if ($overrides[$conversionstr][0] == $overrides[$conversionstr][1]) {
return $whole + 1;
}
$denominator = $overrides[$conversionstr][1];
$numerator = floor($decimal) * $denominator + $overrides[$conversionstr][0];
}
else {
$numerator = $decimal * $power;
$denominator = $power;
}
$gcd = greatest_common_divisor($numerator, $denominator);
$numerator = $numerator / $gcd;
$denominator = $denominator / $gcd;
$top_heavy = $numerator;
$numerator = abs($top_heavy) - abs($whole) * $denominator;
$ingredient_quantity = sprintf($fraction_format, $whole, $numerator, $denominator);
if ($whole == 0 && strpos($ingredient_quantity, '{') >= 0) {
$ingredient_quantity = preg_replace('/{.*}/', '', $ingredient_quantity);
}
else {
$ingredient_quantity = preg_replace('/{|}/', '', $ingredient_quantity);
}
if ($edit_mode) {
$ingredient_quantity = strip_tags($ingredient_quantity);
}
}
return filter_xss_admin(trim($ingredient_quantity));
}
function greatest_common_divisor($a, $b) {
while ($b != 0) {
$remainder = $a % $b;
$a = $b;
$b = $remainder;
}
return abs($a);
}
function recipe_ingredient_quantity_from_fraction($ingredient_quantity) {
$ingredient_quantity = preg_replace('/^(\\d+)[\\-](\\d+)[\\/](\\d+)/', '${1} ${2}/${3}', $ingredient_quantity);
if ($pos_slash = strpos($ingredient_quantity, '/')) {
$pos_space = strpos($ingredient_quantity, ' ');
if ($pos_space === FALSE) {
$pos_space = 0;
}
$whole = (int) substr($ingredient_quantity, 0, $pos_space);
$numerator = (int) substr($ingredient_quantity, $pos_space, $pos_slash);
$denominator = (int) substr($ingredient_quantity, $pos_slash + 1);
$ingredient_quantity = $whole + $numerator / $denominator;
}
return $ingredient_quantity;
}
function recipe_validate($node, $form, &$form_state) {
$return = TRUE;
if (!is_numeric($form_state['values']['recipe_yield']) || $form_state['values']['recipe_yield'] <= 0) {
form_set_error('recipe_yield', t('Yield must be a valid positive integer.'));
$return = FALSE;
}
return $return;
}
function recipe_node_sanitize(&$node) {
if (!empty($node->recipe_yield_unit)) {
$node->recipe_yield_unit = filter_xss($node->recipe_yield_unit, array());
}
}
function recipe_yield_form($form, &$form_state, $node, $show_yield_form) {
if ($show_yield_form == FALSE || variable_get('recipe_summary_location', 0) == 1) {
$form['yield'] = array(
'#markup' => $node->recipe_yield,
);
$form['_space'] = array(
'#markup' => ' ',
);
$form['yield_unit'] = array(
'#markup' => $node->recipe_yield_unit == '' ? t('Servings') : $node->recipe_yield_unit,
);
}
else {
$form['custom_yield'] = array(
'#type' => 'textfield',
'#default_value' => $node->recipe_yield,
'#size' => 2,
'#maxlength' => 4,
'#attributes' => array(
'class' => array(
'recipe-yield-value',
),
),
);
$form['yield_unit'] = array(
'#markup' => $node->recipe_yield_unit == '' ? t('Servings') : $node->recipe_yield_unit,
'#suffix' => '<br/>',
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Change'),
'#attributes' => array(
'class' => array(
'recipe-yield-change',
),
),
);
$form['reset'] = array(
'#type' => 'submit',
'#value' => t('Reset'),
'#attributes' => array(
'class' => array(
'recipe-yield-reset',
),
),
);
$form['halve'] = array(
'#type' => 'submit',
'#value' => t('Halve'),
'#attributes' => array(
'class' => array(
'recipe-yield-halve',
),
),
);
$form['double'] = array(
'#type' => 'submit',
'#value' => t('Double'),
'#attributes' => array(
'class' => array(
'recipe-yield-double',
),
),
);
}
return $form;
}
function recipe_import_myaccess($string, $account = NULL, $reset = FALSE) {
$formats = module_invoke_all('recipeio', 'import_single');
if (count($formats) == 0) {
return FALSE;
}
return user_access($string, $account, $reset);
}
function recipe_export_multi_myaccess($string, $account = NULL, $reset = FALSE) {
$formats = module_invoke_all('recipeio', 'export_multi');
if (count($formats) == 0) {
return FALSE;
}
return user_access($string, $account, $reset);
}
function recipe_import_multi_myaccess($string, $account = NULL, $reset = FALSE) {
$formats = module_invoke_all('recipeio', 'import_multi');
if (count($formats) == 0) {
return FALSE;
}
return user_access($string, $account, $reset);
}
function recipe_get_latest($count = 5) {
$select = db_select('node', 'n');
$select
->addField('n', 'nid');
$select
->addField('n', 'title');
$select
->addField('n', 'sticky');
$select
->addField('n', 'created');
$select
->condition('n.type', 'recipe');
$select
->condition('n.status', 1);
$select
->orderBy('n.sticky', 'DESC');
$select
->orderBy('n.created', 'DESC');
$select
->range(0, $count);
$select
->addTag('node_access');
return $select
->execute();
}
function strip_html_and_encode_entities($string) {
$string = filter_xss($string, array());
$string = str_replace("°", "", $string);
return $string;
}
function recipe_views_api() {
return array(
'api' => 2,
'path' => drupal_get_path('module', 'recipe') . '/includes',
);
}
function recipe_field_extra_fields() {
$extra = array();
$extra['node']['recipe'] = array(
'form' => array(
'recipe_yield' => array(
'label' => t('Yield'),
'description' => t('Recipe module element'),
'weight' => -3,
),
'recipe_yield_unit' => array(
'label' => t('Yield units'),
'description' => t('Recipe module element'),
'weight' => -3,
),
),
'display' => array(
'recipe_summary_box' => array(
'label' => t('Recipe summary box'),
'description' => t('Recipe module element'),
'weight' => -7,
),
),
);
return $extra;
}
function fixEncoding($in_str) {
$cur_encoding = mb_detect_encoding($in_str);
if ($cur_encoding == "UTF-8" && mb_check_encoding($in_str, "UTF-8")) {
return $in_str;
}
else {
return utf8_encode($in_str);
}
}
function recipe_rdf_namespaces() {
return array(
'schema' => 'http://schema.org/',
);
}
function recipe_rdf_mapping() {
return array(
array(
'type' => 'node',
'bundle' => 'recipe',
'mapping' => array(
'rdftype' => array(
'schema:Recipe',
),
'title' => array(
'predicates' => array(
'schema:name',
),
),
'recipe_instructions' => array(
'predicates' => array(
'schema:instructions',
),
),
'recipe_description' => array(
'predicates' => array(
'schema:summary',
),
),
'recipe_prep_time' => array(
'predicates' => array(
'schema:prepTime',
),
'datatype' => 'xsd:duration',
'callback' => 'recipe_duration_iso8601',
),
'recipe_cook_time' => array(
'predicates' => array(
'schema:cookTime',
),
'datatype' => 'xsd:duration',
'callback' => 'recipe_duration_iso8601',
),
'recipe_totaltime' => array(
'predicates' => array(
'schema:totalTime',
),
),
'recipe_yield' => array(
'predicates' => array(
'schema:yield',
),
),
'recipe_ingredient' => array(
'predicates' => array(
'schema:ingredients',
),
),
),
),
);
}
function recipe_duration_iso8601($duration = 0) {
if (is_array($duration) && isset($duration['value'])) {
$duration = $duration['value'];
}
$hours = floor($duration / 60);
$minutes = $duration % 60;
$output = '';
if ($hours > 0) {
$output .= $hours . 'H';
}
if ($minutes > 0) {
$output .= $minutes . 'M';
}
return empty($output) ? 'PT0M' : 'PT' . $output;
}
function recipe_get_units($limit_to_preferred = 0) {
$us_units = array(
'cup' => array(
'name' => t('cup'),
'plural' => t('cups'),
'abbreviation' => t('c', array(), array(
'context' => 'abbreviation cup',
)),
'system' => 'us customary',
'type' => t('volume'),
'aliases' => array(),
),
'us liquid pint' => array(
'name' => t('pint'),
'plural' => t('pints'),
'abbreviation' => t('pt', array(), array(
'context' => 'abbreviation pint',
)),
'system' => 'us customary',
'type' => t('volume'),
'aliases' => array(),
),
'us liquid quart' => array(
'name' => t('quart'),
'plural' => t('quarts'),
'abbreviation' => t('q', array(), array(
'context' => 'abbreviation quart',
)),
'system' => 'us customary',
'type' => t('volume'),
'aliases' => array(),
),
'us gallon' => array(
'name' => t('gallon'),
'plural' => t('gallons'),
'abbreviation' => t('gal', array(), array(
'context' => 'abbreviation gallon',
)),
'system' => 'us customary',
'type' => t('volume'),
'aliases' => array(),
),
'pound' => array(
'name' => t('pound'),
'plural' => t('pounds'),
'abbreviation' => t('lb', array(), array(
'context' => 'abbreviation pound',
)),
'system' => 'us customary',
'type' => t('weight'),
'aliases' => array(),
),
'ounce' => array(
'name' => t('ounce'),
'plural' => t('ounces'),
'abbreviation' => t('oz', array(), array(
'context' => 'abbreviation ounce',
)),
'system' => 'us customary',
'type' => t('weight'),
'aliases' => array(),
),
'us fluid ounce' => array(
'name' => t('fluid ounce'),
'plural' => t('fluid ounces'),
'abbreviation' => t('fl oz', array(), array(
'context' => 'abbreviation fluid ounce',
)),
'system' => 'us customary',
'type' => t('volume'),
'aliases' => array(),
),
);
$si_units = array(
'milliliter' => array(
'name' => t('milliliter'),
'plural' => t('milliliters'),
'abbreviation' => t('ml', array(), array(
'context' => 'abbreviation milliliter',
)),
'system' => 'si',
'type' => t('volume'),
'aliases' => array(),
),
'centiliter' => array(
'name' => t('centiliter'),
'plural' => t('centiliters'),
'abbreviation' => t('cl', array(), array(
'context' => 'abbreviation centiliter',
)),
'system' => 'si',
'type' => t('volume'),
'aliases' => array(),
),
'liter' => array(
'name' => t('liter'),
'plural' => t('liters'),
'abbreviation' => t('l', array(), array(
'context' => 'abbreviation liter',
)),
'system' => 'si',
'type' => t('volume'),
'aliases' => array(),
),
'deciliter' => array(
'name' => t('deciliter'),
'plural' => t('deciliters'),
'abbreviation' => t('dl', array(), array(
'context' => 'abbreviation deciliter',
)),
'system' => 'si',
'type' => t('volume'),
'aliases' => array(),
),
'milligram' => array(
'name' => t('milligram'),
'plural' => t('milligrams'),
'abbreviation' => t('mg', array(), array(
'context' => 'abbreviation milligram',
)),
'system' => 'si',
'type' => t('weight'),
'aliases' => array(),
),
'gram' => array(
'name' => t('gram'),
'plural' => t('grams'),
'abbreviation' => t('g', array(), array(
'context' => 'abbreviation gram',
)),
'system' => 'si',
'type' => t('weight'),
'aliases' => array(),
),
'centigram' => array(
'name' => t('centigram'),
'plural' => t('centigrams'),
'abbreviation' => t('cg', array(), array(
'context' => 'abbreviation centigram',
)),
'system' => 'si',
'type' => t('weight'),
'aliases' => array(),
),
'kilogram' => array(
'name' => t('kilogram'),
'plural' => t('kilograms'),
'abbreviation' => t('kg', array(), array(
'context' => 'abbreviation kilogram',
)),
'system' => 'si',
'type' => t('weight'),
'aliases' => array(),
),
);
$common_units = array(
'tablespoon' => array(
'name' => t('tablespoon'),
'plural' => t('tablespoons'),
'abbreviation' => t('T', array(), array(
'context' => 'abbreviation tablespoon',
)),
'system' => 'common',
'type' => t('volume'),
'aliases' => array(
'tbsp',
'tb',
),
),
'teaspoon' => array(
'name' => t('teaspoon'),
'plural' => t('teaspoons'),
'abbreviation' => t('t', array(), array(
'context' => 'abbreviation teaspoon',
)),
'system' => 'common',
'type' => t('volume'),
'aliases' => array(
'tsp',
),
),
'slice' => array(
'name' => t('slice'),
'plural' => t('slices'),
'abbreviation' => t('sli', array(), array(
'context' => 'abbreviation slice',
)),
'system' => 'common',
'type' => t('indefinite'),
'aliases' => array(),
),
'clove' => array(
'name' => t('clove'),
'plural' => t('cloves'),
'abbreviation' => t('clv', array(), array(
'context' => 'abbreviation clove',
)),
'system' => 'common',
'type' => t('indefinite'),
'aliases' => array(),
),
'load' => array(
'name' => t('loaf'),
'plural' => t('loaves'),
'abbreviation' => t('lf', array(), array(
'context' => 'abbreviation loaf',
)),
'system' => 'common',
'type' => t('indefinite'),
'aliases' => array(),
),
'pinch' => array(
'name' => t('pinch'),
'plural' => t('pinches'),
'abbreviation' => t('pn', array(), array(
'context' => 'abbreviation pinch',
)),
'system' => 'common',
'type' => t('indefinite'),
'aliases' => array(),
),
'package' => array(
'name' => t('package'),
'plural' => t('packages'),
'abbreviation' => t('pk', array(), array(
'context' => 'abbreviation package',
)),
'system' => 'common',
'type' => t('indefinite'),
'aliases' => array(
'pack',
),
),
'can' => array(
'name' => t('can'),
'plural' => t('cans'),
'abbreviation' => t('cn', array(), array(
'context' => 'abbreviation can',
)),
'system' => 'common',
'type' => t('indefinite'),
'aliases' => array(
'jar',
),
),
'drop' => array(
'name' => t('drop'),
'plural' => t('drops'),
'abbreviation' => t('dr', array(), array(
'context' => 'abbreviation drop',
)),
'system' => 'common',
'type' => t('indefinite'),
'aliases' => array(),
),
'bunch' => array(
'name' => t('bunch'),
'plural' => t('bunches'),
'abbreviation' => t('bn', array(), array(
'context' => 'abbreviation bunch',
)),
'system' => 'common',
'type' => t('indefinite'),
'aliases' => array(),
),
'dash' => array(
'name' => t('dash'),
'plural' => t('dashes'),
'abbreviation' => t('ds', array(), array(
'context' => 'abbreviation dash',
)),
'system' => 'common',
'type' => t('indefinite'),
'aliases' => array(),
),
'carton' => array(
'name' => t('carton'),
'plural' => t('cartons'),
'abbreviation' => t('ct', array(), array(
'context' => 'abbreviation carton',
)),
'system' => 'common',
'type' => t('indefinite'),
'aliases' => array(),
),
'unit' => array(
'name' => t('unit'),
'plural' => t('units'),
'abbreviation' => '',
'system' => 'common',
'type' => t('indefinite'),
'aliases' => array(
'each',
'ea',
'whole',
),
),
'unknown' => array(
'name' => t('unknown'),
'plural' => t('unknown'),
'abbreviation' => '',
'system' => 'common',
'type' => t('indefinite'),
'aliases' => array(),
),
);
if (variable_get('recipe_preferred_system_of_measure', 0) == 0) {
$units = array_merge($us_units, $common_units);
if ($limit_to_preferred == 0) {
$units = array_merge($units, $si_units);
}
uasort($units, 'unit_sort');
}
else {
$units = array_merge($si_units, $common_units);
if ($limit_to_preferred == 0) {
$units = array_merge($units, $us_units);
}
uasort($units, 'unit_sort');
}
drupal_alter('recipe_ing_units', $units);
return $units;
}
function unit_sort($a, $b) {
return strcmp($a['name'], $b['name']);
}