├── .gitignore
├── LICENSE
├── README.rst
├── example_project
├── __init__.py
├── manage.py
├── media
├── settings.py
├── templates
│ └── test.html
└── urls.py
├── livevalidation
├── __init__.py
├── media
│ ├── css
│ │ └── livevalidation.css
│ └── js
│ │ └── livevalidation_standalone.compressed.js
├── models.py
├── settings.py
├── templates
│ ├── admin
│ │ ├── auth
│ │ │ └── user
│ │ │ │ └── add_form.html
│ │ ├── base_site.html
│ │ └── change_form.html
│ └── livevalidation
│ │ └── header.html
├── templatetags
│ ├── __init__.py
│ └── live_validation.py
├── tests.py
└── validator.py
└── setup.py
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.pyc
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | LiveValidation is licensed under the terms of the MIT License:
2 |
3 | Copyright (c) 2007 Alec Hill ( www.livevalidation.com )
4 |
5 | Django-LiveValidation is licensed under the terms of the MIT License:
6 |
7 | Copyright (c) 2010 Justin Quick
8 |
9 | Permission is hereby granted, free of charge, to any person obtaining a
10 | copy of this software and associated documentation files (the "Software"),
11 | to deal in the Software without restriction, including without limitation
12 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 | and/or sell copies of the Software, and to permit persons to whom the
14 | Software is furnished to do so, subject to the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 | DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | Django Live Validation
2 | ======================
3 |
4 | Django Live Validation provides quick and easy client-side form validation which validates as you type.
5 | It uses the `Live Validation `_ JS library in conjunction with Django Forms.
6 | This is by no means a replacement to Django's built in form validation, but it is a suppliment which is purely client-side baed which cuts down on server-side requests for validation.
7 | This version of django-livevalidation requires Django >= 1.2, for previous versions please use this project: http://opensource.washingtontimes.com/projects/django-livevalidation/
8 |
9 |
10 | Install
11 | --------
12 |
13 | Place ``'livevalidaiton'`` into your ``INSTALLED_APPS`` and make sure it is above the Django admin since it overrides some of the admin templates::
14 |
15 | INSTALLED_APPS = (
16 | 'livevalidation',
17 | ...
18 | 'django.contrib.admin',
19 | )
20 |
21 |
22 | Usage
23 | ------
24 |
25 | To use livevalidation in your templates, make sure you load the headers first before doing anything::
26 |
27 | {% include 'livevalidation/header.html' %}
28 |
29 | This loads the JS library at ``js/livevalidation_standalone.compressed.js`` and the CSS at ``css/livevalidation.css``. Feel free to tweak the CSS to your liking
30 |
31 | Now you can use the templatetag to validate a form instance::
32 |
33 | {% live_validate form [option=value ...] %}
34 |
35 | Where the ``form`` is any ``django.forms.Form`` (or subclass) instance.
36 | The optional option=value kwargs are in pairs as follows:
37 |
38 | - **validMessage** - message to be used upon successful validation (DEFAULT: "Thankyou!")
39 | - **onValid** - javascript function name to execute when field passes validation
40 | - **onInvalid** - javascript function name to execute when field fails validation
41 | - **insertAfterWhatNode** - id of node to have the message inserted after (DEFAULT: the field that is being validated)
42 | - **onlyOnBlur** - whether you want it to validate as you type or only on blur (DEFAULT: False)
43 | - **wait** - the time you want it to pause from the last keystroke before it validates (milliseconds) (DEFAULT: 0)
44 | - **onlyOnSubmit** - if it is part of a form, whether you want it to validate it only when the form is submitted (DEFAULT: False)
--------------------------------------------------------------------------------
/example_project/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/callowayproject/django-livevalidation/0f9dffea23a27618c61d7f88fb7490e81af9a860/example_project/__init__.py
--------------------------------------------------------------------------------
/example_project/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from django.core.management import execute_manager
3 | try:
4 | import settings # Assumed to be in the same directory.
5 | except ImportError:
6 | import sys
7 | sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
8 | sys.exit(1)
9 |
10 | if __name__ == "__main__":
11 | execute_manager(settings)
12 |
--------------------------------------------------------------------------------
/example_project/media:
--------------------------------------------------------------------------------
1 | ../livevalidation/media
--------------------------------------------------------------------------------
/example_project/settings.py:
--------------------------------------------------------------------------------
1 | # Django settings for example_project project.
2 | import sys
3 | import os
4 |
5 | ROOT = os.path.dirname(__file__)
6 |
7 | sys.path.insert(0, os.path.join(ROOT, '..'))
8 |
9 | DEBUG = True
10 | TEMPLATE_DEBUG = DEBUG
11 |
12 | ADMINS = (
13 | # ('Your Name', 'your_email@domain.com'),
14 | )
15 |
16 | MANAGERS = ADMINS
17 |
18 | DATABASES = {
19 | 'default': {
20 | 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
21 | 'NAME': 'dev.db', # Or path to database file if using sqlite3.
22 | }
23 | }
24 |
25 | # Local time zone for this installation. Choices can be found here:
26 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
27 | # although not all choices may be available on all operating systems.
28 | # On Unix systems, a value of None will cause Django to use the same
29 | # timezone as the operating system.
30 | # If running in a Windows environment this must be set to the same as your
31 | # system time zone.
32 | TIME_ZONE = 'America/Eastern'
33 |
34 | # Language code for this installation. All choices can be found here:
35 | # http://www.i18nguy.com/unicode/language-identifiers.html
36 | LANGUAGE_CODE = 'en-us'
37 |
38 | SITE_ID = 1
39 |
40 | # If you set this to False, Django will make some optimizations so as not
41 | # to load the internationalization machinery.
42 | USE_I18N = False
43 |
44 | # If you set this to False, Django will not format dates, numbers and
45 | # calendars according to the current locale
46 | USE_L10N = True
47 |
48 | # Absolute path to the directory that holds media.
49 | # Example: "/home/media/media.lawrence.com/"
50 | MEDIA_ROOT = os.path.join(ROOT, 'media')
51 |
52 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a
53 | # trailing slash if there is a path component (optional in other cases).
54 | # Examples: "http://media.lawrence.com", "http://example.com/media/"
55 | MEDIA_URL = '/media/'
56 |
57 | # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
58 | # trailing slash.
59 | # Examples: "http://foo.com/media/", "/media/".
60 | ADMIN_MEDIA_PREFIX = '/media/admin/'
61 |
62 | # Make this unique, and don't share it with anybody.
63 | SECRET_KEY = 'dth)zzxz*3=5u=_7$xzb(f+h7ye%d%+__gxlw^6uoh7h=&&!ux'
64 |
65 | # List of callables that know how to import templates from various sources.
66 | TEMPLATE_LOADERS = (
67 | 'django.template.loaders.filesystem.Loader',
68 | 'django.template.loaders.app_directories.Loader',
69 | # 'django.template.loaders.eggs.Loader',
70 | )
71 |
72 | MIDDLEWARE_CLASSES = (
73 | 'django.middleware.common.CommonMiddleware',
74 | 'django.contrib.sessions.middleware.SessionMiddleware',
75 | 'django.middleware.csrf.CsrfViewMiddleware',
76 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
77 | 'django.contrib.messages.middleware.MessageMiddleware',
78 | )
79 |
80 | ROOT_URLCONF = 'example_project.urls'
81 |
82 | TEMPLATE_DIRS = (
83 | os.path.join(ROOT, 'templates'),
84 | )
85 |
86 | INSTALLED_APPS = (
87 | 'livevalidation',
88 | 'django.contrib.auth',
89 | 'django.contrib.contenttypes',
90 | 'django.contrib.sessions',
91 | 'django.contrib.sites',
92 | 'django.contrib.messages',
93 | 'django.contrib.admin',
94 | )
95 |
96 | try:
97 | import django_coverage
98 | TEST_RUNNER = 'django_coverage.coverage_runner.run_tests'
99 | except ImportError:
100 | pass
--------------------------------------------------------------------------------
/example_project/templates/test.html:
--------------------------------------------------------------------------------
1 | {% load lv_tags %}
2 |
3 |
4 | {% include 'lv/header.html' %}
5 |
6 |
7 |
8 |
13 |
14 |
--------------------------------------------------------------------------------
/example_project/urls.py:
--------------------------------------------------------------------------------
1 | import os
2 | from django.conf.urls.defaults import *
3 | from django.contrib import admin
4 |
5 | admin.autodiscover()
6 |
7 | urlpatterns = patterns('',
8 | (r'^admin/', include(admin.site.urls)),
9 | (r'^media/(?P.*)$', 'django.views.static.serve',
10 | {'document_root': os.path.join(os.path.dirname(__file__), 'media')}),
11 | )
12 |
--------------------------------------------------------------------------------
/livevalidation/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/callowayproject/django-livevalidation/0f9dffea23a27618c61d7f88fb7490e81af9a860/livevalidation/__init__.py
--------------------------------------------------------------------------------
/livevalidation/media/css/livevalidation.css:
--------------------------------------------------------------------------------
1 | .LV_validation_message{
2 | font-weight:bold;
3 | margin:0 0 0 5px;
4 | }
5 |
6 | .LV_valid {
7 | color:#00CC00;
8 | }
9 |
10 | .LV_invalid {
11 | color:#CC0000;
12 | }
13 |
14 | .LV_valid_field,
15 | input.LV_valid_field:hover,
16 | input.LV_valid_field:active,
17 | textarea.LV_valid_field:hover,
18 | textarea.LV_valid_field:active {
19 | border: 1px solid #00CC00;
20 | }
21 |
22 | .LV_invalid_field,
23 | input.LV_invalid_field:hover,
24 | input.LV_invalid_field:active,
25 | textarea.LV_invalid_field:hover,
26 | textarea.LV_invalid_field:active {
27 | border: 1px solid #CC0000;
28 | }
--------------------------------------------------------------------------------
/livevalidation/media/js/livevalidation_standalone.compressed.js:
--------------------------------------------------------------------------------
1 | // LiveValidation 1.3 (standalone version)
2 | // Copyright (c) 2007-2008 Alec Hill (www.livevalidation.com)
3 | // LiveValidation is licensed under the terms of the MIT License
4 | var LiveValidation=function(B,A){this.initialize(B,A);};LiveValidation.VERSION="1.3 standalone";LiveValidation.TEXTAREA=1;LiveValidation.TEXT=2;LiveValidation.PASSWORD=3;LiveValidation.CHECKBOX=4;LiveValidation.SELECT=5;LiveValidation.FILE=6;LiveValidation.massValidate=function(C){var D=true;for(var B=0,A=C.length;B=300){this.removeMessageAndFieldClass();}var A=this;if(this.timeout){clearTimeout(A.timeout);}this.timeout=setTimeout(function(){A.validate();},A.wait);},doOnBlur:function(A){this.focused=false;this.validate(A);},doOnFocus:function(A){this.focused=true;this.removeMessageAndFieldClass();},getElementType:function(){switch(true){case (this.element.nodeName.toUpperCase()=="TEXTAREA"):return LiveValidation.TEXTAREA;case (this.element.nodeName.toUpperCase()=="INPUT"&&this.element.type.toUpperCase()=="TEXT"):return LiveValidation.TEXT;case (this.element.nodeName.toUpperCase()=="INPUT"&&this.element.type.toUpperCase()=="PASSWORD"):return LiveValidation.PASSWORD;case (this.element.nodeName.toUpperCase()=="INPUT"&&this.element.type.toUpperCase()=="CHECKBOX"):return LiveValidation.CHECKBOX;case (this.element.nodeName.toUpperCase()=="INPUT"&&this.element.type.toUpperCase()=="FILE"):return LiveValidation.FILE;case (this.element.nodeName.toUpperCase()=="SELECT"):return LiveValidation.SELECT;case (this.element.nodeName.toUpperCase()=="INPUT"):throw new Error("LiveValidation::getElementType - Cannot use LiveValidation on an "+this.element.type+" input!");default:throw new Error("LiveValidation::getElementType - Element must be an input, select, or textarea!");}},doValidations:function(){this.validationFailed=false;for(var C=0,A=this.validations.length;CNumber(C)){Validate.fail(K);}break;}return true;},Format:function(C,E){var C=String(C);var E=E||{};var A=E.failureMessage||"Not valid!";var B=E.pattern||/./;var D=E.negate||false;if(!D&&!B.test(C)){Validate.fail(A);}if(D&&B.test(C)){Validate.fail(A);}return true;},Email:function(B,C){var C=C||{};var A=C.failureMessage||"Must be a valid email address!";Validate.Format(B,{failureMessage:A,pattern:/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i});return true;},Length:function(F,G){var F=String(F);var G=G||{};var E=((G.minimum)||(G.minimum==0))?G.minimum:null;var H=((G.maximum)||(G.maximum==0))?G.maximum:null;var C=((G.is)||(G.is==0))?G.is:null;var A=G.wrongLengthMessage||"Must be "+C+" characters long!";var B=G.tooShortMessage||"Must not be less than "+E+" characters long!";var D=G.tooLongMessage||"Must not be more than "+H+" characters long!";switch(true){case (C!==null):if(F.length!=Number(C)){Validate.fail(A);}break;case (E!==null&&H!==null):Validate.Length(F,{tooShortMessage:B,minimum:E});Validate.Length(F,{tooLongMessage:D,maximum:H});break;case (E!==null):if(F.lengthNumber(H)){Validate.fail(D);}break;default:throw new Error("Validate::Length - Length(s) to validate against must be provided!");}return true;},Inclusion:function(H,F){var F=F||{};var K=F.failureMessage||"Must be included in the list!";var G=(F.caseSensitive===false)?false:true;if(F.allowNull&&H==null){return true;}if(!F.allowNull&&H==null){Validate.fail(K);}var D=F.within||[];if(!G){var A=[];for(var C=0,B=D.length;C{% trans "First, enter a username and password. Then, you'll be able to edit more user options." %}