--- old.module	2008-03-13 09:30:17.000000000 +0100
+++ elements.module	2008-03-25 08:43:10.000000000 +0100
@@ -1,6 +1,4 @@
 <?php
-// $Id: elements.module,v 1.1.2.1 2008/03/13 08:30:17 heine Exp $
-
 /**
  * Provide a list of additional form element-types.
  *
@@ -11,10 +9,91 @@
  */
 function elements_elements() {
   $types['tableselect'] = array('#input' => TRUE, '#advanced_select' => TRUE, '#multiple' => TRUE, '#process' => array('_elements_expand_tableselect' => array()));
-  $type['imagebutton'] = array('#input' => TRUE, '#button_type' => 'submit',);
+  $types['imagebutton']  = array('#input' => TRUE, '#button_type' => 'submit',);
+  $types['isbn']     = array('#input' => TRUE, '#maxlength' => 13, '#size' => 13, '#validate' => array('elements_isbn_validate' => array()));
+  
   return $types;
 }
 
+/**
+ * Theme function for ISBN fields
+ * 
+ * As ISBN fields are ordinary text fields (they only their own validation function) the result of theme_textfield() is returned
+ */
+function theme_isbn($element) {
+  return theme_textfield($element);
+}
+
+/**
+ * Validate the ISBN field input
+ * 
+ * Checks for ISBN-10 and ISBN-13 data
+ */
+function elements_isbn_validate($element) {
+  $isbn = $element['#value'];
+  
+  if (empty($isbn)) {
+    return;
+  }
+  
+  $digits = str_split($isbn);
+  $count = count($digits);
+  
+  //Check the ISBN's length
+  if ($count != 10 && $count != 13) {
+    form_set_error($element['#name'], t('Please make sure the provided ISBN consists of 10 or 13 characters.'));
+    return;
+  }
+  
+  //Check for illegal characters
+  $first_digits = substr($isbn, 0, $count - 1);
+  $last_digit = strtolower(substr($isbn, $count - 1));
+  if (!ctype_digit($first_digits) || !ctype_digit($last_digit) && $last_digit != 'x') {
+    form_set_error($element['#name'], t('ISBNs may only contain digits and an x.'));
+  }
+  
+  //Check 10-digit ISBNs
+  if ($count == 10) {
+    //10-digit ISBNs can have an x for a check digit which translates to 10
+    if ($last_digit == 'x') {
+      $last_digit = 10;
+    }
+  
+    $sum = 0;
+    
+    //Multiply the first 9 digits and add the results
+    for ($i = 0; $i < 9; $i++) {
+      $sum += $digits[$i] * ($i + 1);
+    }
+    $check_digit = $sum % 11;
+  }
+  
+  //Check 13-digit ISBNs
+  else if ($count == 13) {
+    //Check for the GS1 prefix
+    $gs1 = substr($isbn, 0, 3);
+    if ($gs1 != '978' && $gs1 != '979') {
+      form_set_error($element['#name'], t('Pease provide a correct ISBN.'));
+    }
+    
+    $sum = 0;
+    $multiplier = 1;
+    
+    //Multiply the first 12 digits and add the results
+    for ($i = 0; $i < 12; $i++) {
+      $sum += $digits[$i] * $multiplier;
+      
+      //Alternate the multiplier
+      $multiplier = $multiplier == 1? 3 : 1;
+    }
+    $check_digit = 10 - $sum % 10;
+  }
+  
+  //Check if the check digit is correct
+  if ($check_digit != $last_digit) {
+    form_set_error($element['#name'], t('Please provide a correct ISBN.'));
+  }
+}
 
 function theme_imagebutton($element) {
   return '<input type="image" class="form-'. $element['#button_type'] .'" name="'. $element['#name'] .'" value="'. check_plain($element['#default_value']) .'" '. drupal_attributes($element['#attributes']) . ' src="' . $element['#image'] . '" alt="' . $element['#title'] . '" title="' . $element['#title'] . "\" />\n";
