View source
<?php
define('FORMAT_NUMBER_MAX_PRECISION', 8);
function format_number_help($path, $arg) {
switch ($path) {
case 'admin/help#format_number':
return '<p>' . t('The <em>Format Number API</em> module provides a method to configure number formats (site default and user defined) with configurable decimal point and thousand separators. It also exposes several functions that can be used by other contributed or custom modules to display numbers accordingly.') . '</p>';
}
}
function format_number_perm() {
return array(
'configure default number format',
);
}
function format_number_menu() {
$items = array();
$items['admin/settings/format_number'] = array(
'title' => 'Number format',
'description' => 'Configure site wide number format settings.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'format_number_settings_site',
),
'access arguments' => array(
'configure default number format',
),
'file' => 'format_number.settings.inc',
);
return $items;
}
function format_number_theme() {
return array(
'numericfield' => array(
'arguments' => array(
'element' => NULL,
),
),
);
}
function format_number_user($type, &$edit, &$user, $category = NULL) {
if ($type == 'form' && $category == 'account' && variable_get('format_number_user_configurable', 0)) {
module_load_include('inc', 'format_number', 'format_number.settings');
return format_number_settings_user($edit);
}
elseif ($type == 'validate' && $category == 'account' && variable_get('format_number_user_configurable', 0)) {
module_load_include('inc', 'format_number', 'format_number.settings');
format_number_settings_user_validate($edit);
return;
}
}
function format_number_get_decimal_point_options() {
return array(
"." => t('full stop (.)'),
"," => t('comma (,)'),
"٫" => t('arabic decimal separator (٫)'),
);
}
function format_number_get_thousands_separator_options() {
return array(
'' => t('none'),
"." => t('full stop (.)'),
"," => t('comma (,)'),
"'" => t("apostrophe (')"),
" " => t('no-break space ( )'),
"," => t('full width comma (,)'),
"٬" => t('arabic thousands separator (٬)'),
"ወ" => t('ethiopic syllable wa (ወ)'),
);
}
function format_number_get_options($name = NULL) {
static $format_options;
global $user;
if (!isset($format_options)) {
$format_options = array(
'thousands_sep' => variable_get('format_number_thousands_sep', ','),
'decimal_point' => variable_get('format_number_decimal_point', '.'),
);
if (variable_get('format_number_user_configurable', 0) && $user->uid) {
if (drupal_strlen($user->thousands_sep)) {
$format_options['thousands_sep'] = $user->thousands_sep;
}
if (drupal_strlen($user->decimal_point)) {
$format_options['decimal_point'] = $user->decimal_point;
}
}
}
if (isset($name)) {
return isset($format_options[$name]) ? $format_options[$name] : NULL;
}
return $format_options;
}
function format_number_add_js() {
static $ready;
if (!isset($ready)) {
$ready = TRUE;
$module_path = drupal_get_path('module', 'format_number');
drupal_add_css($module_path . '/format_number.css');
drupal_add_js($module_path . '/format_number.js');
drupal_add_js(array(
'format_number' => format_number_get_options(),
), 'setting');
}
}
function format_number($number, $decimals = 0) {
static $format_options;
if (!isset($format_options)) {
$format_options = format_number_get_options();
}
$number = number_format((double) $number, FORMAT_NUMBER_MAX_PRECISION, '.', '');
if ($decimals < 0) {
$decimals = strpos($number, '.') === FALSE ? 0 : drupal_strlen(preg_replace('#^.*\\.([0-9]*?)0*$#', '\\1', $number));
}
if ($decimals > FORMAT_NUMBER_MAX_PRECISION) {
$decimals = FORMAT_NUMBER_MAX_PRECISION;
}
return str_replace(array(
'X',
'Z',
), array(
$format_options['decimal_point'],
$format_options['thousands_sep'],
), number_format($number, $decimals, 'X', 'Z'));
}
function format_number_significant_figures($number, $significant_figures) {
$decimals = floor($significant_figures - log10(abs($number)));
$number = round($number, $decimals);
if ($number == 0) {
$decimals = 0;
}
return format_number($number, $decimals);
}
function parse_formatted_number($formatted_number, $required = TRUE) {
static $format_options, $decimal_point_options, $thousands_separator_options;
if (!isset($format_options)) {
$format_options = format_number_get_options();
$decimal_point_options = format_number_get_decimal_point_options();
$thousands_separator_options = format_number_get_thousands_separator_options();
}
$formatted_number = trim($formatted_number);
if ($formatted_number === '') {
return $required ? FALSE : 0;
}
if ($format_options['thousands_sep'] == " ") {
$thousands_separator_options[' '] = TRUE;
}
$is_negative = FALSE;
if ($formatted_number[0] == '-' || $formatted_number[0] == '+') {
$is_negative = $formatted_number[0] == '-' ? TRUE : FALSE;
$formatted_number = drupal_substr($formatted_number, 1);
}
else {
$last_char = $formatted_number[drupal_strlen($formatted_number) - 1];
if ($last_char == '-' || $last_char == '+') {
$is_negative = $last_char == '-' ? TRUE : FALSE;
$formatted_number = drupal_substr($formatted_number, 0, -1);
}
}
preg_match_all('#[^0-9]#u', $formatted_number, $matches);
$non_numeric_symbols = array_count_values($matches[0]);
$non_numeric_symbols_count = count($non_numeric_symbols);
if ($non_numeric_symbols_count > 2) {
return FALSE;
}
if ($non_numeric_symbols_count == 2) {
$thousands_sep = array_keys($non_numeric_symbols);
$thousands_sep = array_shift($thousands_sep);
if (!isset($thousands_separator_options[$thousands_sep])) {
return FALSE;
}
$formatted_number = str_replace($thousands_sep, '', $formatted_number);
unset($non_numeric_symbols[$thousands_sep]);
$decimal_point = array_keys($non_numeric_symbols);
$decimal_point = array_shift($decimal_point);
if ($non_numeric_symbols[$decimal_point] > 1) {
return FALSE;
}
if (!isset($decimal_point_options[$decimal_point])) {
return FALSE;
}
if ($decimal_point != '.') {
$formatted_number = str_replace($decimal_point, '.', $formatted_number);
}
}
elseif ($non_numeric_symbols_count == 1) {
$unknown_symbol = array_keys($non_numeric_symbols);
$unknown_symbol = array_shift($unknown_symbol);
if ($non_numeric_symbols[$unknown_symbol] > 1) {
if (!isset($thousands_separator_options[$unknown_symbol])) {
return FALSE;
}
$formatted_number = str_replace($unknown_symbol, '', $formatted_number);
}
elseif ($unknown_symbol != '.' && $unknown_symbol != ',') {
if (isset($decimal_point_options[$unknown_symbol])) {
$formatted_number = str_replace($unknown_symbol, '.', $formatted_number);
}
if (isset($thousands_separator_options[$unknown_symbol])) {
$formatted_number = str_replace($unknown_symbol, '', $formatted_number);
}
else {
return FALSE;
}
}
else {
if ($unknown_symbol == $format_options['decimal_point']) {
$formatted_number = str_replace($unknown_symbol, '.', $formatted_number);
}
elseif ($unknown_symbol == $format_options['thousands_sep']) {
$formatted_number = str_replace($unknown_symbol, '', $formatted_number);
}
else {
return FALSE;
}
}
}
return ($is_negative && 0 != $formatted_number ? '-' : '') . $formatted_number;
}
function format_number_elements() {
return array(
'numericfield' => array(
'#input' => TRUE,
'#precision' => 12,
'#decimals' => 0,
'#process' => array(
'format_number_numericfield_process',
),
),
);
}
function format_number_compute_boundary($direction, $precision = 0, $decimals = 0) {
return (double) (($direction == 'lower' ? '-' : '') . str_repeat('9', $precision - $decimals) . '.' . str_repeat('9', $decimals));
}
function format_number_numericfield_process($element, $edit, $form_state, $form) {
$element_precision = isset($element['#precision']) && (int) $element['#precision'] > 0 ? (int) $element['#precision'] : 12;
$element_decimals = isset($element['#decimals']) && (int) $element['#decimals'] >= 0 ? (int) $element['#decimals'] : 0;
$element_minimum = isset($element['#minimum']) ? parse_formatted_number($element['#minimum']) : NULL;
if (!is_numeric($element_minimum)) {
$element_minimum = format_number_compute_boundary('lower', $element_precision, $element_decimals);
}
if (empty($element['#size']) || empty($element['#maxlength'])) {
$element_maxlength = $element_precision;
if ($element_decimals > 0) {
$element_maxlength++;
}
if (isset($element_minimum) && $element_minimum < 0) {
$element_maxlength++;
}
$thousands_sep = format_number_get_options('thousands_sep');
if (!empty($thousands_sep)) {
$element_maxlength += ceil(($element_precision - $element_decimals) / 3) - 1;
}
if (empty($element['#size'])) {
$element['#size'] = $element_maxlength + 1;
}
if (empty($element['#maxlength'])) {
$element['#maxlength'] = $element_maxlength;
}
}
$value = !empty($element['#value']) && is_string($element['#value']) ? $element['#value'] : '';
if (is_numeric($value)) {
$value = format_number($value, $element_decimals);
}
$element['#value'] = $value;
if (isset($element['#attributes']) && is_array($element['#attributes'])) {
$element['#attributes']['decimals'] = $element_decimals;
}
else {
$element['#attributes'] = array(
'decimals' => $element_decimals,
);
}
if (isset($element['#element_validate']) && is_array($element['#element_validate'])) {
array_shift($element['#element_validate'], 'format_number_numericfield_validate');
}
else {
$element['#element_validate'] = array(
'format_number_numericfield_validate',
);
}
return $element;
}
function form_type_numericfield_value($element, $edit = FALSE) {
if ($edit !== FALSE) {
$value = trim(str_replace(array(
"\r",
"\n",
), '', $edit));
if ($value != '' && ($parsed = parse_formatted_number($value)) !== FALSE) {
$value = $parsed;
}
return $value;
}
}
function format_number_numericfield_validate($element, &$form_state) {
$value = $element['#value'];
if ($element['#required'] || $value != '') {
$value = parse_formatted_number($value, $element['#required']);
if (!is_numeric($value)) {
form_error($element, t('%name: The specified number @num is invalid.', array(
'%name' => $element['#title'],
'@num' => $element['#value'],
)));
return;
}
$element_precision = isset($element['#precision']) && (int) $element['#precision'] > 0 ? (int) $element['#precision'] : 12;
$element_decimals = isset($element['#decimals']) && (int) $element['#decimals'] >= 0 ? (int) $element['#decimals'] : 0;
$element_minimum = isset($element['#minimum']) ? parse_formatted_number($element['#minimum']) : NULL;
if (!is_numeric($element_minimum)) {
$element_minimum = format_number_compute_boundary('lower', $element_precision, $element_decimals);
}
$element_maximum = isset($element['#maximum']) ? parse_formatted_number($element['#maximum']) : NULL;
if (!is_numeric($element_maximum)) {
$element_maximum = format_number_compute_boundary('upper', $element_precision, $element_decimals);
}
if ($value < $element_minimum) {
form_error($element, t('%name: The value may be no smaller than @minimum.', array(
'%name' => $element['#title'],
'@minimum' => $element_minimum,
)));
return;
}
elseif ($value > $element_maximum) {
form_error($element, t('%name: The value may be no larger than @maximum.', array(
'%name' => $element['#title'],
'@maximum' => $element_maximum,
)));
return;
}
}
if ($element['#value'] != $value) {
form_set_value($element, $value, $form_state);
}
}
function theme_numericfield($element) {
format_number_add_js();
$size = empty($element['#size']) ? '' : ' size="' . $element['#size'] . '"';
$maxlength = empty($element['#maxlength']) ? '' : ' maxlength="' . $element['#maxlength'] . '"';
$output = '';
_form_set_class($element, array(
'form-numeric',
));
if (isset($element['#field_prefix'])) {
$output .= '<span class="field-prefix">' . $element['#field_prefix'] . '</span> ';
}
$output .= '<input type="text"' . $maxlength . ' name="' . $element['#name'] . '" id="' . $element['#id'] . '"' . $size . ' value="' . check_plain($element['#value']) . '"' . drupal_attributes($element['#attributes']) . ' />';
if (isset($element['#field_suffix'])) {
$output .= ' <span class="field-suffix">' . $element['#field_suffix'] . '</span>';
}
return theme('form_element', $element, $output);
}