Index: cck_phone.info
===================================================================
RCS file: /cvs/drupal/contributions/modules/cck_phone/cck_phone.info,v
retrieving revision 1.1
diff -u -r1.1 cck_phone.info
--- cck_phone.info	8 Jul 2010 11:20:27 -0000	1.1
+++ cck_phone.info	22 Jul 2010 13:11:15 -0000
@@ -1,7 +1,18 @@
 ; $Id: cck_phone.info,v 1.1 2010/07/08 11:20:27 ckng Exp $
-name = Phone Number
-description = "The phone module allows administrators to define a CCK field type for phone numbers."
+name = Phone number
+description = Defines a field type for phone number.
 package = CCK
-dependencies[] = content
-core = 6.x
-
+core = 7.x
+files[] = cck_phone.module
+files[] = theme/phone-field-view.tpl.php
+files[] = includes/cck_phone_countrycodes.inc
+files[] = includes/phone.ca.inc
+files[] = includes/phone.gb.inc
+files[] = includes/phone.my.inc
+files[] = includes/phone.ph.inc
+files[] = includes/phone.us.inc
+files[] = tests/cck_phone.crud.test
+files[] = tests/cck_phone.crud_input.test
+files[] = tests/phone.gb.test
+files[] = tests/phone.my.test
+files[] = tests/phone.us.test
\ No newline at end of file
Index: cck_phone.install
===================================================================
RCS file: /cvs/drupal/contributions/modules/cck_phone/cck_phone.install,v
retrieving revision 1.1
diff -u -r1.1 cck_phone.install
--- cck_phone.install	8 Jul 2010 11:20:27 -0000	1.1
+++ cck_phone.install	23 Jul 2010 11:58:48 -0000
@@ -7,13 +7,12 @@
  * Installation file
  */
 
-
+ 
 /**
- * Implementation of hook_install().
- */
+* Implementation of hook_install().
+*/
 function cck_phone_install() {
-  drupal_load('module', 'content');
-  content_notify('install', 'cck_phone');
+  _cck_phone_update_country_code_list();
   drupal_set_message(st('Phone number module installed successfully.'));
 }
 
@@ -21,27 +20,51 @@
  * Implementation of hook_uninstall().
  */
 function cck_phone_uninstall() {
-  drupal_load('module', 'content');
-  content_notify('uninstall', 'cck_phone');
+  variable_del('cck_phone_custom_cc');
 }
 
 /**
  * Implementation of hook_enable().
- *
- * Notify content module when this module is enabled.
  */
 function cck_phone_enable() {
   // TODO: Migration path for phone.module to cck_phone
-  drupal_load('module', 'content');
-  content_notify('enable', 'cck_phone');
 }
 
 /**
  * Implementation of hook_disable().
- *
- * Notify content module when this module is disabled.
  */
 function cck_phone_disable() {
-  drupal_load('module', 'content');
-  content_notify('disable', 'cck_phone');
+
+}
+
+/**
+ * Update list of country codes phone validation.
+ */
+function cck_phone_update_7000() {
+  _cck_phone_update_country_code_list();
 }
+
+/**
+ * Store country code phone validation.
+ *
+ * This function should be called only at hook_update_N()
+ * when new country phone library is added.
+ */
+function _cck_phone_update_country_code_list() {
+  // This function is too expensive to call at hook_init() and 
+  // should be called only if there's a new country code added.
+  
+  // Load custom country codes phone number includes
+  $path = drupal_get_path('module', 'cck_phone') .'/includes';
+  // Scan include phone numbers directory
+  $files = file_scan_directory($path, '/^phone\..*\.inc$/');
+
+  $countrycodes = array();
+  foreach ($files as $file) {
+    list ($dummy, $countrycode) = explode('.', $file->name);
+    // Faster using array key
+    $countrycodes[$countrycode] = $countrycode;
+  }
+  // Save the list of country codes phone validation
+  variable_set('cck_phone_custom_cc', $countrycodes);
+}
\ No newline at end of file
Index: cck_phone.module
===================================================================
RCS file: /cvs/drupal/contributions/modules/cck_phone/cck_phone.module,v
retrieving revision 1.3
diff -u -r1.3 cck_phone.module
--- cck_phone.module	12 Jul 2010 09:54:52 -0000	1.3
+++ cck_phone.module	26 Jul 2010 13:54:58 -0000
@@ -3,341 +3,321 @@
 
 /**
  * @file
- * Defines phone number fields for CCK.
+ * Defines a field type for phone numbers.
  * Provide some verifications on the phone numbers
  */
 
 define('CCK_PHONE_PHONE_MIN_LENGTH', 4);   // Is there a phone number less than 4 digits?
 define('CCK_PHONE_PHONE_MAX_LENGTH', 15);  // International standard 15 digits
 define('CCK_PHONE_EXTENSION_MAX_LENGTH', 6);
-define('CCK_PHONE_CC_MAX_LENGTH', 2);
-define('CCK_PHONE_MOBILE_AGENT', '/(ipod|iphone|android|blackberry|palm|nokia|opera\s+mobi|opera\s+mini|windows\s+ce|iemobile)/i');
+define('CCK_PHONE_TEXTFIELD_MAX_LENGTH', 60);
 
 /**
- * Implementation of hook_init().
- * This hook is called on module initialization.
- */
-function cck_phone_init() {
-  // load country codes
-  module_load_include('inc', 'cck_phone', 'cck_phone_countrycodes');
-
-  // load custom country codes phone number includes
-  $path = drupal_get_path('module', 'cck_phone') .'/includes';
-  // scan include phone numbers directory
-  $files = file_scan_directory($path, '^phone\..*\.inc$');
-
-  $countrycodes = array();
-  foreach ($files as $file) {
-    module_load_include('inc', 'cck_phone', '/includes/'. $file->name);
-    list ($dummy, $countrycode) = explode('.', $file->name);
-    // faster using array key
-    $countrycodes[$countrycode] = $countrycode;
-  }
-
-  // save the list of country codes phone validation
-  variable_set('cck_phone_custom_cc', $countrycodes);
-}
-
-/**
- * Implementation of hook_theme().
+ * Implementation of hook_field_info().
  */
-function cck_phone_theme() {
+function cck_phone_field_info() {
   return array(
     'phone_number' => array(
-      'arguments' => array('element' => NULL),
-    ),
-    'phone_number_extension' => array(
-      'arguments' => array('extension' => ''),
-    ),
-    'cck_phone_formatter_default' => array(
-      'arguments' => array('element' => NULL),
-    ),
-    'cck_phone_formatter_local' => array(
-      'arguments' => array('element' => NULL),
-    ),
-    'cck_phone_mobile_tel' => array(
-      'arguments' => array('element' => NULL, 'phone' => ''),
+      'label'       => t('Phone number'),
+      'description' => t('Defines a field type for phone numbers.'),
+      'settings' => array(
+        'textfield_size'    => CCK_PHONE_TEXTFIELD_MAX_LENGTH,
+      ),
+      'instance_settings' => array(
+        'default_country'   => NULL,
+        'all_country_codes' => TRUE,
+        'phone_as_link'     => TRUE,       
+      ),
+      'default_widget'    => 'phone_textfield',
+      'default_formatter' => 'phone_formatter',
     ),
   );
 }
 
+/**
+ * Implements hook_field_settings_form().
+ */
+function cck_phone_field_settings_form($field, $instance) {
+  $form     = array();
+  $defaults = field_info_field_settings($field['type']);
+  $settings = array_merge($defaults, $field['settings']);
+  $form['textfield_size'] = array(
+    '#type'          => 'textfield',
+    '#title'         => t('Size of textfield'),
+    '#default_value' => $settings['textfield_size'],
+    '#description'   => t('Enter phone number textfield\'s width.'),
+  );  
+  return $form;
+}
+
+/**
+ * Implements hook_field_instance_settings_form().
+ */
+function cck_phone_field_instance_settings_form($field, $instance) {
+  drupal_add_css(drupal_get_path('module', 'cck_phone') . '/css/cck_phone.css');
+  drupal_add_js(drupal_get_path('module', 'cck_phone') . '/js/cck_phone.manage_field.js');
+  $form       = array();
+  $defaults   = field_info_instance_settings($field['type']);
+  $settings   = array_merge($defaults, $instance['settings']);
+  $cc_options = _cck_phone_cc_options(TRUE);
+  $form['default_country'] = array(
+    '#type'          => 'select',
+    '#title'         => t('Default country code'),
+    '#default_value' => $settings['default_country'],
+    '#options'       => $cc_options,
+    '#weight'        => 1,
+  );
+  $form['all_country_codes'] = array(
+    '#type'          => 'checkbox',
+    '#title'         => t('Show all country codes.'),
+    '#default_value' => $settings['all_country_codes'],
+    '#description'   => t('Uncheck this to select the country to be displayed.'),
+    '#weight'        => 1.1,
+  );
+  // Country codes settings
+  $form['country_codes'] = array(    
+    '#type'        => 'fieldset',
+    '#title'       => 'Country selection',
+    '#attributes'  => array('class' => array('cck-phone-settings')),
+    '#collapsible' => TRUE,
+    '#collapsed'   => TRUE,    
+    '#weight'      => 2,
+    '#description'   => t('Country marks with * has custom country code settings and/or validation.'),
+  );
+  $form['country_codes']['country_selection'] = array(
+    '#type'          => 'checkboxes',
+    '#title'         => t('Select country codes to be included'),    
+    '#default_value' => isset($instance['settings']['country_codes']['country_selection']) && !empty($instance['settings']['country_codes']['country_selection']) ? $instance['settings']['country_codes']['country_selection'] : array($instance['settings']['default_country'] => $instance['settings']['default_country']),
+    '#options'       => $cc_options,    
+  );
+  // We don't need to detect if the device is mobile. RDFA FOAF states:
+  // A phone, specified using fully qualified tel: URI scheme 
+  // (http://xmlns.com/foaf/spec/#term_phone)
+  $form['phone_as_link'] = array(
+    '#type'          => 'checkbox',
+    '#title'         => t('Display phone number as link. !foaf: A phone, specified using fully qualified tel: URI scheme', array('!foaf' => l('RDFA FOAF', 'http://xmlns.com/foaf/spec/#term_phone'))),
+    '#default_value' => $settings['phone_as_link'],
+    '#weight'        => 3,
+  );
+  return $form;
+}
 
 /**
- * Implementation of hook_field_info().
+ * Implements hook_field_schema().
  */
-function cck_phone_field_info() {
+function cck_phone_field_schema($field) {
   return array(
-    'phone_number' => array(
-      'label' => t('Phone number'),
-      'description' => t('Store a number and country code in the database to assemble a phone number.'),
+    'columns' => array(
+      'country' => array(
+        'type'        => 'varchar',
+        'length'      => 2,
+        'not null'    => TRUE,
+        'description' => t('ISO 3166 2-character country code.'),
+      ),
+      'int_code' => array(
+        'type'        => 'int',
+        'not null'    => TRUE,
+        'description' => t('International country calling code.'),
+      ),
+      'value' => array(
+        'type'        => 'varchar',
+        'length'      => CCK_PHONE_PHONE_MAX_LENGTH,
+        'not null'    => TRUE,
+        'description' => t('Sanitized phone number with area code.'),
+      ),
+    ),
+    'indexes' => array(
+      'value_index' => array('value'),
     ),
   );
 }
 
 /**
- * Implementation of hook_field_settings().
+ * Implements hook_field_validate().
  */
-function cck_phone_field_settings($op, $field) {
-  switch ($op) {
-    case 'form':
-      drupal_add_css(drupal_get_path('module', 'cck_phone') . '/cck_phone.css');
-      drupal_add_js(drupal_get_path('module', 'cck_phone') . '/cck_phone.js');
-
-      $form = array();
-      $form['default_country'] = array(
-        '#type' => 'select',
-        '#title' => t('Default country code'),
-        '#default_value' => isset($field['default_country']) && ($field['default_country'] !== '') ? $field['default_country'] : NULL,
-        '#options' => _cck_phone_cc_options(TRUE),
-      );
-
-      $form['all_country_codes'] = array(
-        '#type' => 'checkbox',
-        '#title' => t('Show all country codes.'),
-        '#default_value' => isset($field['all_country_codes']) && ($field['all_country_codes'] !== '') ? $field['all_country_codes'] : TRUE,
-        '#description' => t('Uncheck this to select the country to be displayed.'),
-      );
-
-      // Country codes settings
-      $form['country_codes'] = array(
-        '#title' => 'Country selection',
-        '#type' => 'fieldset',
-        '#collapsible' => TRUE,
-        '#collapsed' => TRUE,
-        '#attributes' => array('class' => 'cck-phone-settings'),
-      );
-
-      $form['country_codes']['country_selection'] = array(
-        '#type' => 'checkboxes',
-        '#title' => t('Select country codes to be included'),
-        '#default_value' => isset($field['country_selection']) && !empty($field['country_selection']) ? $field['country_selection'] : array($field['default_country'] => $field['default_country']),
-        '#options' => _cck_phone_cc_options(TRUE),
-        '#description' => t('Country marks with <em>*</em> has custom country code settings and/or validation.'),
-      );
-
-      $form['enable_custom_country'] = array(
-        '#type' => 'checkbox',
-        '#title' => t('Enable country level validation'),
-        '#default_value' => isset($field['enable_custom_country']) && ($field['enable_custom_country'] !== '') ? $field['enable_custom_country'] : TRUE,
-        '#description' => t('Uncheck this to disable stringent country phone number validation.'),
-      );
-
-      $form['enable_extension'] = array(
-        '#type' => 'checkbox',
-        '#title' => t('Enable phone extension support'),
-        '#default_value' => isset($field['enable_extension']) && ($field['enable_extension'] !== '') ? $field['enable_extension'] : FALSE,
-        '#description' => t('Check this to enable phone number extension field.'),
-      );
-
-      $form['enable_mobile'] = array(
-        '#type' => 'checkbox',
-        '#title' => t('Enable mobile device detection'),
-        '#default_value' => isset($field['enable_mobile']) && ($field['enable_mobile'] !== '') ? $field['enable_mobile'] : FALSE,
-        '#description' => t('Check this to enable phone number link on mobile browsers (RFC3966).'),
-      );
-
-      // Display country specific settings
-      foreach (_cck_phone_custom_cc() as $cc) {
-        $function = $cc . '_phone_field_settings';
-        if (function_exists($function)) {
-          $country_settings = $function($op, $field);
-          if (isset($country_settings) && !empty($country_settings)) {
-            $country_codes = cck_phone_countrycodes($cc);
-            // Wrap with fieldset
-            $wrapper = array(
-              '#title' => $country_codes['country'] . ' specific settings',
-              '#type' => 'fieldset',
-              '#collapsible' => TRUE,
-              '#collapsed' => TRUE,
-              '#attributes' => array('class' => 'cck-phone-settings cck-phone-settings-' . $cc),
+function cck_phone_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
+  $field_name = $field['field_name'];
+  foreach ($items as $delta => $item) {
+    $phone_value = check_plain(preg_replace('/[^0-9]/', '', $item['value']));
+    if (!empty($phone_value)) {
+      $subaddress_value = check_plain($item['subaddress_value']);
+      // Lenient checking, as long as it doesn't have invalid phone number characters
+      $regex = '/^
+        [+\s.()-]*  # optional separator
+        (?:         # }
+          \d        # } 4-15 digits number
+          [\s.()-]* # } each followed by optional separator
+        ){'. CCK_PHONE_PHONE_MIN_LENGTH .','. CCK_PHONE_PHONE_MAX_LENGTH .'} # }
+      $/x';
+      // Generic number validation
+      if (!preg_match($regex, $phone_value)) {
+        $errors[$field_name][$langcode][$delta][] = array(
+          'error'   => 'value',
+          'message' => t('Phone number must be numeric and %min_length to %max_length length.', array('%min_length' => CCK_PHONE_PHONE_MIN_LENGTH, '%max_length' => CCK_PHONE_PHONE_MAX_LENGTH)),
+        );
+      }
+      else {
+        $code = $item['country'];
+        // Custom country level validation
+        $validate_function = $code . '_validate_number';
+        $has_cc = module_load_include('inc', 'cck_phone', 'includes/phone.' . $code) && function_exists($validate_function);
+        if ($has_cc) {
+          if (!$validate_function($phone_value, '', $error_message)) {
+            $errors[$field_name][$langcode][$delta][] = array(
+              'error'   => 'value',
+              'message' => $error_message,
             );
-            $wrapper[] = $country_settings;
-            array_push($form, $wrapper);
           }
         }
       }
-
-      return $form;
-
-    case 'validate':
-      // Validate country specific settings
-      foreach (_cck_phone_custom_cc() as $cc)  {
-        $function = $cc . '_phone_field_settings';
-        if (function_exists($function)) {
-          $function($op, $field);
-        }
-      }
-      break;
-
-    case 'save':
-      $settings = array('default_country', 'all_country_codes', 'country_selection', 'enable_custom_country', 'enable_extension', 'enable_mobile');
-
-      // Save country specific settings
-      foreach (_cck_phone_custom_cc() as $cc)  {
-        $function = $cc . '_phone_field_settings';
-        if (function_exists($function)) {
-          array_push($settings, $function($op, $field));
-        }
-      }
-      return $settings;
-
-    // TODO: filters for phone number?
-//    case 'filters':
-//      break;
-
-    case 'database columns':
-      return array(
-        'number' => array(
-          'type' => 'varchar',
-          'length' => CCK_PHONE_PHONE_MAX_LENGTH,
-          'not null' => FALSE,
-        ),
-        'country_codes' => array(
-          'type' => 'varchar',
-          'length' => CCK_PHONE_CC_MAX_LENGTH,
-          'not null' => FALSE,
-        ),
-        'extension' => array(
-          'type' => 'varchar',
-          'length' => CCK_PHONE_EXTENSION_MAX_LENGTH,
-          'not null' => FALSE,
-        ),
-      );
+    }
   }
 }
 
 /**
- * Implementation of hook_field().
+ * Implements hook_field_widget_error().
  */
-function cck_phone_field($op, &$node, $field, &$items, $teaser, $page) {
-  switch ($op) {
-    case 'validate':
-      foreach ($items as $delta => $value) {
-        _cck_phone_validate($items[$delta], $delta, $field, $node);
-      }
-
-      return $items;
-      break;
-
-    case 'presave':
-      foreach ($items as $delta => $value) {
-        _cck_phone_process($items[$delta], $delta, $field, $node);
-      }
-      break;
-
-    // Do country level code need to modify the output?
-    case 'sanitize':
-      foreach ($items as $delta => $value) {
-        _cck_phone_sanitize($items[$delta], $delta, $field, $node);
-      }
-      break;
+function cck_phone_field_widget_error($element, $error, $form, &$form_state) {
+  $element['#parents'][] = $error['error'];
+  form_error($element, $error['message'], $form, $form_state);
+}
 
+/**
+ * Implements hook_field_presave().
+ */
+function cck_phone_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  module_load_include('inc', 'cck_phone', 'includes/cck_phone_countrycodes');
+  $list = cck_phone_countrycodes();
+  foreach ($items as $delta => $item) {
+    $code  = $item['country'];
+    $value = check_plain(preg_replace('/[^0-9]/', '', $item['value']));
+    $sanitize_number_function = $code . '_sanitize_number';
+    if (function_exists($sanitize_number_function)) {
+      $sanitize_number_function($value);
+    }    
+    $items[$delta]['value']    = $value;
+    $items[$delta]['int_code'] = (int) preg_replace('/^\+/', '', $list[$code]['code']);
   }
+}
 
+/**
+ * Implements hook_field_is_empty().
+ */
+function cck_phone_field_is_empty($item, $field) {
+  return empty($item['value']);
 }
 
+/**************************************************************************
+ * Field Type API: Widget
+ *
+ * The widget is the form element used to receive input from the user
+ * when the field is being populated.
+ **************************************************************************/
 /**
- * Implementation of hook_field_formatter_info().
+ * Implement hook_field_widget_info().
  */
-function cck_phone_field_formatter_info() {
+function cck_phone_field_widget_info() {
   return array(
-    'default' => array(
-      'label' => 'Global phone number (default)',
+    'phone_textfield' => array(
+      'label'       => t('Textfield'),
       'field types' => array('phone_number'),
-      'multiple values' => CONTENT_HANDLE_CORE,
-    ),
-    'local' => array(
-      'label' => 'Local phone number',
-      'field types' => array('phone_number'),
-      'multiple values' => CONTENT_HANDLE_CORE,
     ),
   );
 }
 
 /**
- * Theme function for phone extension.
+ * Implements hook_field_widget_form().
  */
-function theme_phone_number_extension($extension = '') {
-  return t('<em> ext.</em> @extension', array('@extension' => $extension));
+function cck_phone_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
+  $field_name  = $field['field_name'];
+  $elements = array();
+  $elements['phone_field'] = $element;
+  $elements['phone_field']['#type'] = 'item';  
+  $elements['phone_field']['value'] = array(
+    '#type'           => 'textfield',
+    '#size'           => $field['settings']['textfield_size'] ? $field['settings']['textfield_size'] : CCK_PHONE_TEXTFIELD_MAX_LENGTH,
+    '#maxlength'      => CCK_PHONE_PHONE_MAX_LENGTH,
+    '#default_value'  => isset($items[$delta]['value']) ? $items[$delta]['value'] : '',
+    '#parents'        => array($field_name, $langcode, $delta, 'value'),
+  );
+  $elements['phone_field']['phone_advance'] = array(
+    '#type'        => 'fieldset',
+    '#title'       => t('Phone number options'),
+    '#collapsible' => TRUE,
+    '#collapsed'   => TRUE,
+  );
+  $elements['phone_field']['phone_advance']['country'] = array(
+    '#type'           => 'select',
+    '#title'          => t('Country code'),
+    '#default_value'  => isset($items[$delta]['country']) ? $items[$delta]['country'] : $instance['settings']['default_country'],
+    '#parents'        => array($field_name, $langcode, $delta, 'country'),
+  );
+  if ($instance['settings']['all_country_codes']) {
+    $elements['phone_field']['phone_advance']['country']['#options'] = _cck_phone_cc_options();
+  }
+  else {
+    $elements['phone_field']['phone_advance']['country']['#options'] = _cck_phone_cc_options(FALSE, $instance['settings']['country_codes']['country_selection']);
+  }
+  return $elements;
 }
 
+/***********************************************************************
+ *  Field Type API: Formatter
+ *
+ *  These are the api hooks that present formatted (themed) output to the
+ *  user.
+ **********************************************************************/
 /**
- * Theme function for mobile tel.
+ *Implementation of hook_field_formatter_info().
  */
-function theme_cck_phone_mobile_tel($element, $phone = '') {
-  $item = $element['#item'];
-
-  // Mobile browsers support
-  if (isset($item['mobile_output']) && $item['mobile_output'] == TRUE) {
-    // Always output as global phone number without separator, leave the $phone display unchanged
-    $cc = cck_phone_countrycodes($item['country_codes']);
-    $tel = $cc['code'] . $item['number'];
-
-    $phone = '<a href="tel:' . $tel . '">' . $phone . '</a>';
-  }
-
-  return $phone;
+function cck_phone_field_formatter_info() {
+    return array(
+    'phone_formatter' => array(
+      'label'       => t('Phone number'),
+      'field types' => array('phone_number'),
+    ),
+  );
 }
 
 /**
- * Theme function for 'default' or global phone number field formatter.
+ * Implements hook_field_formatter_view().
  */
-function theme_cck_phone_formatter_default($element) {
-  $item = $element['#item'];
-  $phone = '';
-
-  // Display a global phone number with country code.
-  if (!empty($item['number']) && !empty($item['country_codes'])) {
-    // Call country default formatter if exist
-    $function = $item['country_codes'] . '_formatter_default';
-    if (function_exists($function)) {
-      $phone = $function($element);
+function cck_phone_field_formatter_view($object_type, $object, $field, $instance, $langcode, $items, $display) {
+  $element    = array();
+  $type_class = array('type');
+  foreach ($items as $delta => $item) {
+    $code      = $item['country'];
+    $int_code  = $item['int_code'];
+    $tel_value = '+' . $item['int_code'] . $item['value'];
+    $formatter_default_function = $code . '_formatter_default';
+    module_load_include('inc', 'cck_phone', 'includes/phone.' . $code);
+    if (function_exists($formatter_default_function)) {
+      $format = $formatter_default_function($item['value']);
     }
     else {
-      $cc = cck_phone_countrycodes($item['country_codes']);
-      $phone = $cc['code'] .'-'. $item['number'];
+      $format = $item['value'];
     }
-
-    // Extension
-    if (!empty($item['extension'])) {
-      $phone = $phone . theme('phone_number_extension', $item['extension']);
-    }
-
-    // Mobile browsers support
-    $phone = theme('cck_phone_mobile_tel', $element, $phone);
+    $details = array(
+      'value'      => $format,
+      'int_code'   => $int_code,
+      'tel_value'  => $tel_value,
+    );
+    $element[$delta]['#markup'] = theme('phone_field_view', array('phone' => $details));
   }
-
-  return $phone;
+  return $element;
 }
 
 /**
- * Theme function for 'local' phone number field formatter.
+ * Implementation of hook_theme()
  */
-function theme_cck_phone_formatter_local($element) {
-  $item = $element['#item'];
-  $phone = '';
-
-  // Display a local phone number without country code.
-  if (!empty($item['number'])) {
-    // Call country local formatter if exist
-    $function = $item['country_codes'] . '_formatter_local';
-    if (function_exists($function)) {
-      $phone = $function($element);
-    }
-    else {
-      $phone = $item['number'];
-    }
-
-    // Extension
-    if (!empty($item['extension'])) {
-      $phone = $phone . theme('phone_number_extension', $item['extension']);
-    }
-
-    // Mobile browsers support
-    $phone = theme('cck_phone_mobile_tel', $element, $phone);
-  }
-
-  return $phone;
+function cck_phone_theme($existing, $type, $theme, $path) {
+  return array(
+    'phone_field_view' => array(
+      'render element' => 'phone',
+      'template' 	     => 'phone-field-view',
+      'path'           => drupal_get_path('module', 'cck_phone') . '/theme',
+    ),
+  );
 }
 
 /**
@@ -350,16 +330,19 @@
  * @return string
  */
 function _cck_phone_cc_options($show_custom = FALSE, $country_selection = array()) {
+  // Load country codes
+  module_load_include('inc', 'cck_phone', 'includes/cck_phone_countrycodes');
+  
   $options = array();
-
   if ($show_custom) {
     $custom_cc = _cck_phone_custom_cc();
   }
-
-  foreach (cck_phone_countrycodes() as $cc => $value) {
+  
+  $list = cck_phone_countrycodes();
+  foreach ($list as $cc => $value) {
     $cc_name = $value['country'] .' ('. $value['code'] .')';
 
-    // faster using array key instead of in_array
+    // Faster using array key instead of in_array
     if ($show_custom && isset($custom_cc[$cc])) {
       $cc_name .= ' *';
     }
@@ -380,401 +363,9 @@
  *   Array of country codes abbreviation or FALSE if none exist.
  */
 function _cck_phone_custom_cc() {
-  static $cc;
-
+  $cc = &drupal_static(__FUNCTION__);
   if (!isset($cc)) {
     $cc = variable_get('cck_phone_custom_cc', FALSE);
   }
-
   return $cc;
-}
-
-function _cck_phone_valid_input($input) {
-  // lenient checking, as long as don't have invalid phone number character
-  $regex = '/^
-    [\s.()-]*     # optional separator
-    (?:           # }
-      \d          # } 4-15 digits number
-      [\s.()-]*   # } each followed by optional separator
-    ){'. CCK_PHONE_PHONE_MIN_LENGTH .','. CCK_PHONE_PHONE_MAX_LENGTH .'}       # }
-    $/x';
-
-  return preg_match($regex, $input);
-}
-
-function _cck_phone_valid_cc_input($list, $cc) {
-  if (isset($list[$cc]) && $list[$cc] == $cc) {
-    return TRUE;
-  }
-
-  return FALSE;
-}
-
-function _cck_phone_validate(&$item, $delta, $field, $node) {
-  $phone_input = trim($item['number']);
-  $countrycode = trim($item['country_codes']);
-  $ext_input = '';
-  if ($field['enable_extension']) {
-    $ext_input = trim($item['extension']);
-  }
-
-  if ($phone_input && !(isset($field['widget']['default_value'][$delta]['number']) && $phone_input == $field['widget']['default_value'][$delta]['number'] && !$field['required'])) {
-
-    $error_params = array(
-      '%phone_input' => check_plain($phone_input),   // original phone input
-      '%countrycode' => check_plain($countrycode),
-      '%min_length' => CCK_PHONE_PHONE_MIN_LENGTH,
-      '%max_length' => CCK_PHONE_PHONE_MAX_LENGTH,
-      '%ext_input' => check_plain($ext_input),
-      '%ext_max_length' => CCK_PHONE_EXTENSION_MAX_LENGTH,
-    );
-
-    // Only allow digit, dash, space and bracket
-    if (!_cck_phone_valid_input($phone_input, $ext_input)) {
-      $error = t('Phone number must be %min_length-%max_length digits only.', $error_params);
-      if ($field['enable_extension'] && $ext_input != '') {
-        $error .= '<br />'. t('Phone extension must be less than %ext_max_length digits.', $error_params);
-      }
-
-      form_set_error($field['field_name'], $error);
-    }
-    else {
-      if (!$field['all_country_codes']) {
-        if (!_cck_phone_valid_cc_input($field['country_selection'], $countrycode)) {
-          $error = t('Invalid country code "%countrycode" submitted.', $error_params);
-          form_set_error($field['field_name'], $error);
-        }
-      }
-      // Generic number validation
-      if (!cck_phone_validate_number($countrycode, $phone_input, $ext_input)) {
-        $error = t('Phone number must be %min_length-%max_length digits only.', $error_params);
-        if ($field['enable_extension'] && $ext_input != '') {
-          $error .= '<br />'. t('Phone extension must be less than %ext_max_length digits.', $error_params);
-        }
-
-        form_set_error($field['field_name'], $error);
-      }
-      // Country level validation if enabled
-      elseif ($field['enable_custom_country'] != 0 || is_null($field['enable_custom_country']) || !isset($field['enable_custom_country'])) {
-        $custom_cc = _cck_phone_custom_cc();
-
-        if (isset($custom_cc[$countrycode])) {
-          $validate_function = $countrycode . '_validate_number';
-
-          if (function_exists($validate_function)) {
-            $error = '';
-            if (!$validate_function($phone_input, $ext_input, $error)) {
-              form_set_error($field['field_name'], t($error, $error_params));
-            }
-          }
-        }
-      }
-    }
-  }
-}
-
-function _cck_phone_process(&$item, $delta = 0, $field, $node) {
-  $widget = $field['widget']['default_value'][$delta];
-  // Clean up the phone number.
-  $item['number'] = cck_phone_clean_number($item['number']);
-  $item['extension'] = cck_phone_clean_number($item['extension']);
-
-  // Don't save an invalid default value.
-  if ((isset($widget['number']) && $item['number'] == $widget['number']) && (isset($widget['country_codes']) && $item['country_codes'] == $widget['country_codes']) && is_object($node)) {
-    if (!cck_phone_validate_number($item['country_codes'], $item['number'], $item['extension'])) {
-      unset($item['number']);
-      unset($item['country_codes']);
-      unset($item['extension']);
-    }
-  }
-}
-
-/**
- * Cleanup user-entered values for a phone number field according to field settings.
- *
- * @param $item
- *   A single phone number item, usually containing number and country code.
- * @param $delta
- *   The delta value if this field is one of multiple fields.
- * @param $field
- *   The CCK field definition.
- * @param $node
- *   The node containing this phone number.
- */
-function _cck_phone_sanitize(&$item, $delta, &$field, &$node) {
-  if (!empty($item['number'])) {
-    $cc = $item['country_codes'];
-    $item['number'] = cck_phone_clean_number($item['number']);
-
-    $custom_cc = _cck_phone_custom_cc();
-    if (isset($custom_cc[$cc])) {
-      $function = $cc . '_sanitize_number';
-
-      if (function_exists($function)) {
-        $function($item['number']);
-      }
-    }
-  }
-
-  if ($field['enable_extension']) {
-    $item['extension'] = cck_phone_clean_number($item['extension']);
-  }
-  else {
-    unset($item['extension']);
-  }
-
-  if ($field['enable_mobile'] && preg_match(CCK_PHONE_MOBILE_AGENT, drupal_strtolower($_SERVER['HTTP_USER_AGENT']))) {
-    $item['mobile_output'] = TRUE;
-  }
-}
-
-
-/**
- * Implementation of hook_widget_info().
- */
-function cck_phone_widget_info() {
-  return array(
-    'phone_number' => array(
-      'label' => t('Phone number'),
-      'field types' => array('phone_number'),
-      'multiple values' => CONTENT_HANDLE_CORE,
-    ),
-  );
-}
-
-/**
- * Implementation of hook_widget_settings().
- */
-function cck_phone_widget_settings($op, $widget) {
-  switch ($op) {
-    case 'form':
-      $form = array();
-      $size = (isset($widget['size']) && is_numeric($widget['size'])) ? $widget['size'] : CCK_PHONE_PHONE_MAX_LENGTH;
-      $form['input']['size'] = array(
-        '#type' => 'textfield',
-        '#title' => t('Size of phone number textfield'),
-        '#default_value' => $size,
-        '#element_validate' => array('_element_validate_integer_positive'),
-        '#required' => TRUE,
-        '#description' => t('International number is maximum 15 digits with additional country code, default is %length.', array('%length' => CCK_PHONE_PHONE_MAX_LENGTH)),
-      );
-      return $form;
-
-    case 'save':
-      return array('size');
-  }
-}
-
-/**
- * Implementation of hook_widget().
- */
-function cck_phone_widget(&$form, &$form_state, $field, $items, $delta = 0) {
-  $element = array(
-    '#type' => $field['widget']['type'],
-    '#default_value' => isset($items[$delta]) ? $items[$delta] : '',
-    '#title' => $field['widget']['label'],
-    '#weight' => $field['widget']['weight'],
-    '#description' => $field['widget']['description'],
-    '#required' => $field['required'],
-    '#field' => $field,
-  );
-  return $element;
-}
-
-/**
- * Implementation of hook_content_is_empty().
- */
-function cck_phone_content_is_empty($item, $field) {
-  if (empty($item['number'])) {
-    return TRUE;
-  }
-  return FALSE;
-}
-
-/**
- * Implementation of FAPI hook_elements().
- */
-function cck_phone_elements() {
-  return array(
-    'phone_number' => array(
-      '#input' => TRUE,
-      '#process' => array('cck_phone_process'),
-      '#autocomplete_path' => FALSE,
-    ),
-  );
-}
-
-/**
- * FAPI theme for an individual phone number elements.
- *
- * The phone number is already rendered by the themes and the html
- * output lives in $element['#children']. Override this theme to
- * make custom changes to the output.
- *
- * $element['#title'] is the field title
- * $element['#field_name'] contains the field name
- * $element['#delta''] is the position of this element in the group
- * $element['number] is the phone number
- * $element['country_codes'] is the country code
- */
-function theme_phone_number($element) {
-  drupal_add_css(drupal_get_path('module', 'cck_phone') .'/cck_phone.css');
-
-  // Prefix single value phone number fields with the name of the field.
-//  if (empty($element['#field']['multiple'])) {
-//    if (isset($element['number']) && isset($element['country_codes'])) {
-//      $element['number']['#title'] = $element['#title'] .' '. $element['number']['#title'];
-//      $element['country_codes']['#title'] = $element['#title'] .' '. $element['country_codes']['#title'];
-//    }
-//    elseif ($element['number']) {
-//      $element['number']['#title'] = $element['#title'];
-//    }
-//  }
-
-  $output = '';
-
-  $output = '<div class="form-item"';
-  if (!empty($element['#id'])) {
-    $output .= ' id="'. $element['#id'] .'-wrapper"';
-  }
-  $output .= ">\n";
-
-  $required = !empty($element['#required']) ? '<span class="form-required" title="'. t('This field is required.') .'">*</span>' : '';
-
-  if (!empty($element['#title'])) {
-    $title = $element['#title'];
-    if (!empty($element['number']['#id'])) {
-      $output .= ' <label for="'. $element['number']['#id'] .'">'. t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) ."</label>\n";
-    }
-    else {
-      $output .= ' <label>'. t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) ."</label>\n";
-    }
-  }
-
-  $output .= '<div class="cck-phone-field clear-block">';
-  if (isset($element['number'])) {
-    $output .= '<div class="cck-phone-field-phone cck-phone-column">'. theme('textfield', $element['number']) .'</div>';
-  }
-  if (isset($element['extension'])) {
-    $prefix = isset($element['extension']['#prefix']) ? $element['extension']['#prefix'] : '';
-    $output .= '<div class="cck-phone-field-ext cck-phone-column">'. $prefix . theme('textfield', $element['extension']) .'</div>';
-  }
-  $output .= '<div class="cck-phone-field-cc cck-phone-column">'. theme('select', $element['country_codes']) .'</div>';
-  $output .= '</div></div>';
-
-  return $output;
-}
-
-/**
- * Process an individual element.
- */
-function cck_phone_process($element, $edit, $form_state, $form) {
-  $field_name = $element['#field_name'];
-  $field = $form['#field_info'][$field_name];
-  $field_key  = $element['#columns'][0];
-  $delta = $element['#delta'];
-
-  $element['number'] = array(
-    '#type' => 'textfield',
-    '#maxlength' => CCK_PHONE_PHONE_MAX_LENGTH,
-    '#size' => CCK_PHONE_PHONE_MAX_LENGTH,
-//    '#title' => t('Number'),
-    '#description' => $element['#description'],
-    '#required' => ($delta == 0 && $field['number'] !== 'optional') ? $element['#required'] : FALSE,
-    '#default_value' => isset($element['#value']['number']) ? $element['#value']['number'] : NULL,
-  );
-
-  if ($field['enable_extension']) {
-    $element['extension'] = array(
-     '#type' => 'textfield',
-     '#maxlength' => CCK_PHONE_EXTENSION_MAX_LENGTH,
-     '#size' => CCK_PHONE_EXTENSION_MAX_LENGTH,
-//     '#title' => t('ext'),
-     '#required' => FALSE,
-     '#default_value' => isset($element['#value']['extension']) ? $element['#value']['extension'] : NULL,
-     '#prefix' => '<div class="cck-phone-extension">'. t('ext') .'</div>',
-    );
-  }
-
-  $element['country_codes'] = array(
-    '#type' => 'select',
-//    '#title' => 'Country code',
-    '#default_value' => ($element['#value']['number'] != '' && isset($element['#value']['country_codes'])) ? $element['#value']['country_codes'] : (isset($field['default_country']) ? $field['default_country'] : NULL),
-  );
-  if ($field['all_country_codes']) {
-    $element['country_codes']['#options'] = _cck_phone_cc_options();
-  }
-  else {
-    $element['country_codes']['#options'] = _cck_phone_cc_options(FALSE, $field['country_selection']);
-  }
-
-  return $element;
-}
-
-/**
- * Strip number of space, hash, dash, bracket, etc leaving digit only.
- *
- * @param string $number
- * @return string Returns digit only phone number.
- */
-function cck_phone_clean_number($number) {
-  // Remove none numeric characters
-  $number = preg_replace('/[^0-9]/', '', $number);
-
-  return $number;
-}
-
-/**
- * Generic validation for Phone Number.
- *
- * @param string $countrycode
- * @param string $number
- * @return boolean Returns boolean FALSE if the phone number is not valid.
- */
-function cck_phone_validate_number($countrycode, $number, $ext = '') {
-  // We don't want to worry about separators
-  $number = cck_phone_clean_number($number);
-  if ($number !== '' && drupal_strlen($number) > CCK_PHONE_PHONE_MAX_LENGTH) {
-    return FALSE;
-  }
-
-  $ext = cck_phone_clean_number($ext);
-  if ($ext !== '' && drupal_strlen($ext) > CCK_PHONE_EXTENSION_MAX_LENGTH) {
-    return FALSE;
-  }
-
-  return TRUE;
-}
-
-
-/* ------ Token ------ */
-
-/**
- * Implementation of hook_token_list().
- */
-function cck_phone_token_list($type = 'all') {
-  if ($type == 'field' || $type == 'all') {
-    $tokens = array();
-
-    $tokens['cck_phone']['number'] = t('Phone number');
-    $tokens['cck_phone']['country_codes'] = t('Country code');
-    $tokens['cck_phone']['extension'] = t('Extension');
-
-    return $tokens;
-  }
-}
-
-/**
- * Implementation of hook_token_values().
- */
-function cck_phone_token_values($type, $object = NULL, $options = array()) {
-  if ($type == 'field') {
-    $item = $object[0];
-
-    $tokens['number'] = $item['number'];
-    $tokens['country_codes'] = $item['country_codes'];
-    $tokens['cck_phone']['extension'] = $item['extension'];
-
-    return $tokens;
-  }
-}
+}
\ No newline at end of file
Index: includes/phone.ca.inc
===================================================================
RCS file: /cvs/drupal/contributions/modules/cck_phone/includes/phone.ca.inc,v
retrieving revision 1.1
diff -u -r1.1 phone.ca.inc
--- includes/phone.ca.inc	8 Jul 2010 11:22:37 -0000	1.1
+++ includes/phone.ca.inc	24 Jul 2010 06:02:20 -0000
@@ -7,23 +7,25 @@
  */
 
 /**
- * Verifies that $number is a valid ten-digit North American phone number.
+ * Validate country level phone number.
  *
  * @param $number
- *   Digits only value.
- * @param $ext
- *   Digits only value.
+ *   Digits only phone number value.
+ * @param $subaddress
+ *   Subaddress value for telephone/fax's extension number, ISDN subaddress, 
+ *   fax's T33 subaddress, modem's parameters/recommended parameters. 
+ *   Reference: http://tools.ietf.org/html/rfc2806.
  * @param $error
- *   The error message to shown to user.
- *   Available parameters to use in the error message are
- *   - "%countrycode": the alpha-2 CC
- *   - "%phone_input": the original number input by user (could be invalid)
- *   - "%max_length": allowed maximum length of the phone number
+ *   Error message that will be displayed to user.
+ * @param $phone_type
+ *   Nature of the phone (Voice, Home, Msg, Work, Pref, Fax, Cell, Video, 
+ *   Pager, BBS, Modem, Car, ISDN, PCS)
  * @return boolean
- *   TRUE if it is a valid phone number for that country, FALSE otherwise.
+ *   TRUE if it is a valid phone number for this country, FALSE otherwise.
  */
-function ca_validate_number($number, $ext = '', &$error) {
-  return us_validate_number($number, $ext = '', &$error);
+function ca_validate_number($number = '', $subaddress = '', &$error, $phone_type = 'Voice') {
+  module_load_include('inc', 'cck_phone', 'includes/phone.us');
+  return us_validate_number($number, $subaddress, $error, $phone_type);
 }
 
 /**
@@ -33,43 +35,17 @@
  *   A single phone number item.
  */
 function ca_sanitize_number(&$number) {
+  module_load_include('inc', 'cck_phone', 'includes/phone.us');
   us_sanitize_number($number);
 }
 
 /**
  * Default formatter for international phone number.
  *
- * @param $element
- *   $element['#item']['country_codes']: alpha-2 country code
- *   $element['#item']['number']: phone number
- * @param $error
- *   The error message to shown to user.
- *   Available parameters to use in the error message are
- *   - "%countrycode": the alpha-2 CC
- *   - "%phone_input": the original number input by user (could be invalid)
- *   - "%max_length": allowed maximum length of the phone number
- * @return boolean
- *   TRUE if it is a valid phone number for that country, FALSE otherwise.
- */
-function ca_formatter_default($element) {
-  return us_formatter_default($element);
-}
-
-/**
- * Local formatter for local phone number.
- *
- * @param $element
- *   $element['#item']['country_codes']: alpha-2 country code
- *   $element['#item']['number']: phone number
- * @param $error
- *   The error message to shown to user.
- *   Available parameters to use in the error message are
- *   - "%countrycode": the alpha-2 CC
- *   - "%phone_input": the original number input by user (could be invalid)
- *   - "%max_length": allowed maximum length of the phone number
- * @return boolean
- *   TRUE if it is a valid phone number for that country, FALSE otherwise.
+ * @param $number
+ *   Phone number.
  */
-function ca_formatter_local($element) {
-  return us_formatter_local($element);
+function ca_formatter_default($number) {
+  module_load_include('inc', 'cck_phone', 'includes/phone.us');
+  return us_formatter_default($number);
 }
\ No newline at end of file
Index: includes/phone.gb.inc
===================================================================
RCS file: /cvs/drupal/contributions/modules/cck_phone/includes/phone.gb.inc,v
retrieving revision 1.1
diff -u -r1.1 phone.gb.inc
--- includes/phone.gb.inc	8 Jul 2010 11:22:37 -0000	1.1
+++ includes/phone.gb.inc	24 Jul 2010 07:12:33 -0000
@@ -25,29 +25,27 @@
  * Validate country level phone number.
  *
  * @param $number
- *   Digits only value.
- * @param $ext
- *   Digits only value.
+ *   Digits only phone number value.
+ * @param $subaddress
+ *   Subaddress value for telephone/fax's extension number, ISDN subaddress, 
+ *   fax's T33 subaddress, modem's parameters/recommended parameters. 
+ *   Reference: http://tools.ietf.org/html/rfc2806.
  * @param $error
- *   The error message to shown to user.
- *   Available parameters to use in the error message are
- *   - "%countrycode": the alpha-2 CC
- *   - "%phone_input": the original number input by user (could be invalid)
- *   - "%max_length": allowed maximum length of the phone number
+ *   Error message that will be displayed to user.
+ * @param $phone_type
+ *   Nature of the phone (Voice, Home, Msg, Work, Pref, Fax, Cell, Video, 
+ *   Pager, BBS, Modem, Car, ISDN, PCS)
  * @return boolean
- *   TRUE if it is a valid phone number for that country, FALSE otherwise.
+ *   TRUE if it is a valid phone number for this country, FALSE otherwise.
  */
-function gb_validate_number($number, $ext = '', &$error) {
-  // We don't want to worry about separators
-  $number = cck_phone_clean_number($number);
-
-  if (preg_match(_uk_phone_rules(), $number)) {
-    return TRUE;
+function gb_validate_number($number = '', $subaddress = '', &$error, $phone_type = 'Voice') {
+  if (!empty($number)) {
+    if (preg_match(_uk_phone_rules(), $number)) {
+      return TRUE;
+    }
+    $error = t('"%phone_input" is not a valid United Kingdom phone number, it should be 10 digits number like "29 9999 9999", with optional leading "0"', array('%phone_input' => $number));
+    return FALSE;
   }
-
-  // t() is no needed
-  $error = '"%phone_input" is not a valid United Kingdom phone number, it should be 10 digits number like "99 9999 9999", with optional leading "0"';
-  return FALSE;
 }
 
 /**
@@ -64,58 +62,16 @@
 /**
  * Default formatter for international phone number.
  *
- * @param $element
- *   $element['#item']['country_codes']: alpha-2 country code
- *   $element['#item']['number']: phone number
- * @param $error
- *   The error message to shown to user.
- *   Available parameters to use in the error message are
- *   - "%countrycode": the alpha-2 CC
- *   - "%phone_input": the original number input by user (could be invalid)
- *   - "%max_length": allowed maximum length of the phone number
- * @return boolean
- *   TRUE if it is a valid phone number for that country, FALSE otherwise.
- */
-function gb_formatter_default($element) {
-  $item = $element['#item'];
-
-  // Display a global phone number with country code.
-  $cc = cck_phone_countrycodes($item['country_codes']);
-
-  $result = preg_match(_uk_phone_rules, $item['number'], $matches);
-
-  if ($result) {
-    // output as +44 AA BBBB CCCC, +44 AAA BBB CCCC or +44 AAAA BBB CCC
-    $phone =  $cc['code'] . $matches[1] .'-'. $matches[2] .' '. $matches[3];
-  }
-
-  return $phone;
-}
-
-
-/**
- * Local formatter for local phone number.
- *
- * @param $element
- *   $element['#item']['country_codes']: alpha-2 country code
- *   $element['#item']['number']: phone number
- * @param $error
- *   The error message to shown to user.
- *   Available parameters to use in the error message are
- *   - "%countrycode": the alpha-2 CC
- *   - "%phone_input": the original number input by user (could be invalid)
- *   - "%max_length": allowed maximum length of the phone number
- * @return boolean
- *   TRUE if it is a valid phone number for that country, FALSE otherwise.
+ * @param $number
+ *   Phone number.
  */
-function gb_formatter_local($element) {
-  // Display a local phone number without country code.
-  $result = preg_match(_uk_phone_rules, $item['number'], $matches);
+function gb_formatter_default($number) {
+  $result = preg_match(_uk_phone_rules(), $number, $matches);
 
   if ($result) {
-    // output as 0AA BBBB CCCC,  0AAA BBB CCCC or 0AAAA BBB CCC
-    $phone =  '0'. $matches[1] .'-'. $matches[2] .' '. $matches[3];
+    // output as AA BBBB CCCC, AAA BBB CCCC or AAAA BBB CCC
+    $phone =  $matches[1] .'-'. $matches[2] .' '. $matches[3];
   }
 
   return $phone;
-}
+}
\ No newline at end of file
Index: includes/phone.my.inc
===================================================================
RCS file: /cvs/drupal/contributions/modules/cck_phone/includes/phone.my.inc,v
retrieving revision 1.1
diff -u -r1.1 phone.my.inc
--- includes/phone.my.inc	8 Jul 2010 11:22:37 -0000	1.1
+++ includes/phone.my.inc	24 Jul 2010 07:08:18 -0000
@@ -45,78 +45,64 @@
 }
 
 /**
- * Verifies that $number is a valid Malaysia phone number.
+ * Validate country level phone number.
  *
  * @param $number
- *   Digits only value.
- * @param $ext
- *   Digits only value.
+ *   Digits only phone number value.
+ * @param $subaddress
+ *   Subaddress value for telephone/fax's extension number, ISDN subaddress, 
+ *   fax's T33 subaddress, modem's parameters/recommended parameters. 
+ *   Reference: http://tools.ietf.org/html/rfc2806.
  * @param $error
- *   The error message to shown to user.
- *   Available parameters to use in the error message are
- *   - "%countrycode": the alpha-2 CC
- *   - "%phone_input": the original number input by user (could be invalid)
- *   - "%max_length": allowed maximum length of the phone number
+ *   Error message that will be displayed to user.
+ * @param $phone_type
+ *   Nature of the phone (Voice, Home, Msg, Work, Pref, Fax, Cell, Video, 
+ *   Pager, BBS, Modem, Car, ISDN, PCS)
  * @return boolean
- *   TRUE if it is a valid phone number for that country, FALSE otherwise.
+ *   TRUE if it is a valid phone number for this country, FALSE otherwise.
  */
-function my_validate_number($number, $ext = '', &$error) {
-  // We don't want to worry about separators
-  $number = cck_phone_clean_number($number);
-
-  foreach (_my_phone_rules() as $rule) {
-    // define regular expression
-    $regex = '/^
-      ([0]*)                             # an optional 0
-      ('. $rule[0] .')                   # area code
-      \d{'. $rule[1] .'}                 # local number within length $rule[1] & $rule[2]
-      $/x';
-
-    $result = preg_match($regex, $number, $matches);
-
-    if ($result) {
-      return TRUE;
+function my_validate_number($number = '', $subaddress = '', &$error, $phone_type = 'Voice') {
+  if (!empty($number)) {
+    foreach (_my_phone_rules() as $rule) {
+      // define regular expression
+      $regex = '/^
+        ([0]*)                             # an optional 0
+        ('. $rule[0] .')                   # area code
+        \d{'. $rule[1] .'}                 # local number within length $rule[1] & $rule[2]
+        $/x';
+
+      $result = preg_match($regex, $number, $matches);
+
+      if ($result) {
+        return TRUE;
+      }
     }
+    $error = t('"%phone_input" is not a valid Malaysia phone number, it should be 9-10 digits number like "03-2222 2222", "0" is optional and will be removed.', array('%phone_input' => $number));
+    return FALSE;
   }
-
-  // t() is no needed
-  $error = '"%phone_input" is not a valid Malaysia phone number, it should be 9-10 digits number like "03-2222 2222", "0" is optional and will be removed.';
-  return FALSE;
 }
 
 /**
- * Cleanup user-entered values for a phone number field for saving to DB.
+ * Cleanup user-entered values for a phone number field for storing to DB.
  *
  * @param $number
  *   A single phone number item.
+ * @param $href
+ *   Valid number (numeric and + charaters only) placed at 
+ *   href="tel:<phone number>;ext=123" of anchor tag.
  */
 function my_sanitize_number(&$number) {
   // Remove trunk prefix '0'
-
   $number = preg_replace('/^([0]*)/', '', $number);
 }
 
 /**
  * Default formatter for international phone number.
  *
- * @param $element
- *   $element['#item']['country_codes']: alpha-2 country code
- *   $element['#item']['number']: phone number
- * @param $error
- *   The error message to shown to user.
- *   Available parameters to use in the error message are
- *   - "%countrycode": the alpha-2 CC
- *   - "%phone_input": the original number input by user (could be invalid)
- *   - "%max_length": allowed maximum length of the phone number
- * @return boolean
- *   TRUE if it is a valid phone number for that country, FALSE otherwise.
+ * @param $number
+ *   Phone number.
  */
-function my_formatter_default($element) {
-  $item = $element['#item'];
-
-  // Display a global phone number with country code.
-  $cc = cck_phone_countrycodes($item['country_codes']);
-
+function my_formatter_default($number) {
   // Format the phone number however you like, this is the default
   foreach (_my_phone_rules() as $rule) {
     // define regular expression
@@ -125,55 +111,14 @@
       (\d{3,4})
       (\d{4})
       $/x';
-
-    $result = preg_match($regex, $item['number'], $matches);
+    $result = preg_match($regex, $number, $matches);
 
     if ($result) {
-      // output as +60A-BBB CCCC or +60A-BBBB CCCC
-      $phone =  $cc['code'] . $matches[1] .'-'. $matches[2] .' '. $matches[3];
+      // output as A-BBB CCCC
+      $phone =  $matches[1] .'-'. $matches[2] .' '. $matches[3];
 
       continue;
     }
   }
-
-  return $phone . $ext;
-}
-
-/**
- * Local formatter for local phone number.
- *
- * @param $element
- *   $element['#item']['country_codes']: alpha-2 country code
- *   $element['#item']['number']: phone number
- * @param $error
- *   The error message to shown to user.
- *   Available parameters to use in the error message are
- *   - "%countrycode": the alpha-2 CC
- *   - "%phone_input": the original number input by user (could be invalid)
- *   - "%max_length": allowed maximum length of the phone number
- * @return boolean
- *   TRUE if it is a valid phone number for that country, FALSE otherwise.
- */
-function my_formatter_local($element) {
-  // Display a local phone number without country code.
-  $phone = $element['#item']['number'];
-
-  foreach (_my_phone_rules() as $rule) {
-    // define regular expression
-    $regex = '/^
-      ('. $rule[0] .')                   # area code
-      (\d{3,4})
-      (\d{4})
-      $/x';
-
-    $result = preg_match($regex, $phone, $matches);
-
-    if ($result) {
-      // output as 0A-BBB CCCC or 0A-BBBB CCCC
-      $phone = '0'. $matches[1] .'-'. $matches[2] .' '. $matches[3];
-      continue;
-    }
-  }
-
   return $phone;
-}
+}
\ No newline at end of file
Index: includes/phone.us.inc
===================================================================
RCS file: /cvs/drupal/contributions/modules/cck_phone/includes/phone.us.inc,v
retrieving revision 1.1
diff -u -r1.1 phone.us.inc
--- includes/phone.us.inc	8 Jul 2010 11:22:37 -0000	1.1
+++ includes/phone.us.inc	24 Jul 2010 06:51:51 -0000
@@ -7,48 +7,45 @@
  */
 
 /**
- * Verifies that $number is a valid ten-digit North American phone number.
+ * Validate country level phone number.
  *
  * @param $number
- *   Digits only value.
- * @param $ext
- *   Digits only value.
+ *   Digits only phone number value.
+ * @param $subaddress
+ *   Subaddress value for telephone/fax's extension number, ISDN subaddress, 
+ *   fax's T33 subaddress, modem's parameters/recommended parameters. 
+ *   Reference: http://tools.ietf.org/html/rfc2806.
  * @param $error
- *   The error message to shown to user.
- *   Available parameters to use in the error message are
- *   - "%countrycode": the alpha-2 CC
- *   - "%phone_input": the original number input by user (could be invalid)
- *   - "%max_length": allowed maximum length of the phone number
+ *   Error message that will be displayed to user.
+ * @param $phone_type
+ *   Nature of the phone (Voice, Home, Msg, Work, Pref, Fax, Cell, Video, 
+ *   Pager, BBS, Modem, Car, ISDN, PCS)
  * @return boolean
- *   TRUE if it is a valid phone number for that country, FALSE otherwise.
+ *   TRUE if it is a valid phone number for this country, FALSE otherwise.
  */
-function us_validate_number($number, $ext = '', &$error) {
-  // Don't need to check for extension because it has been checked by generic validation as all digits, unless has special format/requirements
-  // We don't want to worry about separators
-  $number = cck_phone_clean_number($number);
-
-  // define regular expression
-  $regex = '/^
-    ([1]*)        # an optional 1
-    [2-9][0-8]\d  # area code (Allowed range of [2-9] for the first digit, [0-8] for the second, and [0-9] for the third digit)
-    [2-9]\d{2}    # 3-digit prefix (cannot start with 0 or 1)
-    \d{4}         # 4-digit line number
-    $/x';
-
-  $result = preg_match($regex, $number, $matches);
-
-  if ($result && $matches[1] == '') {
-    return TRUE;
-  }
-  elseif ($result && $matches[1] == '1') {
-    // t() is no needed
-    $error = 'Please enter a 10 digits North American phone number like "999 999 9999", without the country code "1" or "+1"';
-    return FALSE;
-  }
-  else {
-    // t() is no needed
-    $error = '"%phone_input" is not a valid North American phone number, it should be 10 digits number like "999 999 9999"';
-    return FALSE;
+function us_validate_number($number = '', $subaddress = '', &$error, $phone_type = 'Voice') {
+  if (!empty($number)) {
+    // Define regular expression
+    $regex = '/^
+      ([1]*)        # an optional 1
+      [2-9][0-8]\d  # area code (Allowed range of [2-9] for the first digit, [0-8] for the second, and [0-9] for the third digit)
+      [2-9]\d{2}    # 3-digit prefix (cannot start with 0 or 1)
+      \d{4}         # 4-digit line number
+      $/x';
+
+    $result = preg_match($regex, $number, $matches);
+
+    if ($result && $matches[1] == '') {
+      return TRUE;
+    }
+    elseif ($result && $matches[1] == '1') {
+      $error = t('Please enter a 10 digits North American phone number like "999 999 9999", without the country code "1" or "+1"');
+      return FALSE;
+    }
+    else {
+      $error = t('%phone_input is not a valid North American phone number, it should be 10 digits number like "989 999 9999"', array('%phone_input' => $number));
+      return FALSE;
+    }
   }
 }
 
@@ -68,25 +65,10 @@
 /**
  * Default formatter for international phone number.
  *
- * @param $element
- *   $element['#item']['country_codes']: alpha-2 country code
- *   $element['#item']['number']: phone number
- * @param $error
- *   The error message to shown to user.
- *   Available parameters to use in the error message are
- *   - "%countrycode": the alpha-2 CC
- *   - "%phone_input": the original number input by user (could be invalid)
- *   - "%max_length": allowed maximum length of the phone number
- * @return boolean
- *   TRUE if it is a valid phone number for that country, FALSE otherwise.
+ * @param $number
+ *   Phone number.
  */
-function us_formatter_default($element) {
-  $item = $element['#item'];
-  $phone = '';
-
-  // Display a global phone number with country code.
-  $cc = cck_phone_countrycodes($item['country_codes']);
-
+function us_formatter_default($number) {
   // Format the phone number however you like, this is the default
   // define regular expression
   $regex = '/^
@@ -95,43 +77,7 @@
     (\d{4})         # 4-digit line number
     /x';
 
-  $result = preg_match($regex, $item['number'], $matches);
-
-  if ($result) {
-    // output as +1 (AAA) BBB CCCC
-    $phone =  $cc['code'] .' ('. $matches[1] .') '. $matches[2] .' '. $matches[3];
-  }
-
-  return $phone . $ext;
-}
-
-/**
- * Local formatter for local phone number.
- *
- * @param $element
- *   $element['#item']['country_codes']: alpha-2 country code
- *   $element['#item']['number']: phone number
- * @param $error
- *   The error message to shown to user.
- *   Available parameters to use in the error message are
- *   - "%countrycode": the alpha-2 CC
- *   - "%phone_input": the original number input by user (could be invalid)
- *   - "%max_length": allowed maximum length of the phone number
- * @return boolean
- *   TRUE if it is a valid phone number for that country, FALSE otherwise.
- */
-function us_formatter_local($element) {
-  $item = $element['#item'];
-  $phone = '';
-
-  // Display a local phone number without country code.
-  $regex = '/^
-    ([2-9][0-8]\d)  # area code (Allowed range of [2-9] for the first digit, [0-8] for the second, and [0-9] for the third digit)
-    ([2-9]\d{2})    # 3-digit prefix (cannot start with 0 or 1)
-    (\d{4})         # 4-digit line number
-    /x';
-
-  $result = preg_match($regex, $item['number'], $matches);
+  $result = preg_match($regex, $number, $matches);
 
   if ($result) {
     // output as (AAA) BBB CCCC
@@ -139,4 +85,4 @@
   }
 
   return $phone;
-}
+}
\ No newline at end of file
--- cck_phone_countrycodes.inc.tortoise.removed
+++ cck_phone_countrycodes.inc.tortoise.removed
@@ -0,0 +1,266 @@
+<?php
+// $Id: cck_phone_countrycodes.inc,v 1.1 2010/07/08 11:20:27 ckng Exp $
+
+/**
+ * @file
+ * Defines country codes for Phone Number.
+ * Provide country name and international codes per country codes.
+ */
+
+/**
+ * Get all the country codes for supported countries.
+ *
+ * @param $cc
+ *   Optional, two character country code. If this is ommitted all country codes
+ *   will be returned.
+ * @return
+ *   If no country code is provided an array keyed by country code, values are
+ *   arrays with a 'country' and 'code' values. If an invalid $cc is provided,
+ *   FALSE will be returned. If the country code is valid the country code for
+ *   that country will be returned.
+ */
+function cck_phone_countrycodes($cc = NULL) {
+  // Alpha-2 codes from ISO 3166-1 http://en.wikipedia.org/wiki/ISO_3166-1
+  // Country codes from http://en.wikipedia.org/wiki/Country_calling_code
+  static $country_code = array(
+    'af' => array('country' => 'Afghanistan', 'code' => '+93'),
+    'al' => array('country' => 'Albania', 'code' => '+355'),
+    'dz' => array('country' => 'Algeria', 'code' => '+213'),
+    'as' => array('country' => 'American Samoa', 'code' => '+1'),
+    'ad' => array('country' => 'Andorra', 'code' => '+376'),
+    'ao' => array('country' => 'Angola', 'code' => '+244'),
+    'ai' => array('country' => 'Anguilla', 'code' => '+1'),
+    'ag' => array('country' => 'Antigua and Barbuda', 'code' => '+1'),
+    'ar' => array('country' => 'Argentina', 'code' => '+54'),
+    'am' => array('country' => 'Armenia', 'code' => '+374'),
+    'aw' => array('country' => 'Aruba', 'code' => '+297'),
+    'au' => array('country' => 'Australia', 'code' => '+61'),
+    'at' => array('country' => 'Austria', 'code' => '+43'),
+    'az' => array('country' => 'Azerbaijan', 'code' => '+994'),
+    'bs' => array('country' => 'Bahamas, The', 'code' => '+1'),
+    'bh' => array('country' => 'Bahrain', 'code' => '+973'),
+    'bd' => array('country' => 'Bangladesh', 'code' => '+880'),
+    'bb' => array('country' => 'Barbados', 'code' => '+1'),
+    'by' => array('country' => 'Belarus', 'code' => '+375'),
+    'be' => array('country' => 'Belgium', 'code' => '+32'),
+    'bz' => array('country' => 'Belize', 'code' => '+501'),
+    'bj' => array('country' => 'Benin', 'code' => '+229'),
+    'bm' => array('country' => 'Bermuda', 'code' => '+1'),
+    'bt' => array('country' => 'Bhutan', 'code' => '+975'),
+    'bo' => array('country' => 'Bolivia', 'code' => '+591'),
+    'ba' => array('country' => 'Bosnia and Herzegovina', 'code' => '+387'),
+    'bw' => array('country' => 'Botswana', 'code' => '+267'),
+    'br' => array('country' => 'Brazil', 'code' => '+55'),
+    'io' => array('country' => 'British Indian Ocean Territory', 'code' => '+246'),
+    'vg' => array('country' => 'British Virgin Islands', 'code' => '+1'),
+    'bn' => array('country' => 'Brunei', 'code' => '+673'),
+    'bg' => array('country' => 'Bulgaria', 'code' => '+359'),
+    'bf' => array('country' => 'Burkina Faso', 'code' => '+226'),
+    'bi' => array('country' => 'Burundi', 'code' => '+257'),
+    'kh' => array('country' => 'Cambodia', 'code' => '+855'),
+    'cm' => array('country' => 'Cameroon', 'code' => '+237'),
+    'ca' => array('country' => 'Canada', 'code' => '+1'),
+    'cv' => array('country' => 'Cape Verde', 'code' => '+238'),
+    'ky' => array('country' => 'Cayman Islands', 'code' => '+1'),
+    'cf' => array('country' => 'Central African Republic', 'code' => '+236'),
+    'td' => array('country' => 'Chad', 'code' => '+235'),
+    'cl' => array('country' => 'Chile', 'code' => '+56'),
+    'cn' => array('country' => 'China', 'code' => '+86'),
+    'cx' => array('country' => 'Christmas Island', 'code' => '+61'),
+    'cc' => array('country' => 'Cocos-Keeling Islands', 'code' => '+61'),
+    'co' => array('country' => 'Colombia', 'code' => '+57'),
+    'km' => array('country' => 'Comoros', 'code' => '+269'),
+    'cg' => array('country' => 'Congo, Republic of the', 'code' => '+242'),
+    'cd' => array('country' => 'Congo, Democratic Republic of', 'code' => '+243'),
+    'ck' => array('country' => 'Cook Islands', 'code' => '+682'),
+    'cr' => array('country' => 'Costa Rica', 'code' => '+506'),
+    'hr' => array('country' => 'Croatia', 'code' => '+385'),
+    'cu' => array('country' => 'Cuba', 'code' => '+53'),
+    'cy' => array('country' => 'Cyprus', 'code' => '+357'),
+    'cz' => array('country' => 'Czech Republic', 'code' => '+420'),
+    'dk' => array('country' => 'Denmark', 'code' => '+45'),
+    'dj' => array('country' => 'Djibouti', 'code' => '+253'),
+    'dm' => array('country' => 'Dominica', 'code' => '+1'),
+    'do' => array('country' => 'Dominican Republic', 'code' => '+1'),
+    'tp' => array('country' => 'East Timor', 'code' => '+670'),
+    'ec' => array('country' => 'Ecuador', 'code' => '+593'),
+    'eg' => array('country' => 'Egypt', 'code' => '+20'),
+    'sv' => array('country' => 'El Salvador', 'code' => '+503'),
+    'gq' => array('country' => 'Equatorial Guinea', 'code' => '+240'),
+    'er' => array('country' => 'Eritrea', 'code' => '+291'),
+    'ee' => array('country' => 'Estonia', 'code' => '+372'),
+    'et' => array('country' => 'Ethiopia', 'code' => '+251'),
+    'fk' => array('country' => 'Falkland Islands', 'code' => '+500'),
+    'fo' => array('country' => 'Faroe Islands', 'code' => '+298'),
+    'fj' => array('country' => 'Fiji', 'code' => '+679'),
+    'fi' => array('country' => 'Finland', 'code' => '+358'),
+    'fr' => array('country' => 'France', 'code' => '+33'),
+    'gf' => array('country' => 'French Guiana', 'code' => '+594'),
+    'pf' => array('country' => 'French Polynesia', 'code' => '+689'),
+    'ga' => array('country' => 'Gabon', 'code' => '+241'),
+    'gm' => array('country' => 'Gambia, The', 'code' => '+220'),
+    'ge' => array('country' => 'Georgia', 'code' => '+995'),
+    'de' => array('country' => 'Germany', 'code' => '+49'),
+    'gh' => array('country' => 'Ghana', 'code' => '+233'),
+    'gi' => array('country' => 'Gibraltar', 'code' => '+350'),
+    'gr' => array('country' => 'Greece', 'code' => '+30'),
+    'gl' => array('country' => 'Greenland', 'code' => '+299'),
+    'gd' => array('country' => 'Grenada', 'code' => '+1'),
+    'gp' => array('country' => 'Guadeloupe', 'code' => '+590'),
+    'gu' => array('country' => 'Guam', 'code' => '+1'),
+    'gt' => array('country' => 'Guatemala', 'code' => '+502'),
+    'gn' => array('country' => 'Guinea', 'code' => '+224'),
+    'gw' => array('country' => 'Guinea-Bissau', 'code' => '+245'),
+    'gy' => array('country' => 'Guyana', 'code' => '+592'),
+    'ht' => array('country' => 'Haiti', 'code' => '+509'),
+    'hn' => array('country' => 'Honduras', 'code' => '+504'),
+    'hk' => array('country' => 'Hong Kong', 'code' => '+852'),
+    'hu' => array('country' => 'Hungary', 'code' => '+36'),
+    'is' => array('country' => 'Iceland', 'code' => '+354'),
+    'in' => array('country' => 'India', 'code' => '+91'),
+    'id' => array('country' => 'Indonesia', 'code' => '+62'),
+    'ir' => array('country' => 'Iran', 'code' => '+98'),
+    'iq' => array('country' => 'Iraq', 'code' => '+964'),
+    'ie' => array('country' => 'Ireland', 'code' => '+353'),
+    'il' => array('country' => 'Israel', 'code' => '+972'),
+    'it' => array('country' => 'Italy', 'code' => '+39'),
+    'ci' => array('country' => 'Ivory Coast', 'code' => '+225'),
+    'jm' => array('country' => 'Jamaica', 'code' => '+1'),
+    'jp' => array('country' => 'Japan', 'code' => '+81'),
+    'jo' => array('country' => 'Jordan', 'code' => '+962'),
+    'kz' => array('country' => 'Kazakhstan', 'code' => '+7'),
+    'ke' => array('country' => 'Kenya', 'code' => '+254'),
+    'ki' => array('country' => 'Kiribati', 'code' => '+686'),
+    'kw' => array('country' => 'Kuwait', 'code' => '+965'),
+    'kg' => array('country' => 'Kyrgyzstan', 'code' => '+996'),
+    'la' => array('country' => 'Laos', 'code' => '+856'),
+    'lv' => array('country' => 'Latvia', 'code' => '+371'),
+    'lb' => array('country' => 'Lebanon', 'code' => '+961'),
+    'ls' => array('country' => 'Lesotho', 'code' => '+266'),
+    'lr' => array('country' => 'Liberia', 'code' => '+231'),
+    'ly' => array('country' => 'Libya', 'code' => '+218'),
+    'li' => array('country' => 'Liechtenstein', 'code' => '+423'),
+    'lt' => array('country' => 'Lithuania', 'code' => '+370'),
+    'lu' => array('country' => 'Luxembourg', 'code' => '+352'),
+    'mo' => array('country' => 'Macau', 'code' => '+853'),
+    'mk' => array('country' => 'Macedonia', 'code' => '+389'),
+    'mg' => array('country' => 'Madagascar', 'code' => '+261'),
+    'mw' => array('country' => 'Malawi', 'code' => '+265'),
+    'my' => array('country' => 'Malaysia', 'code' => '+60'),
+    'mv' => array('country' => 'Maldives', 'code' => '+960'),
+    'ml' => array('country' => 'Mali', 'code' => '+223'),
+    'mt' => array('country' => 'Malta', 'code' => '+356'),
+    'mh' => array('country' => 'Marshall Islands', 'code' => '+692'),
+    'mq' => array('country' => 'Martinique', 'code' => '+596'),
+    'mr' => array('country' => 'Mauritania', 'code' => '+222'),
+    'mu' => array('country' => 'Mauritius', 'code' => '+230'),
+    'yt' => array('country' => 'Mayotte', 'code' => '+269'),
+    'mx' => array('country' => 'Mexico', 'code' => '+52'),
+    'fm' => array('country' => 'Micronesia, Federated States of', 'code' => '+691'),
+    'md' => array('country' => 'Moldova', 'code' => '+373'),
+    'mc' => array('country' => 'Monaco', 'code' => '+377'),
+    'mn' => array('country' => 'Mongolia', 'code' => '+976'),
+    'me' => array('country' => 'Montenegro', 'code' => '+382'),
+    'ms' => array('country' => 'Montserrat', 'code' => '+1'),
+    'ma' => array('country' => 'Morocco', 'code' => '+212'),
+    'mz' => array('country' => 'Mozambique', 'code' => '+258'),
+    'mm' => array('country' => 'Myanmar', 'code' => '+95'),
+    'na' => array('country' => 'Namibia', 'code' => '+264'),
+    'nr' => array('country' => 'Nauru', 'code' => '+674'),
+    'np' => array('country' => 'Nepal', 'code' => '+977'),
+    'nl' => array('country' => 'Netherlands', 'code' => '+31'),
+    'an' => array('country' => 'Netherlands Antilles', 'code' => '+599'),
+    'nc' => array('country' => 'New Caledonia', 'code' => '+687'),
+    'nz' => array('country' => 'New Zealand', 'code' => '+64'),
+    'ni' => array('country' => 'Nicaragua', 'code' => '+505'),
+    'ne' => array('country' => 'Niger', 'code' => '+227'),
+    'ng' => array('country' => 'Nigeria', 'code' => '+234'),
+    'nu' => array('country' => 'Niue', 'code' => '+683'),
+    'nf' => array('country' => 'Norfolk Island', 'code' => '+672'),
+    'kp' => array('country' => 'North Korea', 'code' => '+850'),
+    'mp' => array('country' => 'Northern Mariana Islands', 'code' => '+1'),
+    'no' => array('country' => 'Norway', 'code' => '+47'),
+    'om' => array('country' => 'Oman', 'code' => '+968'),
+    'pk' => array('country' => 'Pakistan', 'code' => '+92'),
+    'pw' => array('country' => 'Palau', 'code' => '+680'),
+    'ps' => array('country' => 'Palestine', 'code' => '+970'),
+    'pa' => array('country' => 'Panama', 'code' => '+507'),
+    'pg' => array('country' => 'Papua New Guinea', 'code' => '+675'),
+    'py' => array('country' => 'Paraguay', 'code' => '+595'),
+    'pe' => array('country' => 'Peru', 'code' => '+51'),
+    'ph' => array('country' => 'Philippines', 'code' => '+63'),
+    'pl' => array('country' => 'Poland', 'code' => '+48'),
+    'pt' => array('country' => 'Portugal', 'code' => '+351'),
+    'pr' => array('country' => 'Puerto Rico', 'code' => '+1'),
+    'qa' => array('country' => 'Qatar', 'code' => '+974'),
+    'ro' => array('country' => 'Romania', 'code' => '+40'),
+    'ru' => array('country' => 'Russia', 'code' => '+7'),
+    'rw' => array('country' => 'Rwanda', 'code' => '+250'),
+    'sh' => array('country' => 'Saint Helena', 'code' => '+290'),
+    'kn' => array('country' => 'Saint Kitts and Nevis', 'code' => '+1'),
+    'lc' => array('country' => 'Saint Lucia', 'code' => '+1'),
+    'pm' => array('country' => 'Saint Pierre and Miquelon', 'code' => '+508'),
+    'vc' => array('country' => 'Saint Vincent and the Grenadines', 'code' => '+1'),
+    'ws' => array('country' => 'Samoa', 'code' => '+1'),
+    'sm' => array('country' => 'San Marino', 'code' => '+378'),
+    'st' => array('country' => 'Sao Tome and Principe', 'code' => '+239'),
+    'sa' => array('country' => 'Saudi Arabia', 'code' => '+966'),
+    'sn' => array('country' => 'Senegal', 'code' => '+221'),
+    'rs' => array('country' => 'Serbia', 'code' => '+381'),
+    'sc' => array('country' => 'Seychelles', 'code' => '+248'),
+    'sl' => array('country' => 'Sierra Leone', 'code' => '+232'),
+    'sg' => array('country' => 'Singapore', 'code' => '+65'),
+    'sk' => array('country' => 'Slovakia', 'code' => '+421'),
+    'si' => array('country' => 'Slovenia', 'code' => '+386'),
+    'sb' => array('country' => 'Solomon Islands', 'code' => '+677'),
+    'so' => array('country' => 'Somalia', 'code' => '+252'),
+    'za' => array('country' => 'South Africa', 'code' => '+27'),
+    'kr' => array('country' => 'South Korea', 'code' => '+82'),
+    'es' => array('country' => 'Spain', 'code' => '+34'),
+    'lk' => array('country' => 'Sri Lanka', 'code' => '+94'),
+    'sd' => array('country' => 'Sudan', 'code' => '+249'),
+    'sr' => array('country' => 'Suriname', 'code' => '+597'),
+    'sz' => array('country' => 'Swaziland', 'code' => '+268'),
+    'se' => array('country' => 'Sweden', 'code' => '+46'),
+    'ch' => array('country' => 'Switzerland', 'code' => '+41'),
+    'sy' => array('country' => 'Syria', 'code' => '+963'),
+    'tw' => array('country' => 'Taiwan', 'code' => '+886'),
+    'tj' => array('country' => 'Tajikistan', 'code' => '+992'),
+    'tz' => array('country' => 'Tanzania', 'code' => '+255'),
+    'th' => array('country' => 'Thailand', 'code' => '+66'),
+    'tg' => array('country' => 'Togo', 'code' => '+228'),
+    'tk' => array('country' => 'Tokelau', 'code' => '+690'),
+    'to' => array('country' => 'Tonga', 'code' => '+676'),
+    'tt' => array('country' => 'Trinidad and Tobago', 'code' => '+1'),
+    'tn' => array('country' => 'Tunisia', 'code' => '+216'),
+    'tr' => array('country' => 'Turkey', 'code' => '+90'),
+    'tm' => array('country' => 'Turkmenistan', 'code' => '+993'),
+    'tc' => array('country' => 'Turks and Caicos Islands', 'code' => '+1'),
+    'tv' => array('country' => 'Tuvalu', 'code' => '+688'),
+    'ug' => array('country' => 'Uganda', 'code' => '+256'),
+    'ua' => array('country' => 'Ukraine', 'code' => '+380'),
+    'ae' => array('country' => 'United Arab Emirates', 'code' => '+971'),
+    'gb' => array('country' => 'United Kingdom', 'code' => '+44'),
+    'us' => array('country' => 'United States', 'code' => '+1'),
+    'uy' => array('country' => 'Uruguay', 'code' => '+598'),
+    'vi' => array('country' => 'US Virgin Islands', 'code' => '+1'),
+    'uz' => array('country' => 'Uzbekistan', 'code' => '+998'),
+    'vu' => array('country' => 'Vanuatu', 'code' => '+678'),
+    'va' => array('country' => 'Vatican City', 'code' => '+39'),
+    've' => array('country' => 'Venezuela', 'code' => '+58'),
+    'vn' => array('country' => 'Vietnam', 'code' => '+84'),
+    'wf' => array('country' => 'Wallis and Futuna', 'code' => '+681'),
+    'ye' => array('country' => 'Yemen', 'code' => '+967'),
+    'zm' => array('country' => 'Zambia', 'code' => '+260'),
+    'zw' => array('country' => 'Zimbabwe', 'code' => '+263'),
+  );
+
+  if (is_null($cc)) {
+    return $country_code;
+  }
+  elseif (isset($country_code[$cc])) {
+    return $country_code[$cc];
+  }
+
+  return FALSE;
+}

--- css/cck_phone.css
+++ css/cck_phone.css
@@ -0,0 +1,35 @@
+/* $Id: cck_phone.css,v 1.2 2010/07/12 09:54:52 ckng Exp $ */
+.cck-phone-field .form-item {
+  margin: 0;
+}
+
+.cck-phone-column {
+  float: left;
+}
+.cck-phone-field-phone {
+  width: 15em;
+}
+.cck-phone-field-cc {
+  width: 25em;
+}
+
+.cck-phone-field-ext {
+  width: 9em;
+}
+.cck-phone-extension {
+  float: left;
+  margin: 0 .5em;
+}
+.cck-phone-field-ext .form-item {
+  float: left;
+}
+
+.cck-phone-settings .form-checkboxes .form-item {
+  float: left;
+  width: 33%;
+}
+
+.cck-phone-settings .cck-phone-default-country {
+  background: #eee;
+  font-weight: bold;
+}

--- includes/cc.template.php
+++ includes/cc.template.php
@@ -0,0 +1,70 @@
+<?php
+// $Id: API.php,v 1.3 2010/07/12 09:54:52 ckng Exp $
+
+/**
+ * @file
+ * Phone Number custom country API
+ *
+ * 'CC' will be used throughout this document to indicate country code
+ * abbreviation. You should replace it with the correct country code
+ * in the following functions name. For full list of country code
+ * abbreviation, refer to the 2 alphabet list in the countries.txt.
+ */
+
+
+/**
+ * Validate country level phone number.
+ *
+ * @param $number
+ *   Digits only phone number value.
+ * @param $subaddress
+ *   Subaddress value for telephone/fax's extension number, ISDN subaddress, 
+ *   fax's T33 subaddress, modem's parameters/recommended parameters. 
+ *   Reference: http://tools.ietf.org/html/rfc2806.
+ * @param $error
+ *   Error message that will be displayed to user.
+ * @param $phone_type
+ *   Nature of the phone (Voice, Home, Msg, Work, Pref, Fax, Cell, Video, 
+ *   Pager, BBS, Modem, Car, ISDN, PCS)
+ * @return boolean
+ *   TRUE if it is a valid phone number for this country, FALSE otherwise.
+ */
+function CC_validate_number($number = '', $subaddress = '', &$error, $phone_type = 'Voice') {
+  // Assign $subaddress_error as FALSE if $subaddress is not valid
+  if (!empty($subaddress) && $subaddress_error) {
+    $error = t('%subaddress is not a valid extension number', array('%subaddress' => $subaddress));
+    return FALSE;
+  }
+  // Assign $number_error as FALSE if $number is not valid
+  if (!empty($number) && $number_error) {
+    $error = t('%phone_input is not a valid phone number, it should be 10 digits number like "999 999 9999"', array('%phone_input' => $number));
+    return FALSE;
+  }
+  return TRUE;
+}
+
+
+/**
+ * Cleanup user-entered values for a phone number field for storing to DB.
+ *
+ * @param $number
+ *   A single phone number item.
+ */
+function CC_sanitize_number(&$number) {
+  // your cleanup like removing trunk prefix
+  $number = preg_replace('/^([0]*)/', '', $number);
+}
+
+
+/**
+ * Default formatter for international phone number.
+ *
+ * @param $number
+ *   Phone number.
+ */
+function CC_formatter_default($number) {
+  // Format the phone number and its area code into human readable format
+  $phone = $number;
+
+  return $phone;
+}

--- includes/cck_phone_countrycodes.inc
+++ includes/cck_phone_countrycodes.inc
@@ -0,0 +1,266 @@
+<?php
+// $Id: cck_phone_countrycodes.inc,v 1.1 2010/07/08 11:20:27 ckng Exp $
+
+/**
+ * @file
+ * Defines country codes for Phone Number.
+ * Provide country name and international codes per country codes.
+ */
+
+/**
+ * Get all the country codes for supported countries.
+ *
+ * @param $cc
+ *   Optional, two character country code. If this is ommitted all country codes
+ *   will be returned.
+ * @return
+ *   If no country code is provided an array keyed by country code, values are
+ *   arrays with a 'country' and 'code' values. If an invalid $cc is provided,
+ *   FALSE will be returned. If the country code is valid the country code for
+ *   that country will be returned.
+ */
+function cck_phone_countrycodes($cc = NULL) {
+  // Alpha-2 codes from ISO 3166-1 http://en.wikipedia.org/wiki/ISO_3166-1
+  // Country codes from http://en.wikipedia.org/wiki/Country_calling_code
+  static $country_code = array(
+    'af' => array('country' => 'Afghanistan', 'code' => '+93'),
+    'al' => array('country' => 'Albania', 'code' => '+355'),
+    'dz' => array('country' => 'Algeria', 'code' => '+213'),
+    'as' => array('country' => 'American Samoa', 'code' => '+1'),
+    'ad' => array('country' => 'Andorra', 'code' => '+376'),
+    'ao' => array('country' => 'Angola', 'code' => '+244'),
+    'ai' => array('country' => 'Anguilla', 'code' => '+1'),
+    'ag' => array('country' => 'Antigua and Barbuda', 'code' => '+1'),
+    'ar' => array('country' => 'Argentina', 'code' => '+54'),
+    'am' => array('country' => 'Armenia', 'code' => '+374'),
+    'aw' => array('country' => 'Aruba', 'code' => '+297'),
+    'au' => array('country' => 'Australia', 'code' => '+61'),
+    'at' => array('country' => 'Austria', 'code' => '+43'),
+    'az' => array('country' => 'Azerbaijan', 'code' => '+994'),
+    'bs' => array('country' => 'Bahamas, The', 'code' => '+1'),
+    'bh' => array('country' => 'Bahrain', 'code' => '+973'),
+    'bd' => array('country' => 'Bangladesh', 'code' => '+880'),
+    'bb' => array('country' => 'Barbados', 'code' => '+1'),
+    'by' => array('country' => 'Belarus', 'code' => '+375'),
+    'be' => array('country' => 'Belgium', 'code' => '+32'),
+    'bz' => array('country' => 'Belize', 'code' => '+501'),
+    'bj' => array('country' => 'Benin', 'code' => '+229'),
+    'bm' => array('country' => 'Bermuda', 'code' => '+1'),
+    'bt' => array('country' => 'Bhutan', 'code' => '+975'),
+    'bo' => array('country' => 'Bolivia', 'code' => '+591'),
+    'ba' => array('country' => 'Bosnia and Herzegovina', 'code' => '+387'),
+    'bw' => array('country' => 'Botswana', 'code' => '+267'),
+    'br' => array('country' => 'Brazil', 'code' => '+55'),
+    'io' => array('country' => 'British Indian Ocean Territory', 'code' => '+246'),
+    'vg' => array('country' => 'British Virgin Islands', 'code' => '+1'),
+    'bn' => array('country' => 'Brunei', 'code' => '+673'),
+    'bg' => array('country' => 'Bulgaria', 'code' => '+359'),
+    'bf' => array('country' => 'Burkina Faso', 'code' => '+226'),
+    'bi' => array('country' => 'Burundi', 'code' => '+257'),
+    'kh' => array('country' => 'Cambodia', 'code' => '+855'),
+    'cm' => array('country' => 'Cameroon', 'code' => '+237'),
+    'ca' => array('country' => 'Canada', 'code' => '+1'),
+    'cv' => array('country' => 'Cape Verde', 'code' => '+238'),
+    'ky' => array('country' => 'Cayman Islands', 'code' => '+1'),
+    'cf' => array('country' => 'Central African Republic', 'code' => '+236'),
+    'td' => array('country' => 'Chad', 'code' => '+235'),
+    'cl' => array('country' => 'Chile', 'code' => '+56'),
+    'cn' => array('country' => 'China', 'code' => '+86'),
+    'cx' => array('country' => 'Christmas Island', 'code' => '+61'),
+    'cc' => array('country' => 'Cocos-Keeling Islands', 'code' => '+61'),
+    'co' => array('country' => 'Colombia', 'code' => '+57'),
+    'km' => array('country' => 'Comoros', 'code' => '+269'),
+    'cg' => array('country' => 'Congo, Republic of the', 'code' => '+242'),
+    'cd' => array('country' => 'Congo, Democratic Republic of', 'code' => '+243'),
+    'ck' => array('country' => 'Cook Islands', 'code' => '+682'),
+    'cr' => array('country' => 'Costa Rica', 'code' => '+506'),
+    'hr' => array('country' => 'Croatia', 'code' => '+385'),
+    'cu' => array('country' => 'Cuba', 'code' => '+53'),
+    'cy' => array('country' => 'Cyprus', 'code' => '+357'),
+    'cz' => array('country' => 'Czech Republic', 'code' => '+420'),
+    'dk' => array('country' => 'Denmark', 'code' => '+45'),
+    'dj' => array('country' => 'Djibouti', 'code' => '+253'),
+    'dm' => array('country' => 'Dominica', 'code' => '+1'),
+    'do' => array('country' => 'Dominican Republic', 'code' => '+1'),
+    'tp' => array('country' => 'East Timor', 'code' => '+670'),
+    'ec' => array('country' => 'Ecuador', 'code' => '+593'),
+    'eg' => array('country' => 'Egypt', 'code' => '+20'),
+    'sv' => array('country' => 'El Salvador', 'code' => '+503'),
+    'gq' => array('country' => 'Equatorial Guinea', 'code' => '+240'),
+    'er' => array('country' => 'Eritrea', 'code' => '+291'),
+    'ee' => array('country' => 'Estonia', 'code' => '+372'),
+    'et' => array('country' => 'Ethiopia', 'code' => '+251'),
+    'fk' => array('country' => 'Falkland Islands', 'code' => '+500'),
+    'fo' => array('country' => 'Faroe Islands', 'code' => '+298'),
+    'fj' => array('country' => 'Fiji', 'code' => '+679'),
+    'fi' => array('country' => 'Finland', 'code' => '+358'),
+    'fr' => array('country' => 'France', 'code' => '+33'),
+    'gf' => array('country' => 'French Guiana', 'code' => '+594'),
+    'pf' => array('country' => 'French Polynesia', 'code' => '+689'),
+    'ga' => array('country' => 'Gabon', 'code' => '+241'),
+    'gm' => array('country' => 'Gambia, The', 'code' => '+220'),
+    'ge' => array('country' => 'Georgia', 'code' => '+995'),
+    'de' => array('country' => 'Germany', 'code' => '+49'),
+    'gh' => array('country' => 'Ghana', 'code' => '+233'),
+    'gi' => array('country' => 'Gibraltar', 'code' => '+350'),
+    'gr' => array('country' => 'Greece', 'code' => '+30'),
+    'gl' => array('country' => 'Greenland', 'code' => '+299'),
+    'gd' => array('country' => 'Grenada', 'code' => '+1'),
+    'gp' => array('country' => 'Guadeloupe', 'code' => '+590'),
+    'gu' => array('country' => 'Guam', 'code' => '+1'),
+    'gt' => array('country' => 'Guatemala', 'code' => '+502'),
+    'gn' => array('country' => 'Guinea', 'code' => '+224'),
+    'gw' => array('country' => 'Guinea-Bissau', 'code' => '+245'),
+    'gy' => array('country' => 'Guyana', 'code' => '+592'),
+    'ht' => array('country' => 'Haiti', 'code' => '+509'),
+    'hn' => array('country' => 'Honduras', 'code' => '+504'),
+    'hk' => array('country' => 'Hong Kong', 'code' => '+852'),
+    'hu' => array('country' => 'Hungary', 'code' => '+36'),
+    'is' => array('country' => 'Iceland', 'code' => '+354'),
+    'in' => array('country' => 'India', 'code' => '+91'),
+    'id' => array('country' => 'Indonesia', 'code' => '+62'),
+    'ir' => array('country' => 'Iran', 'code' => '+98'),
+    'iq' => array('country' => 'Iraq', 'code' => '+964'),
+    'ie' => array('country' => 'Ireland', 'code' => '+353'),
+    'il' => array('country' => 'Israel', 'code' => '+972'),
+    'it' => array('country' => 'Italy', 'code' => '+39'),
+    'ci' => array('country' => 'Ivory Coast', 'code' => '+225'),
+    'jm' => array('country' => 'Jamaica', 'code' => '+1'),
+    'jp' => array('country' => 'Japan', 'code' => '+81'),
+    'jo' => array('country' => 'Jordan', 'code' => '+962'),
+    'kz' => array('country' => 'Kazakhstan', 'code' => '+7'),
+    'ke' => array('country' => 'Kenya', 'code' => '+254'),
+    'ki' => array('country' => 'Kiribati', 'code' => '+686'),
+    'kw' => array('country' => 'Kuwait', 'code' => '+965'),
+    'kg' => array('country' => 'Kyrgyzstan', 'code' => '+996'),
+    'la' => array('country' => 'Laos', 'code' => '+856'),
+    'lv' => array('country' => 'Latvia', 'code' => '+371'),
+    'lb' => array('country' => 'Lebanon', 'code' => '+961'),
+    'ls' => array('country' => 'Lesotho', 'code' => '+266'),
+    'lr' => array('country' => 'Liberia', 'code' => '+231'),
+    'ly' => array('country' => 'Libya', 'code' => '+218'),
+    'li' => array('country' => 'Liechtenstein', 'code' => '+423'),
+    'lt' => array('country' => 'Lithuania', 'code' => '+370'),
+    'lu' => array('country' => 'Luxembourg', 'code' => '+352'),
+    'mo' => array('country' => 'Macau', 'code' => '+853'),
+    'mk' => array('country' => 'Macedonia', 'code' => '+389'),
+    'mg' => array('country' => 'Madagascar', 'code' => '+261'),
+    'mw' => array('country' => 'Malawi', 'code' => '+265'),
+    'my' => array('country' => 'Malaysia', 'code' => '+60'),
+    'mv' => array('country' => 'Maldives', 'code' => '+960'),
+    'ml' => array('country' => 'Mali', 'code' => '+223'),
+    'mt' => array('country' => 'Malta', 'code' => '+356'),
+    'mh' => array('country' => 'Marshall Islands', 'code' => '+692'),
+    'mq' => array('country' => 'Martinique', 'code' => '+596'),
+    'mr' => array('country' => 'Mauritania', 'code' => '+222'),
+    'mu' => array('country' => 'Mauritius', 'code' => '+230'),
+    'yt' => array('country' => 'Mayotte', 'code' => '+269'),
+    'mx' => array('country' => 'Mexico', 'code' => '+52'),
+    'fm' => array('country' => 'Micronesia, Federated States of', 'code' => '+691'),
+    'md' => array('country' => 'Moldova', 'code' => '+373'),
+    'mc' => array('country' => 'Monaco', 'code' => '+377'),
+    'mn' => array('country' => 'Mongolia', 'code' => '+976'),
+    'me' => array('country' => 'Montenegro', 'code' => '+382'),
+    'ms' => array('country' => 'Montserrat', 'code' => '+1'),
+    'ma' => array('country' => 'Morocco', 'code' => '+212'),
+    'mz' => array('country' => 'Mozambique', 'code' => '+258'),
+    'mm' => array('country' => 'Myanmar', 'code' => '+95'),
+    'na' => array('country' => 'Namibia', 'code' => '+264'),
+    'nr' => array('country' => 'Nauru', 'code' => '+674'),
+    'np' => array('country' => 'Nepal', 'code' => '+977'),
+    'nl' => array('country' => 'Netherlands', 'code' => '+31'),
+    'an' => array('country' => 'Netherlands Antilles', 'code' => '+599'),
+    'nc' => array('country' => 'New Caledonia', 'code' => '+687'),
+    'nz' => array('country' => 'New Zealand', 'code' => '+64'),
+    'ni' => array('country' => 'Nicaragua', 'code' => '+505'),
+    'ne' => array('country' => 'Niger', 'code' => '+227'),
+    'ng' => array('country' => 'Nigeria', 'code' => '+234'),
+    'nu' => array('country' => 'Niue', 'code' => '+683'),
+    'nf' => array('country' => 'Norfolk Island', 'code' => '+672'),
+    'kp' => array('country' => 'North Korea', 'code' => '+850'),
+    'mp' => array('country' => 'Northern Mariana Islands', 'code' => '+1'),
+    'no' => array('country' => 'Norway', 'code' => '+47'),
+    'om' => array('country' => 'Oman', 'code' => '+968'),
+    'pk' => array('country' => 'Pakistan', 'code' => '+92'),
+    'pw' => array('country' => 'Palau', 'code' => '+680'),
+    'ps' => array('country' => 'Palestine', 'code' => '+970'),
+    'pa' => array('country' => 'Panama', 'code' => '+507'),
+    'pg' => array('country' => 'Papua New Guinea', 'code' => '+675'),
+    'py' => array('country' => 'Paraguay', 'code' => '+595'),
+    'pe' => array('country' => 'Peru', 'code' => '+51'),
+    'ph' => array('country' => 'Philippines', 'code' => '+63'),
+    'pl' => array('country' => 'Poland', 'code' => '+48'),
+    'pt' => array('country' => 'Portugal', 'code' => '+351'),
+    'pr' => array('country' => 'Puerto Rico', 'code' => '+1'),
+    'qa' => array('country' => 'Qatar', 'code' => '+974'),
+    'ro' => array('country' => 'Romania', 'code' => '+40'),
+    'ru' => array('country' => 'Russia', 'code' => '+7'),
+    'rw' => array('country' => 'Rwanda', 'code' => '+250'),
+    'sh' => array('country' => 'Saint Helena', 'code' => '+290'),
+    'kn' => array('country' => 'Saint Kitts and Nevis', 'code' => '+1'),
+    'lc' => array('country' => 'Saint Lucia', 'code' => '+1'),
+    'pm' => array('country' => 'Saint Pierre and Miquelon', 'code' => '+508'),
+    'vc' => array('country' => 'Saint Vincent and the Grenadines', 'code' => '+1'),
+    'ws' => array('country' => 'Samoa', 'code' => '+1'),
+    'sm' => array('country' => 'San Marino', 'code' => '+378'),
+    'st' => array('country' => 'Sao Tome and Principe', 'code' => '+239'),
+    'sa' => array('country' => 'Saudi Arabia', 'code' => '+966'),
+    'sn' => array('country' => 'Senegal', 'code' => '+221'),
+    'rs' => array('country' => 'Serbia', 'code' => '+381'),
+    'sc' => array('country' => 'Seychelles', 'code' => '+248'),
+    'sl' => array('country' => 'Sierra Leone', 'code' => '+232'),
+    'sg' => array('country' => 'Singapore', 'code' => '+65'),
+    'sk' => array('country' => 'Slovakia', 'code' => '+421'),
+    'si' => array('country' => 'Slovenia', 'code' => '+386'),
+    'sb' => array('country' => 'Solomon Islands', 'code' => '+677'),
+    'so' => array('country' => 'Somalia', 'code' => '+252'),
+    'za' => array('country' => 'South Africa', 'code' => '+27'),
+    'kr' => array('country' => 'South Korea', 'code' => '+82'),
+    'es' => array('country' => 'Spain', 'code' => '+34'),
+    'lk' => array('country' => 'Sri Lanka', 'code' => '+94'),
+    'sd' => array('country' => 'Sudan', 'code' => '+249'),
+    'sr' => array('country' => 'Suriname', 'code' => '+597'),
+    'sz' => array('country' => 'Swaziland', 'code' => '+268'),
+    'se' => array('country' => 'Sweden', 'code' => '+46'),
+    'ch' => array('country' => 'Switzerland', 'code' => '+41'),
+    'sy' => array('country' => 'Syria', 'code' => '+963'),
+    'tw' => array('country' => 'Taiwan', 'code' => '+886'),
+    'tj' => array('country' => 'Tajikistan', 'code' => '+992'),
+    'tz' => array('country' => 'Tanzania', 'code' => '+255'),
+    'th' => array('country' => 'Thailand', 'code' => '+66'),
+    'tg' => array('country' => 'Togo', 'code' => '+228'),
+    'tk' => array('country' => 'Tokelau', 'code' => '+690'),
+    'to' => array('country' => 'Tonga', 'code' => '+676'),
+    'tt' => array('country' => 'Trinidad and Tobago', 'code' => '+1'),
+    'tn' => array('country' => 'Tunisia', 'code' => '+216'),
+    'tr' => array('country' => 'Turkey', 'code' => '+90'),
+    'tm' => array('country' => 'Turkmenistan', 'code' => '+993'),
+    'tc' => array('country' => 'Turks and Caicos Islands', 'code' => '+1'),
+    'tv' => array('country' => 'Tuvalu', 'code' => '+688'),
+    'ug' => array('country' => 'Uganda', 'code' => '+256'),
+    'ua' => array('country' => 'Ukraine', 'code' => '+380'),
+    'ae' => array('country' => 'United Arab Emirates', 'code' => '+971'),
+    'gb' => array('country' => 'United Kingdom', 'code' => '+44'),
+    'us' => array('country' => 'United States', 'code' => '+1'),
+    'uy' => array('country' => 'Uruguay', 'code' => '+598'),
+    'vi' => array('country' => 'US Virgin Islands', 'code' => '+1'),
+    'uz' => array('country' => 'Uzbekistan', 'code' => '+998'),
+    'vu' => array('country' => 'Vanuatu', 'code' => '+678'),
+    'va' => array('country' => 'Vatican City', 'code' => '+39'),
+    've' => array('country' => 'Venezuela', 'code' => '+58'),
+    'vn' => array('country' => 'Vietnam', 'code' => '+84'),
+    'wf' => array('country' => 'Wallis and Futuna', 'code' => '+681'),
+    'ye' => array('country' => 'Yemen', 'code' => '+967'),
+    'zm' => array('country' => 'Zambia', 'code' => '+260'),
+    'zw' => array('country' => 'Zimbabwe', 'code' => '+263'),
+  );
+
+  if (is_null($cc)) {
+    return $country_code;
+  }
+  elseif (isset($country_code[$cc])) {
+    return $country_code[$cc];
+  }
+
+  return FALSE;
+}

--- includes/phone.ph.inc
+++ includes/phone.ph.inc
@@ -0,0 +1,108 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Phone number field for Philippine phone numbers.
+ */
+
+/**
+ * Validate country level phone number.
+ *
+ * @param $number
+ *   Digits only phone number value.
+ * @param $subaddress
+ *   Subaddress value for telephone/fax's extension number, ISDN subaddress, 
+ *   fax's T33 subaddress, modem's parameters/recommended parameters. 
+ *   Reference: http://tools.ietf.org/html/rfc2806.
+ * @param $error
+ *   Error message that will be displayed to user.
+ * @param $phone_type
+ *   Nature of the phone (Voice, Home, Msg, Work, Pref, Fax, Cell, Video, 
+ *   Pager, BBS, Modem, Car, ISDN, PCS)
+ * @return boolean
+ *   TRUE if it is a valid phone number for this country, FALSE otherwise.
+ */
+function ph_validate_number($number = '', $subaddress = '', &$error, $phone_type = 'Voice') {
+  ph_sanitize_number($number);
+  if (!empty($number) && (drupal_strlen($number) < 8 || drupal_strlen($number) > 12)) {
+    $error = t('%phone_input is not a valid phone number, it should have at least 8 digits number like "2 999 9999" and maximum of 12 digits like "12345 999 9999".', array('%phone_input' => $number));
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+ * Cleanup user-entered values for a phone number field for storing to DB.
+ *
+ * @param $number
+ *   A single phone number item.
+ */
+function ph_sanitize_number(&$number) {
+  $number = preg_replace('/^([0]*)/', '', $number);
+}
+
+/**
+ * Default formatter for international phone number.
+ *
+ * @param $number
+ *   Phone number.
+ */
+function ph_formatter_default($number) {
+  $regex = "/
+    # 5 digit area code.
+    (
+        (\d{5}) # capture 5 digit area code
+        (\d{3}) # capture first set of numbers in the local number
+        (\d{4}) # capture second set of numbers in the local number
+    |
+    # 4 digit area code.
+        (\d{4}) # capture 4 digit area code
+        (\d{3}) # capture first set of numbers in the local number
+        (\d{4}) # capture second set of numbers in the local number
+    |
+    # 3 digit area code.
+        (\d{3}) # capture 3 digit area code
+        (\d{3}) # capture first set of numbers in the local number
+        (\d{4}) # capture second set of numbers in the local number
+    |
+    # 2 digit area code.
+        (\d{2}) # capture 2 digit area code
+        (\d{3}) # capture first set of numbers in the local number
+        (\d{4}) # capture second set of numbers in the local number
+    |
+    # 1 digit area code.
+        (\d{1}) # capture 1 digit area code
+        (\d{3}) # capture first set of numbers in the local number
+        (\d{4}) # capture second set of numbers in the local number
+    )
+  /x";
+  
+  preg_match($regex, $number, $matches);
+  if (isset($matches[14]) && !empty($matches[14])) {
+    $area     = $matches[14];
+    $head_num = $matches[15];
+    $tail_num = $matches[16];
+  }
+  elseif (isset($matches[11]) && !empty($matches[11])) {
+    $area     = $matches[11];
+    $head_num = $matches[12];
+    $tail_num = $matches[13];
+  }
+  elseif (isset($matches[8]) && !empty($matches[8])) {
+    $area     = $matches[8];
+    $head_num = $matches[9];
+    $tail_num = $matches[10];
+  }
+  elseif (isset($matches[5]) && !empty($matches[5])) {
+    $area     = $matches[5];
+    $head_num = $matches[6];
+    $tail_num = $matches[7];
+  }
+  else {
+    $area     = $matches[2];
+    $head_num = $matches[3];
+    $tail_num = $matches[4];
+  }
+  return '(' . $area . ') ' . $head_num . '-' . $tail_num;
+}

--- js/cck_phone.manage_field.js
+++ js/cck_phone.manage_field.js
@@ -0,0 +1,113 @@
+// $Id: cck_phone.js,v 1.2 2010/07/12 09:54:52 ckng Exp $
+
+Drupal.PhoneNumber = Drupal.PhoneNumber || {};
+
+/**
+ * Filters checkboxes based on their label.
+ * This code is shamelessly taken from checkbox_filter
+ */
+Drupal.PhoneNumber.filter = function() {
+  var field = $(this);
+  var checkboxes = $('.form-checkboxes .form-item', field.parent().parent());
+  var found = false;
+  var label = "";
+  var option = null;
+  for (var i = 0; i < checkboxes.length; i++) {
+    option = checkboxes.eq(i);
+    label = Drupal.PhoneNumber.trim(option.text());
+    if (label.toUpperCase().indexOf(field.val().toUpperCase()) < 0) {
+      option.hide();
+    } else {
+      option.show();
+    }
+  }
+}
+
+/**
+ * Trims whitespace from strings
+ */
+Drupal.PhoneNumber.trim = function(str) {
+	var	str = str.replace(/^\s\s*/, ''),
+		ws = /\s/,
+		i = str.length;
+	while (ws.test(str.charAt(--i)));
+	return str.slice(0, i + 1);
+}
+
+/**
+ * Check/Uncheck all checkboxes
+ */
+Drupal.PhoneNumber.checkall = function(e) {
+  var field = $(this);
+  var checkboxes = $('.form-checkboxes .form-item:visible .form-checkbox', field.parent().parent());
+
+  var checked = (field.text() == Drupal.t('Select all'));
+  if (checked) {
+    checkboxes.attr('checked', true);
+    field.text(Drupal.t('Deselect all'));
+  }
+  else {
+    checkboxes.attr('checked', false);
+    Drupal.PhoneNumber.checkDefault();
+    field.text(Drupal.t('Select all'));
+  }
+}
+
+/**
+ * Country selection should include default country code by default.
+ */
+Drupal.PhoneNumber.checkDefault = function(e) {
+  var defaultCC = $('#edit-default-country').val();
+  var span = $('<span class="default-cc"></span>').append(Drupal.t('Default'));
+
+  if ($('.cck-phone-default-country').find('.form-checkbox').val() == defaultCC) {
+    $('#edit-country-selection-' + defaultCC)
+      .attr('checked', 'checked');
+  }
+  else {
+    $('.cck-phone-default-country')
+      .removeClass('cck-phone-default-country')
+      .find('span.default-cc').remove();
+
+
+    $('#edit-country-selection-' + defaultCC)
+      .attr('checked', 'checked')
+      .parents('.form-item:first')
+        .addClass('cck-phone-default-country')
+        .append(span);
+  }
+}
+
+/**
+ * Attach a filtering textfield to checkboxes.
+ */
+Drupal.behaviors.PhoneNumber = function (context) {
+  // Toggle collapsible on selection
+  $('#edit-all-country-codes').change(function() {
+    if ($(this).attr('checked')) {
+      $('fieldset.cck-phone-settings').addClass('collapsed');
+    }
+    else {
+      $('fieldset.cck-phone-settings').removeClass('collapsed');
+    }
+  });
+  $('#edit-all-country-codes').trigger('change');
+
+  // Ensure the new default country is checked
+  $('#edit-default-country, .cck-phone-settings .form-checkboxes').bind('change', Drupal.PhoneNumber.checkDefault);
+  $('#edit-default-country').trigger('change');
+  $('form#content-field-edit-form').submit(Drupal.PhoneNumber.checkDefault);
+
+
+  // Filter for countries
+  var form = '<div class="form-item">'
+           + '  <label>' + Drupal.t('Filter') + ':</label> '
+           + '  <input class="cck-phone-filter" type="text" size="16" />'
+           + '</div>'
+           + '<div class="form-item">'
+           + '  <a class="cck-phone-check" href="javascript://">' + Drupal.t('Select all') + '</a>'
+           + '</div>';
+  $('.cck-phone-settings .form-checkboxes', context).before(form);
+  $('input.cck-phone-filter').bind('keyup', Drupal.PhoneNumber.filter);
+  $('a.cck-phone-check').bind('click', Drupal.PhoneNumber.checkall);
+}

--- theme/phone-field-view.tpl.php
+++ theme/phone-field-view.tpl.php
@@ -0,0 +1,20 @@
+<?php
+// $Id$
+/**
+ * @file phone-field-view.tpl.php
+ * Default theme implementation for rendering phone number field.
+ *
+ * Available variables:
+ * - $phone: An associative array containing:
+ * -- value: Formatted phone number.
+ * -- int_code: International country calling code.
+ * -- tel_value: Formatted phone number for tel URI.
+ *
+ * @ingroup themeable
+ */
+?>
+<span class="tel">
+  <a href="tel:<?php print $phone['tel_value']; ?>">
+    <?php print '+' . $phone['int_code'] . ' ' . $phone['value']; ?>
+  </a>
+</span>


