' . t('The following characters are recognized in the format parameter string:') . ''; $output .= '
'; foreach (name_replacement_tokens() as $token => $title) { $output .= "
{$token}
{$title}
"; } $output .= '
'; return $output; } /** * Provides the tokens that the name parse can handle. * * Todo:: make the labels generic */ function name_replacement_tokens() { $tokens = array( 't' => t('Title'), 'g' => t('Given name'), 'm' => t('Middle name(s)'), 'f' => t('Family name'), 'c' => t('Credentials'), 's' => t('Generational suffix'), 'x' => t('First letter given'), 'y' => t('First letter middle'), 'z' => t('First letter family'), 'e' => t('Conditional: Either the given or family name. Given name is given preference.'), 'E' => t('Conditional: Either the given or family name. Family name is given preference.'), 'i' => t('Separator 1'), 'j' => t('Separator 2'), 'k' => t('Separator 3'), '\\' => t('You can prevent a character in the format string from being expanded by escaping it with a preceding backslash.'), 'L' => t('Modifier: Converts the next token to all lowercase.'), 'U' => t('Modifier: Converts the next token to all uppercase.'), 'F' => t('Modifier: Converts the first letter to uppercase.'), 'G' => t('Modifier: Converts the first letter of ALL words to uppercase.'), 'T' => t('Modifier: Trims whitespace around the next token.'), 'S' => t('Modifier: Ensures that the next token is safe for the display.'), '+' => t('Conditional: Insert the token if both the surrounding tokens are not empty.'), '-' => t('Conditional: Insert the token if the previous token is not empty'), '~' => t('Conditional: Insert the token if the previous token is empty'), '=' => t('Conditional: Insert the token if the next token is not empty.'), '^' => t('Conditional: Insert the token if the next token is empty.'), '|' => t('Conditional: Uses the previous token unless empty, otherwise it uses this token.'), '(' => t('Group: Start of token grouping.'), ')' => t('Group: End of token grouping.'), /* // Placeholders for token support insertion on the [object / key | entity / bundle]. '1' => t('Token placeholder 1'), '2' => t('Token placeholder 2'), '3' => t('Token placeholder 3'), '4' => t('Token placeholder 4'), '5' => t('Token placeholder 5'), '6' => t('Token placeholder 6'), '7' => t('Token placeholder 7'), '8' => t('Token placeholder 8'), '9' => t('Token placeholder 9'), */ ); return $tokens; } function _name_generate_tokens($name_components, $settings = array()) { $name_components = (array) $name_components; $markup = !empty($settings['markup']); $name_components += array( 'title' => '', 'given' => '', 'middle' => '', 'family' => '', 'credentials' => '', 'generational' => '', ); $settings = name_settings(); $tokens = array( 't' => theme('name_component', array('value' => $name_components['title'], 'component' => 'title', 'markup' => $markup, 'modifier' => NULL)), 'g' => theme('name_component', array('value' => $name_components['given'], 'component' => 'given', 'markup' => $markup, 'modifier' => NULL)), 'm' => theme('name_component', array('value' => $name_components['middle'], 'component' => 'middle', 'markup' => $markup, 'modifier' => NULL)), 'f' => theme('name_component', array('value' => $name_components['family'], 'component' => 'family', 'markup' => $markup, 'modifier' => NULL)), 'c' => theme('name_component', array('value' => $name_components['credentials'], 'component' => 'credentials', 'markup' => $markup, 'modifier' => NULL)), 's' => theme('name_component', array('value' => $name_components['generational'], 'component' => 'generational', 'markup' => $markup, 'modifier' => NULL)), 'x' => theme('name_component', array('value' => $name_components['given'], 'component' => 'given', 'markup' => $markup, 'modifier' => 'initial')), 'y' => theme('name_component', array('value' => $name_components['middle'], 'component' => 'middle', 'markup' => $markup, 'modifier' => 'initial')), 'z' => theme('name_component', array('value' => $name_components['family'], 'component' => 'family', 'markup' => $markup, 'modifier' => 'initial')), 'i' => $settings['sep1'], 'j' => $settings['sep2'], 'k' => $settings['sep3'], ); $given = $tokens['g']; $family = $tokens['f']; if ($given || $family) { $tokens += array( 'e' => $given ? $given : $family, 'E' => $family ? $family : $given, ); } else { $tokens += array( 'e' => NULL, 'E' => NULL, ); } return $tokens; } /** * TODO: Look at replacing the raw string functions with the Drupal equivalent * functions. Will need to test this carefully... */ function _name_format($name_components, $format = '', $settings = array(), $tokens = NULL) { if (empty($format)) { return ''; } if (!isset($tokens)) { $tokens = _name_generate_tokens($name_components, $settings); } // Nuetralise any escapped backslashes. $format = str_replace('\\\\', "\t", $format); $pieces = array(); $len = strlen($format); $modifiers = ''; $conditions = ''; $depth = 0; for ($i = 0; $i < strlen($format); $i++) { $char = $format{$i}; $last_char = ($i > 0) ? $format{$i -1} : FALSE; $next_char = ($i < $len - 2) ? $format{$i + 1} : FALSE; // Handle escaped letters. if ($char == '\\') { continue; } if ($last_char == '\\') { $pieces[] = _name_format_add_component($char, $modifiers, $conditions); continue; } switch ($char) { case 'L': case 'U': case 'F': case 'T': case 'S': case 'G': $modifiers .= $char; break; case '=': case '^': case '|': case '+': case '-': case '~': $conditions .= $char; break; case '(': case ')': $remaining_string = substr($format, $i); if ($char == '(' && $closing_bracket = _name_format_closing_bracket_position($remaining_string)) { $sub_string = _name_format($tokens, substr($format, $i + 1, $closing_bracket - 1), $settings, $tokens); // Increment the counter past the closing bracket. $i += $closing_bracket; $pieces[] = _name_format_add_component($sub_string, $modifiers, $conditions); } else { // Unmatched, add it. $pieces[] = _name_format_add_component($char, $modifiers, $conditions); } break; default: if (array_key_exists($char, $tokens)) { $char = $tokens[$char]; } $pieces[] = _name_format_add_component($char, $modifiers, $conditions); break; } } $parsed_pieces = array(); for ($i = 0; $i < count($pieces); $i++) { $component = $pieces[$i]['value']; $conditions = $pieces[$i]['conditions']; $last_component = ($i > 0) ? $pieces[$i - 1]['value'] : FALSE; $next_component = ($i < count($pieces) - 1) ? $pieces[$i + 1]['value'] : FALSE; if (empty($conditions)) { $parsed_pieces[$i] = $component; } else { // Modifier: Conditional insertion. Insert if both the surrounding tokens are not empty. if (strpos($conditions, '+') !== FALSE && !empty($last_component) && !empty($next_component)) { $parsed_pieces[$i] = $component; } // Modifier: Conditional insertion. Insert if the previous token is not empty. if (strpos($conditions, '-') !== FALSE && !empty($last_component)) { $parsed_pieces[$i] = $component; } // Modifier: Conditional insertion. Insert if the previous token is empty. if (strpos($conditions, '~') !== FALSE && empty($last_component)) { $parsed_pieces[$i] = $component; } // Modifier: Insert the token if the next token is empty. if (strpos($conditions, '^') !== FALSE && empty($next_component)) { $parsed_pieces[$i] = $component; } // Modifier: Insert the token if the next token is not empty. // This overrides the above two settings. if (strpos($conditions, '=') !== FALSE && !empty($next_component)) { $parsed_pieces[$i] = $component; } // Modifier: Conditional insertion. Uses the previous token unless empty, otherwise insert this token. if (strpos($conditions, '|') !== FALSE) { if (empty($last_component)) { $parsed_pieces[$i] = $component; } else { unset($parsed_pieces[$i]); } } } } return str_replace('\\\\', "\t", implode('', $parsed_pieces)); } function _name_format_add_component($string, &$modifiers = '', &$conditions = '') { $string = _name_format_apply_modifiers($string, $modifiers); $piece = array( 'value' => $string, 'conditions' => $conditions, ); $conditions = ''; $modifiers = ''; return $piece; } function _name_format_apply_modifiers($string, $modifiers) { if (!is_null($string) || strlen($string)) { if ($modifiers) { $original_string = $string; $prefix = ''; $suffix = ''; if (preg_match('/^(]*>)(.*)(<\/span>)$/i', $string, $matches)) { $prefix = $matches[1]; $string = $matches[2]; $suffix = $matches[3]; } for ($j = 0; $j < strlen($modifiers); $j++) { switch ($modifiers{$j}) { case 'L': $string = drupal_strtolower($string); break; case 'U': $string = drupal_strtoupper($string); break; case 'F': $string = drupal_ucfirst($string); break; case 'G': if (!empty($string)) { $parts = explode(' ', $string); $string = array(); foreach ($parts as $part) { $string[] = drupal_ucfirst($part); } $string = implode(' ', $string); } break; case 'T': $string = trim($string); break; case 'S': $string = check_plain($string); break; } } $string = $prefix . $string . $suffix; } } return $string; } /** * Helper function to put out the first matched bracket position. * * Accepts strings in the format, ^ marks the matched bracket. * '(xxx^)xxx(xxxx)xxxx' or '(xxx(xxx(xxxx))xxx^)' */ function _name_format_closing_bracket_position($string) { // Simplify the string by removing escaped brackets. $depth = 0; $string = str_replace(array('\(', '\)'), array('__', '__'), $string); for ($i = 0; $i < strlen($string); $i++) { $char = $string{$i}; if ($char == '(') { $depth++; } elseif ($char == ')') { $depth--; if ($depth == 0) { return $i; } } } return FALSE; }