/* This file is part of OpenMyEWB. OpenMyEWB is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenMyEWB is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenMyEWB. If not, see <http://www.gnu.org/licenses/>. OpenMyEWB is Copyright 2005-2009 Nicolas Kruchten (nicolas@kruchten.com), Francis Kung, Engineers Without Borders Canada, Michael Trauttmansdorff, Jon Fishbein, David Kadish */ package ca.myewb.frame.forms.element; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.LinkedList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import ca.myewb.frame.Helpers; public abstract class Element { protected String type; protected String label; protected String internalName; protected String value; protected String error; protected boolean highlight; protected boolean required; private String instructions = ""; private String instructionTemplate = ""; public String getInstructionTemplate() { return instructionTemplate; } public void setInstructionTemplate(String instructionTemplate) { this.instructionTemplate = instructionTemplate; } // This is only so Multiment can extend this protected Element() { } protected Element(String name, String label, String value, boolean required) { highlight = false; error = ""; this.internalName = name; this.label = label; this.value = value; this.required = required; } public boolean validate() { // Only validation done here is to check required fields. // Any more detailed validation & input cleaning should be done // in overriding methods in specific elements. if (required && ((value == null) || value.trim().equals(""))) { highlight(); setError("This field is required"); return false; } else { return true; } } public boolean ensureAlphabetic(List<Character> allowed, boolean allowAccents) { return ensureAlphabetic(allowed, value, allowAccents); } private boolean ensureAlphabetic(List<Character> allowed, String value, boolean allowAccents) { if ((value == null) || value.equals("")) { return true; } String strippedValue = value; for (char ok : allowed) { while (strippedValue.indexOf(ok) != -1) { String v2 = strippedValue.substring(0, strippedValue.indexOf(ok)); strippedValue = v2 + strippedValue.substring(strippedValue.indexOf(ok) + 1); } } if ((strippedValue == null) || strippedValue.equals("")) { return true; } char[] chars = strippedValue.toCharArray(); for (int i = 0; i < chars.length; i++) { if (((chars[i] < 'a') || (chars[i] > 'z')) && ((chars[i] < 'A') || (chars[i] > 'Z'))) { if (allowAccents) { Pattern alphabetic = Pattern.compile("^\\p{L}*$", Pattern.CANON_EQ | Pattern.UNICODE_CASE); Matcher myMatcher = alphabetic.matcher(strippedValue); if (!myMatcher.find()) { highlight(); setError("This field can only contain letters"); return false; } } else { highlight(); setError("This field can only contain letters with no accents or diacritics"); return false; } } } return true; } public boolean ensureNumeric(List<Character> allowed) { if (value.equals("") || (value == null)) { return true; } char[] chars = value.toCharArray(); for (int i = 0; i < chars.length; i++) { if (((chars[i] < '0') || (chars[i] > '9')) && !(allowed.contains(new Character(chars[i])))) { highlight(); setError("This field can only contain numbers"); return false; } } return true; } // Bounded numeric public boolean ensureNumeric(List<Character> allowed, int lower, int upper) { if (value.equals("") || (value == null)) { return true; } if (ensureNumeric(allowed) == true) { if (((new Integer(value).intValue()) < lower) || ((new Integer(value).intValue()) > upper)) { highlight(); setError("This field can only contain numbers between " + lower + " and " + upper); return false; } return true; } return false; } public boolean ensureNumeric() { return ensureNumeric(new LinkedList<Character>()); } public boolean ensureNumeric(int lower, int upper) { return ensureNumeric(new LinkedList<Character>(), lower, upper); } public boolean ensureNumeric(int lower) { return ensureNumeric(new LinkedList<Character>(), lower, Integer.MAX_VALUE); } public boolean ensureAlphanumeric(List<Character> allowed, String value, boolean allowAccents) { List<Character> localAllowed = new LinkedList<Character>(); localAllowed.addAll(allowed); for (int i = 0; i < 10; i++) { localAllowed.add(new String(i + "").charAt(0)); } if (!ensureAlphabetic(localAllowed, value, allowAccents)) { highlight(); setError("This field can only contain letters and numbers"); return false; } return true; } public boolean ensureAlphanumeric(List<Character> l, boolean allowAccents) { return ensureAlphanumeric(l, value, allowAccents); } public boolean ensureAlphanumeric(boolean allowAccents) { return ensureAlphanumeric(new LinkedList<Character>(), allowAccents); } public boolean ensureEmail() { return ensureEmail(value, true); } public boolean ensureEmail(String value, boolean fixCase) { if (value.equals("") || (value == null)) { return true; } List<Character> allowed = new LinkedList<Character>(); allowed.add(new Character('.')); allowed.add(new Character('@')); allowed.add(new Character('_')); allowed.add(new Character('-')); if ((ensureAlphanumeric(allowed, value, false) == false) || (value.indexOf('@') != value.lastIndexOf('@'))) { highlight(); setError(value + " is not a valid email address"); return false; } if (value.indexOf('@') != -1) { String user = value.substring(0, value.indexOf('@')); String domain = value.substring(value.indexOf('@') + 1); boolean isValid = !user.equals("") && (domain.indexOf('.') != -1); while (isValid && (domain.indexOf('.') != -1)) { isValid = isValid && (!domain.substring(0, domain.indexOf('.')) .equals("")); domain = domain.substring(domain.indexOf('.') + 1); } isValid = isValid && (domain.length() > 1); if (isValid) { if (fixCase) { this.value = value.toLowerCase(); } return true; } } highlight(); setError(value + " is not a valid email address"); return false; } public boolean ensureEmailList() { String[] emails = value.split("\n"); String cleanList = ""; boolean isClean = true; for (int i = 0; i < emails.length; i++) { String email = emails[i].trim(); isClean = ensureEmail(email, false) && isClean; cleanList = cleanList + email.toLowerCase() + "\n"; } this.value = cleanList.substring(0, cleanList.length() - 1); return isClean; } public boolean ensureWordLength(int maxLength, boolean split) { String[] words = value.split("\\s"); //split on any whitespace for (String word : words) { if (word.length() > maxLength) { if (split) { String fixedword = word.substring(0, maxLength); String secondPart = word.substring(maxLength); while (secondPart.length() > maxLength) { fixedword += (" " + secondPart.substring(0, maxLength)); secondPart = secondPart.substring(maxLength); } fixedword += (" " + secondPart); value = value.replace(word, fixedword); } else //simple trim { value = value.replace(word, word.substring(0, maxLength)); } } } return true; } public boolean ensureTotalLength(boolean invalidIfTooLong, int maxLength) { if (value.length() > maxLength) { if (invalidIfTooLong) { highlight(); setError("This field can only contain up to " + maxLength + " characters."); return false; } else { value = value.substring(0, maxLength); } } return true; } public boolean ensureZipCode() { if (value.equals("") || (value == null)) { return true; } if( !ensureNumeric(0, 99999) ) { setError("Not a valid zip code."); return false; } return true; } public boolean ensurePostalCode() { if (value.equals("") || (value == null)) { return true; } // Remove spaces, if any while (value.indexOf(' ') != -1) { String v2 = value.substring(0, value.indexOf(' ')); value = v2 + value.substring(value.indexOf(' ') + 1); } // Convert to upper case value = value.toUpperCase(); // Check for validity: bad characters & length if (value.length() != 6) { highlight(); setError("This field contained an invalid postal code"); return false; } char[] letters = new char[] { value.charAt(0), value.charAt(2), value.charAt(4) }; for (int i = 0; i < letters.length; i++) { if ((letters[i] < 'A') || (letters[i] > 'Z')) { highlight(); setError("This field contained an invalid postal code"); return false; } } char[] numbers = new char[] { value.charAt(1), value.charAt(3), value.charAt(5) }; for (int i = 0; i < numbers.length; i++) { if ((numbers[i] < '0') || (numbers[i] > '9')) { highlight(); setError("This field contained an invalid postal code"); return false; } } // Now re-add the space String v2 = value.substring(0, 3); value = v2 + " " + value.substring(3); return true; } public boolean ensureDate() { if (value.equals("") || (value == null)) { return true; } DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); try { formatter.parse(value); return true; } catch (ParseException e) { highlight(); setError("Please use YYYY-MM-DD format"); return false; } } public boolean ensureDateTime() { if (value.equals("") || (value == null)) { return true; } DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd kk:mm"); try { formatter.parse(value); return true; } catch (ParseException e) { highlight(); setError("Please use YYYY-MM-DD hh:mm (24-hour time) format"); return false; } } public boolean ensureTime() { if (value.equals("") || (value == null)) { return true; } DateFormat formatter = new SimpleDateFormat("kk:mm"); try { formatter.parse(value); return true; } catch (ParseException e) { highlight(); setError("Please use hh:mm (24-hour time) format"); return false; } } public boolean ensureName() { if (value.equals("") || (value == null)) { return true; } List<Character> allowed = new LinkedList<Character>(); allowed.add(new Character('-')); allowed.add(new Character(' ')); allowed.add(new Character('.')); allowed.add(new Character('\'')); if (ensureAlphanumeric(allowed, true) == false) { highlight(); setError("This contained invalid characters"); return false; } // Reformat it for the lazy people if (value.toUpperCase().equals(value) || value.toLowerCase().equals(value)) { value = value.toLowerCase(); // And capitalize every letter after a space, period, or hyphen int i = 0; while ((i > -1) && (i < value.length())) { // Capitalize the letter at i String front = value.substring(0, i); String end = value.substring(i + 1); String toCap = String.valueOf(value.charAt(i)); toCap = toCap.toUpperCase(); value = front + toCap + end; // Find the next letter needing capitalizing int j = value.indexOf(' ', i); int k = value.indexOf('-', i); if ((j == -1) || ((k < j) && (k != -1))) { j = k; } k = value.indexOf('.', i); if ((j == -1) || ((k < j) && (k != -1))) { j = k; } // Some funky stuff to prevent infinite loops =) if (j == -1) { i = -1; } else { i = j + 1; } } } return true; } public boolean getHighlight() { return highlight; } public void highlight() { highlight = true; } public String getName() { return label; } public String getValue() { if (value == null) { return null; } return value .replace('\u2018', '\'').replace('\u2019', '\'') //fancy apostrophes .replace('\u201D', '"').replace('\u201C', '"') //fancy quotes .replace('\u00AB', '"').replace('\u00BB', '"') //french quotes .replace('\u2013', '-').replace('\u2014', '-') //en and em dashes .replace("\u2026", "...") //ellipsis .replace("\u2022", "-").replace("\u25E6", "-") //bullets .replace("\u25AA", "-").replace("\u25AB", "-") //bullets ; } public String getSafeValue() { if (value == null) return null; else { return Helpers.htmlSafe(getValue()); } } public void setValue(String value) { this.value = value; } public String getType() { return type; } public String getInternalName() { return internalName; } public void require() { required = true; } public boolean isRequired() { return required; } public String getError() { return error; } public void setError(String error) { this.error = error; } public String getTemplate() { return ("frame/elements/" + getType() + ".vm").toLowerCase(); } public boolean ensurePasswordStrength() { if (value.equals("") || (value == null)) { return true; } if (value.length() < 6) { highlight(); setError("Please use at least 6 characters in your password"); return false; } return true; } public String getInstructions() { return instructions; } public void setInstructions(String instructions) { this.instructions = instructions; } public boolean ensureFloat() { if (value.equals("") || (value == null)) { return true; } try { if(Float.parseFloat(value) < 0) { highlight(); setError("This field must only have positive numbers"); return false; } } catch(NumberFormatException e) { highlight(); setError("This field must only have a decimal number"); return false; } return true; } public boolean ensureUrl() { if (value.equals("") || (value == null)) { return true; } if(!value.startsWith("http://") && !value.startsWith("https://")) { highlight(); setError("This field must start with http:// or https://"); return false; } if(!value.contains(".")) { highlight(); setError("That doesn't look like a valid URL."); return false; } return true; } }