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_permission() {
return array(
'configure default number format' => array(
'title' => t('Configure default format number'),
),
);
}
function format_number_menu() {
$items = array();
$items['admin/config/regional/format_number'] = array(
'title' => 'Number format',
'description' => 'Configure site wide number format settings.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'format_number_site_settings_form',
),
'access arguments' => array(
'configure default number format',
),
'file' => 'format_number.settings.inc',
);
return $items;
}
function format_number_theme() {
return array(
'numericfield' => array(
'render element' => 'element',
),
);
}
function format_number_form_user_profile_form_alter(&$form, &$form_state) {
if ($form['#user_category'] == 'account' && variable_get('format_number_user_configurable', 0)) {
module_load_include('inc', 'format_number', 'format_number.settings');
$form += format_number_user_settings_form($form_state['user']->data);
$form['#validate'][] = 'format_number_user_settings_form_validate';
}
}
function format_number_user_presave(&$edit, $account, $category) {
if (isset($edit['decimal_point'])) {
$edit['data']['decimal_point'] = $edit['decimal_point'];
}
if (isset($edit['thousands_sep'])) {
$edit['data']['thousands_sep'] = $edit['thousands_sep'];
}
}
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 (isset($user->data['thousands_sep']) && drupal_strlen($user->data['thousands_sep'])) {
$format_options['thousands_sep'] = $user->data['thousands_sep'];
}
if (isset($user->data['decimal_point']) && drupal_strlen($user->data['decimal_point'])) {
$format_options['decimal_point'] = $user->data['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_element_info() {
return array(
'numericfield' => array(
'#input' => TRUE,
'#precision' => 12,
'#decimals' => 0,
'#process' => array(
'format_number_numericfield_process',
),
'#element_validate' => array(
'format_number_numericfield_validate',
),
'#theme' => 'numericfield',
),
);
}
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, &$form_state) {
$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,
);
}
return $element;
}
function form_type_numericfield_value($element, $input = FALSE) {
if ($input !== FALSE && $input !== NULL) {
$value = trim(str_replace(array(
"\r",
"\n",
), '', $input));
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($variables) {
format_number_add_js();
$element =& $variables['element'];
$element['#attributes']['type'] = 'text';
element_set_attributes($element, array(
'id',
'name',
'value',
'size',
'maxlength',
));
_form_set_class($element, array(
'form-text',
'form-numeric',
));
$variables['element']['#children'] = '<input' . drupal_attributes($element['#attributes']) . ' />';
return theme('form_element', $variables);
}