├── test
└── example
│ ├── __init__.py
│ ├── urls.py
│ ├── settings.py
│ └── media
│ └── js
│ ├── jquery.scrollTo.js
│ ├── sha1.lib.js
│ ├── md5.lib.js
│ └── jquery.form.js
├── REQUIREMENTS
├── MANIFEST.in
├── src
└── djjsmin
│ ├── __init__.py
│ ├── utils.py
│ └── commands.py
├── doc
├── markdoc.yaml
└── wiki
│ ├── settings.md
│ └── index.md
├── .gitignore
├── UNLICENSE
├── setup.py
├── README.md
└── distribute_setup.py
/test/example/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/REQUIREMENTS:
--------------------------------------------------------------------------------
1 | django-boss>=0.3
2 | jsmin>=2.0.1
3 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include REQUIREMENTS
2 | include distribute_setup.py
3 |
--------------------------------------------------------------------------------
/src/djjsmin/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | __version__ = '0.2'
4 |
5 |
--------------------------------------------------------------------------------
/doc/markdoc.yaml:
--------------------------------------------------------------------------------
1 | wiki-name: django-jsmin Documentation
2 |
3 | markdown:
4 | extensions:
5 | - codehilite
6 | - def_list
7 | - headerid
8 |
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.egg-info
2 | *.pyc
3 | *.pyo
4 | .DS_Store
5 | MANIFEST
6 | build
7 | dist
8 | doc/.html
9 | doc/.tmp
10 | test/example/dev.db
11 | test/example/media/js/*.min.js
12 |
--------------------------------------------------------------------------------
/test/example/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls.defaults import *
2 |
3 | # Uncomment the next two lines to enable the admin:
4 | # from django.contrib import admin
5 | # admin.autodiscover()
6 |
7 | urlpatterns = patterns('',
8 | # Example:
9 | # (r'^example/', include('example.foo.urls')),
10 |
11 | # Uncomment the admin/doc line below and add 'django.contrib.admindocs'
12 | # to INSTALLED_APPS to enable admin documentation:
13 | # (r'^admin/doc/', include('django.contrib.admindocs.urls')),
14 |
15 | # Uncomment the next line to enable the admin:
16 | # (r'^admin/', include(admin.site.urls)),
17 | )
18 |
--------------------------------------------------------------------------------
/UNLICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | import os
5 | import re
6 |
7 | from distribute_setup import use_setuptools; use_setuptools()
8 | from setuptools import setup, find_packages
9 |
10 |
11 | rel_file = lambda *args: os.path.join(os.path.dirname(os.path.abspath(__file__)), *args)
12 |
13 | def read_from(filename):
14 | fp = open(filename)
15 | try:
16 | return fp.read()
17 | finally:
18 | fp.close()
19 |
20 | def get_version():
21 | data = read_from(rel_file('src', 'djjsmin', '__init__.py'))
22 | return re.search(r"__version__ = '([^']+)'", data).group(1)
23 |
24 | def get_requirements():
25 | data = read_from(rel_file('REQUIREMENTS'))
26 | lines = map(lambda s: s.strip(), data.splitlines())
27 | return filter(None, lines)
28 |
29 |
30 | setup(
31 | name = 'django-jsmin',
32 | version = get_version(),
33 | author = "Zachary Voase",
34 | author_email = "zacharyvoase@me.com",
35 | url = 'http://github.com/zacharyvoase/django-jsmin',
36 | description = "JavaScript library minification for Django.",
37 | packages = find_packages(where='src'),
38 | package_dir = {'': 'src'},
39 | install_requires = get_requirements(),
40 | )
41 |
--------------------------------------------------------------------------------
/test/example/settings.py:
--------------------------------------------------------------------------------
1 | # Django settings for example project.
2 |
3 | DEBUG = True
4 | TEMPLATE_DEBUG = DEBUG
5 |
6 | ADMINS = (
7 | ('Zachary Voase', 'zacharyvoase@me.com'),
8 | )
9 |
10 | MANAGERS = ADMINS
11 |
12 | DATABASE_ENGINE = 'sqlite3'
13 | DATABASE_NAME = 'dev.db'
14 | DATABASE_USER = ''
15 | DATABASE_PASSWORD = ''
16 | DATABASE_HOST = ''
17 | DATABASE_PORT = ''
18 | TIME_ZONE = 'America/Chicago'
19 | LANGUAGE_CODE = 'en-us'
20 | SITE_ID = 1
21 | USE_I18N = True
22 | MEDIA_ROOT = ''
23 | MEDIA_URL = ''
24 | ADMIN_MEDIA_PREFIX = '/media/'
25 | SECRET_KEY = '1(lnvq&ib1(a+=_%(6_)njg0^y$i*2t@e3#0wl1k)zehg*$nf$'
26 | TEMPLATE_LOADERS = (
27 | 'django.template.loaders.filesystem.load_template_source',
28 | 'django.template.loaders.app_directories.load_template_source',
29 | # 'django.template.loaders.eggs.load_template_source',
30 | )
31 | MIDDLEWARE_CLASSES = (
32 | 'django.middleware.common.CommonMiddleware',
33 | 'django.contrib.sessions.middleware.SessionMiddleware',
34 | )
35 | ROOT_URLCONF = 'example.urls'
36 | TEMPLATE_DIRS = (
37 | )
38 |
39 | INSTALLED_APPS = (
40 | 'django.contrib.contenttypes',
41 | 'django.contrib.sessions',
42 | 'django.contrib.sites',
43 | 'djjsmin',
44 | )
45 |
46 | JSMIN_INPUT = [
47 | 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js', # jQuery framework
48 | 'media/js/jquery.*.js', # jQuery plugins
49 | 'media/js/*.lib.js', # Libraries
50 | ]
51 |
52 | JSMIN_OUTPUT = 'media/js/minified.min.js'
53 |
54 |
55 | import logging
56 |
57 | logging.root.setLevel(logging.DEBUG)
58 | handler = logging.StreamHandler()
59 | handler.setLevel(logging.DEBUG)
60 | logging.root.addHandler(handler)
61 |
--------------------------------------------------------------------------------
/doc/wiki/settings.md:
--------------------------------------------------------------------------------
1 | # Settings
2 |
3 | There are a few settings which `django-jsmin` will use to figure out how to build your minified JavaScript library.
4 |
5 | `DEBUG`
6 | : If this is `True`, `django-jsmin` will not (by default) minify the output
7 | JS. This is to help with interactive debugging during development. It can be
8 | overridden with the options to the command-line interface; see the output of
9 | `djboss jsmin --help` for more information.
10 |
11 | `JSMIN_INPUT` (required)
12 | : A list of [glob][] patterns or URLs which `django-jsmin` will expand to get
13 | a list of JavaScript filenames. For example:
14 |
15 | [glob]: http://docs.python.org/library/glob.html
16 |
17 | JSMIN_INPUT = [
18 | 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js',
19 | 'media/js/*.js',
20 | 'apps/*/js/*.js',
21 | ]
22 |
23 | First, the jQuery library is downloaded from Google’s servers. The second
24 | item will be expanded to get a list of the JS files in the `media/js/`
25 | directory. Then, any JS files in the `js/` sub-directory of each application
26 | will be included. Note that if a glob doesn’t match anything, it will just
27 | fail silently (by returning an empty list).
28 |
29 | All relative paths in globs are first resolved. `django-jsmin` will check
30 | for the following settings, in this order:
31 |
32 | * `JSMIN_ROOT`
33 | * `PROJECT_DIR`
34 | * `PROJECT_ROOT`
35 |
36 | Finally, if none exist, the directory containing the settings module will be
37 | considered the base path for resolution.
38 |
39 | `JSMIN_OUTPUT` (required)
40 | : The filename to which the minified JS data will be written. Relative output
41 | filenames will be resolved as specified above.
42 |
43 | `JSMIN_ROOT` (optional)
44 | : See the paragraph on relative glob resolution above.
45 |
46 | `JSMIN_PROLOG` (optional)
47 | : A filename (relative or absolute) which contains a piece of text to include
48 | at the beginning of the minified JS file. This will usually be a comment
49 | containing a copyright statement or license information.
50 |
--------------------------------------------------------------------------------
/src/djjsmin/utils.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import logging
4 | import os
5 | import tempfile
6 | import urllib2
7 | import urlparse
8 |
9 |
10 | LOG = logging.getLogger('django.djjsmin')
11 |
12 |
13 | ## workaround for Python pre-2.6.
14 | if not hasattr(os.path, 'relpath'):
15 | def relpath(path, start=os.path.curdir):
16 | """Return a relative version of a path"""
17 |
18 | if not path:
19 | raise ValueError("no path specified")
20 |
21 | start_list = os.path.abspath(start).split(os.path.sep)
22 | path_list = os.path.abspath(path).split(os.path.sep)
23 |
24 | # Work out how much of the filepath is shared by start and path.
25 | i = len(os.path.commonprefix([start_list, path_list]))
26 |
27 | rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:]
28 | if not rel_list:
29 | return os.path.curdir
30 | return os.path.join(*rel_list)
31 | os.path.relpath = relpath
32 |
33 |
34 | def get_root(settings):
35 | """Get the directory from which to resolve the `JSMIN_INPUT` globs."""
36 |
37 | if hasattr(settings, 'JSMIN_ROOT'):
38 | return settings.JSMIN_ROOT
39 | elif hasattr(settings, 'PROJECT_DIR'):
40 | return settings.PROJECT_DIR
41 | elif hasattr(settings, 'PROJECT_ROOT'):
42 | return settings.PROJECT_ROOT
43 | return os.path.dirname(os.path.abspath(settings.__file__))
44 |
45 |
46 | def get_prolog(settings, root):
47 | """Get the prolog data from the `JSMIN_PROLOG` setting."""
48 |
49 | if hasattr(settings, 'JSMIN_PROLOG'):
50 | filename = make_abs(settings.JSMIN_PROLOG, root)
51 | if not os.path.exists(filename):
52 | LOG.warn("Specified JSMIN_PROLOG does not exist, continuing anyway")
53 | else:
54 | return read_from(filename)
55 | return ''
56 |
57 |
58 | def make_abs(path, root):
59 | """Ensure a path is absolute."""
60 |
61 | return path if os.path.isabs(path) else os.path.abspath(os.path.join(root, path))
62 |
63 |
64 | def temp_fetch(url):
65 | """Fetch a URL and save it in a temporary file, returning the filename."""
66 |
67 | conn = urllib2.urlopen(url)
68 | try:
69 | fp = tempfile.NamedTemporaryFile(delete=False)
70 | LOG.info("Saving %s to a temporary file" % truncate_url(url))
71 | try:
72 | fp.write(conn.read())
73 | finally:
74 | fp.close()
75 | finally:
76 | conn.close()
77 |
78 | LOG.info("Saved %s to %s" % (truncate_url(url), os.path.basename(fp.name)))
79 | return fp.name
80 |
81 |
82 | def truncate_url(url):
83 | """Return a short version of a URL."""
84 |
85 | split = list(urlparse.urlsplit(url))
86 |
87 | path = split[2]
88 | if path == '/' or path.count('/') <= 2:
89 | pass
90 | elif path.endswith('/'):
91 | split[2] = '/.../' + '/'.join(path.rsplit('/', 2)[-2:])
92 | else:
93 | split[2] = '/.../' + path.rsplit('/', 1)[-1]
94 |
95 | return urlparse.urlunsplit(split)
96 |
97 |
98 | def read_from(filename):
99 | fp = open(filename)
100 | try:
101 | return fp.read()
102 | finally:
103 | fp.close()
104 |
--------------------------------------------------------------------------------
/doc/wiki/index.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # `django-jsmin` Documentation
4 |
5 | `django-jsmin` is a reusable application for [Django][] which simplifies and automates the process of [minifying][] your JavaScript libraries.
6 |
7 | [django]: http://www.djangoproject.com/
8 | [minifying]: http://www.crockford.com/javascript/jsmin.html
9 |
10 |
11 | ## Why Minify?
12 |
13 | Minified JS is usually much smaller than regular JS. Comments and whitespace are very helpful when developing JavaScript code, but in production they just take up valuable network bandwidth. The effects of minifying code could range from faster page load times to smaller bandwidth bills from your hosting provider.
14 |
15 | Minification can also obfuscate your code (making it difficult for third parties to copy), although effective obfuscation isn’t guaranteed, since it’s more of a side-effect of the minification process.
16 |
17 |
18 | ## Installation and Setup
19 |
20 | * Install the `django-jsmin` library:
21 |
22 | :::bash
23 | $ pip install django-jsmin # OR
24 | $ easy_install django-jsmin
25 |
26 | These commands will both install all the required dependencies.
27 |
28 | * Add `'djjsmin'` to your `INSTALLED_APPS` setting.
29 |
30 | * Add the necessary settings to your `settings.py` file:
31 |
32 | #!python
33 | JSMIN_ROOT = '/path/to/my/project/'
34 |
35 | # JSMIN_INPUT contains a list of all the input files and URLs.
36 | JSMIN_INPUT = [
37 | 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js',
38 | 'media/js/jquery.*.js', # jQuery plugins
39 | 'media/js/*.src.js', # project-specific libraries
40 | ]
41 |
42 | JSMIN_OUTPUT = 'media/js/project.min.js'
43 |
44 | More information on the available settings can be found [here](/settings).
45 |
46 |
47 | ## `DEBUG` mode
48 |
49 | If `DEBUG` is set to `True` in your Django project when you run `django-jsmin`,
50 | the JavaScript files will only be concatenated to the output file, not
51 | compressed. This allows you to debug your code with meaningful line numbers
52 | during development, and then use the fully-minified version in production. You
53 | can force specific behaviour with options to the `djboss jsmin` command; see the
54 | output of `djboss jsmin --help` for more information.
55 |
56 |
57 | ## Usage
58 |
59 | `django-jsmin` uses [`django-boss`][djboss], a library/tool for writing and
60 | running Django management commands. This will be installed automatically by
61 | setuptools when you install `django-jsmin`.
62 |
63 | [djboss]: http://github.com/zacharyvoase/django-boss
64 |
65 | Usage is relatively simple:
66 |
67 | :::bash
68 | $ djboss --log-level DEBUG jsmin
69 | Saving http://ajax.googleapis.com/.../jquery.js to a temporary file
70 | Saved http://ajax.googleapis.com/.../jquery.js to tmpN7MAsi
71 | Reading tmpN7MAsi
72 | Reading media/js/jquery.plugin1.js
73 | Reading media/js/jquery.plugin2.js
74 | Reading media/js/app-specific.lib.js
75 | Writing to media/js/minified.min.js
76 | Cleaning temporary file tmpN7MAsi
77 |
78 | The JS file will be output to the filename given by the `JSMIN_OUTPUT` setting, in this case `media/js/minified.min.js`.
79 |
80 |
81 | ## License
82 |
83 | `django-jsmin` is licensed under the following MIT/X11-style license:
84 |
85 | > Copyright (c) 2009 Zachary Voase
86 | >
87 | > Permission is hereby granted, free of charge, to any person
88 | > obtaining a copy of this software and associated documentation
89 | > files (the "Software"), to deal in the Software without
90 | > restriction, including without limitation the rights to use,
91 | > copy, modify, merge, publish, distribute, sublicense, and/or sell
92 | > copies of the Software, and to permit persons to whom the
93 | > Software is furnished to do so, subject to the following
94 | > conditions:
95 | >
96 | > The above copyright notice and this permission notice shall be
97 | > included in all copies or substantial portions of the Software.
98 | >
99 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
100 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
101 | > OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
102 | > NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
103 | > HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
104 | > WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
105 | > FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
106 | > OTHER DEALINGS IN THE SOFTWARE.
107 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # `django-jsmin`
2 |
3 | `django-jsmin` is a reusable application for [Django][] which simplifies and automates the process of [minifying][] your JavaScript libraries.
4 |
5 | [django]: http://www.djangoproject.com/
6 | [minifying]: http://www.crockford.com/javascript/jsmin.html
7 |
8 |
9 | ## Why Minify?
10 |
11 | Minified JS is usually much smaller than regular JS. Comments and whitespace are very helpful when developing JavaScript code, but in production they just take up valuable network bandwidth. The effects of minifying code could range from faster page load times to smaller bandwidth bills from your hosting provider.
12 |
13 | Minification can also obfuscate your code (making it difficult for third parties to copy), although effective obfuscation isn’t guaranteed, since it’s more of a side-effect of the minification process.
14 |
15 |
16 | ## Installation and Setup
17 |
18 | * Install the `django-jsmin` library:
19 |
20 | $ pip install django-jsmin # OR
21 | $ easy_install django-jsmin
22 |
23 | These commands will both install all the required dependencies.
24 |
25 | * Add `'djjsmin'` to your `INSTALLED_APPS` setting.
26 |
27 | * Add the necessary settings to your `settings.py` file:
28 |
29 | ## somewhere in settings.py
30 | JSMIN_ROOT = '/path/to/my/project/'
31 |
32 | # JSMIN_INPUT contains a list of all the input files and URLs.
33 | JSMIN_INPUT = [
34 | 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js',
35 | 'media/js/jquery.*.js', # jQuery plugins
36 | 'media/js/*.src.js', # project-specific libraries
37 | ]
38 |
39 | JSMIN_OUTPUT = 'media/js/project.min.js'
40 |
41 | More information on the available settings can be found [here](http://github.com/zacharyvoase/django-jsmin/blob/master/doc/wiki/settings.md).
42 |
43 |
44 | ## `DEBUG` mode
45 |
46 | If `DEBUG` is set to `True` in your Django project when you run `django-jsmin`,
47 | the JavaScript files will only be concatenated to the output file, not
48 | compressed. This allows you to debug your code with meaningful line numbers
49 | during development, and then use the fully-minified version in production. You
50 | can force specific behaviour with options to the `djboss jsmin` command; see the
51 | output of `djboss jsmin --help` for more information.
52 |
53 |
54 | ## Usage
55 |
56 | `django-jsmin` uses [`django-boss`][djboss], a library/tool for writing and
57 | running Django management commands. This will be installed automatically by
58 | setuptools when you install `django-jsmin`.
59 |
60 | [djboss]: http://github.com/zacharyvoase/django-boss
61 |
62 | Usage is relatively simple:
63 |
64 | $ djboss --log-level DEBUG jsmin
65 | Saving http://ajax.googleapis.com/.../jquery.js to a temporary file
66 | Saved http://ajax.googleapis.com/.../jquery.js to tmpN7MAsi
67 | Reading tmpN7MAsi
68 | Reading media/js/jquery.plugin1.js
69 | Reading media/js/jquery.plugin2.js
70 | Reading media/js/app-specific.lib.js
71 | Writing to media/js/minified.min.js
72 | Cleaning temporary file tmpN7MAsi
73 |
74 | The JS file will be output to the filename given by the `JSMIN_OUTPUT` setting, in this case `media/js/minified.min.js`.
75 |
76 |
77 | ## (Un)license
78 |
79 | This is free and unencumbered software released into the public domain.
80 |
81 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
82 | software, either in source code form or as a compiled binary, for any purpose,
83 | commercial or non-commercial, and by any means.
84 |
85 | In jurisdictions that recognize copyright laws, the author or authors of this
86 | software dedicate any and all copyright interest in the software to the public
87 | domain. We make this dedication for the benefit of the public at large and to
88 | the detriment of our heirs and successors. We intend this dedication to be an
89 | overt act of relinquishment in perpetuity of all present and future rights to
90 | this software under copyright law.
91 |
92 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
93 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
94 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE
95 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
96 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
97 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
98 |
99 | For more information, please refer to
100 |
--------------------------------------------------------------------------------
/src/djjsmin/commands.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from cStringIO import StringIO
4 | import glob
5 | import logging
6 | import os
7 | import os.path as p
8 |
9 | from django.core.exceptions import ImproperlyConfigured
10 | from djboss.commands import *
11 | import jsmin as libjsmin
12 |
13 | from djjsmin import utils
14 |
15 |
16 | LOG = logging.getLogger('django.djjsmin')
17 |
18 |
19 | def resolve_patterns(patterns, root):
20 | """Resolve a list of globs/URLs into absolute filenames."""
21 |
22 | input_files, temp_files = [], []
23 |
24 | for pattern in patterns:
25 | # Handle URLs in the JSMIN_INPUT setting.
26 | if pattern.startswith("http:"):
27 | temp_filename = utils.temp_fetch(pattern)
28 | input_files.append(temp_filename)
29 | temp_files.append(temp_filename)
30 |
31 | else:
32 | # Ensure glob patterns are absolute.
33 | glob_files = glob.glob(utils.make_abs(pattern, root))
34 | # Sort filenames within the results of a single pattern.
35 | glob_files.sort()
36 |
37 | for filename in glob_files:
38 | # Make sure there are no repetitions.
39 | if filename not in input_files:
40 | input_files.append(filename)
41 |
42 | return input_files, temp_files
43 |
44 |
45 | @command
46 | @argument('-d', '--dev-mode', action='store_true', default=None, dest='development_mode',
47 | help="Don't minify (just concatenate). Defaults to the value of DEBUG.")
48 | @argument('-p', '--prod-mode', action='store_false', dest='development_mode',
49 | help="Minify, even when DEBUG is True.")
50 | def jsmin(args):
51 | """Minify the configured JavaScript libraries."""
52 |
53 | if not hasattr(args.settings, 'JSMIN_INPUT'):
54 | raise ImproperlyConfigured("Must provide a JSMIN_INPUT setting")
55 | elif not hasattr(args.settings, 'JSMIN_OUTPUT'):
56 | raise ImproperlyConfigured("Must provide a JSMIN_OUTPUT setting")
57 |
58 | root = utils.get_root(args.settings)
59 |
60 | # Set up development mode. If nothing is specified, this will default to the
61 | # value of `settings.DEBUG`. The `-d` and `-p` options override this value.
62 | if args.development_mode is None:
63 | development_mode = args.settings.DEBUG
64 | else:
65 | development_mode = args.development_mode
66 |
67 | # `temp_files` have to be deleted after processing, whether minification was
68 | # successful or not.
69 | input_files, temp_files = resolve_patterns(args.settings.JSMIN_INPUT, root)
70 |
71 | try:
72 | # Get an absolute output filename.
73 | output_file = utils.make_abs(args.settings.JSMIN_OUTPUT, root)
74 |
75 | if output_file in input_files:
76 | # This can happen if you output a '.js' file to the same directory
77 | # you're reading from. Remove it from the input files.
78 | input_files.remove(output_file)
79 |
80 | input_io = StringIO()
81 | try:
82 | # Populate the input StringIO.
83 | for filename in input_files:
84 | if filename in temp_files:
85 | LOG.info("Reading %s" % p.basename(filename))
86 | else:
87 | LOG.info("Reading %s" % p.relpath(filename))
88 |
89 | # The additional whitespace/comments will be filtered out by the
90 | # minifier later on, unless we are in development mode, in which
91 | # case we want the whitespace and comments.
92 | input_io.write("/* FILE: %s */" % filename + os.linesep)
93 | input_io.write(utils.read_from(filename))
94 | input_io.write(os.linesep * 2)
95 | input_io.seek(0)
96 |
97 | output_io = open(output_file, 'w')
98 | try:
99 | output_io.write(utils.get_prolog(args.settings, root))
100 |
101 | if development_mode:
102 | LOG.info("Writing to %s" % p.relpath(output_file))
103 | output_io.write(input_io.getvalue())
104 | else:
105 | # Minify and write the output.
106 | LOG.info("Minifying and writing to %s" % p.relpath(output_file))
107 | libjsmin.JavascriptMinify(input_io, output_io).minify()
108 | finally:
109 | output_io.close() # Clean up.
110 | finally:
111 | input_io.close() # Clean up.
112 |
113 | finally:
114 | # Clean up.
115 | for temp_filename in temp_files:
116 | LOG.info("Cleaning temporary file %s" % p.basename(temp_filename))
117 | os.remove(temp_filename)
118 |
--------------------------------------------------------------------------------
/test/example/media/js/jquery.scrollTo.js:
--------------------------------------------------------------------------------
1 | /**
2 | * jQuery.ScrollTo
3 | * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
4 | * Dual licensed under MIT and GPL.
5 | * Date: 5/25/2009
6 | *
7 | * @projectDescription Easy element scrolling using jQuery.
8 | * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
9 | * Works with jQuery +1.2.6. Tested on FF 2/3, IE 6/7/8, Opera 9.5/6, Safari 3, Chrome 1 on WinXP.
10 | *
11 | * @author Ariel Flesler
12 | * @version 1.4.2
13 | *
14 | * @id jQuery.scrollTo
15 | * @id jQuery.fn.scrollTo
16 | * @param {String, Number, DOMElement, jQuery, Object} target Where to scroll the matched elements.
17 | * The different options for target are:
18 | * - A number position (will be applied to all axes).
19 | * - A string position ('44', '100px', '+=90', etc ) will be applied to all axes
20 | * - A jQuery/DOM element ( logically, child of the element to scroll )
21 | * - A string selector, that will be relative to the element to scroll ( 'li:eq(2)', etc )
22 | * - A hash { top:x, left:y }, x and y can be any kind of number/string like above.
23 | * - A percentage of the container's dimension/s, for example: 50% to go to the middle.
24 | * - The string 'max' for go-to-end.
25 | * @param {Number} duration The OVERALL length of the animation, this argument can be the settings object instead.
26 | * @param {Object,Function} settings Optional set of settings or the onAfter callback.
27 | * @option {String} axis Which axis must be scrolled, use 'x', 'y', 'xy' or 'yx'.
28 | * @option {Number} duration The OVERALL length of the animation.
29 | * @option {String} easing The easing method for the animation.
30 | * @option {Boolean} margin If true, the margin of the target element will be deducted from the final position.
31 | * @option {Object, Number} offset Add/deduct from the end position. One number for both axes or { top:x, left:y }.
32 | * @option {Object, Number} over Add/deduct the height/width multiplied by 'over', can be { top:x, left:y } when using both axes.
33 | * @option {Boolean} queue If true, and both axis are given, the 2nd axis will only be animated after the first one ends.
34 | * @option {Function} onAfter Function to be called after the scrolling ends.
35 | * @option {Function} onAfterFirst If queuing is activated, this function will be called after the first scrolling ends.
36 | * @return {jQuery} Returns the same jQuery object, for chaining.
37 | *
38 | * @desc Scroll to a fixed position
39 | * @example $('div').scrollTo( 340 );
40 | *
41 | * @desc Scroll relatively to the actual position
42 | * @example $('div').scrollTo( '+=340px', { axis:'y' } );
43 | *
44 | * @dec Scroll using a selector (relative to the scrolled element)
45 | * @example $('div').scrollTo( 'p.paragraph:eq(2)', 500, { easing:'swing', queue:true, axis:'xy' } );
46 | *
47 | * @ Scroll to a DOM element (same for jQuery object)
48 | * @example var second_child = document.getElementById('container').firstChild.nextSibling;
49 | * $('#container').scrollTo( second_child, { duration:500, axis:'x', onAfter:function(){
50 | * alert('scrolled!!');
51 | * }});
52 | *
53 | * @desc Scroll on both axes, to different values
54 | * @example $('div').scrollTo( { top: 300, left:'+=200' }, { axis:'xy', offset:-20 } );
55 | */
56 | ;(function( $ ){
57 |
58 | var $scrollTo = $.scrollTo = function( target, duration, settings ){
59 | $(window).scrollTo( target, duration, settings );
60 | };
61 |
62 | $scrollTo.defaults = {
63 | axis:'xy',
64 | duration: parseFloat($.fn.jquery) >= 1.3 ? 0 : 1
65 | };
66 |
67 | // Returns the element that needs to be animated to scroll the window.
68 | // Kept for backwards compatibility (specially for localScroll & serialScroll)
69 | $scrollTo.window = function( scope ){
70 | return $(window)._scrollable();
71 | };
72 |
73 | // Hack, hack, hack :)
74 | // Returns the real elements to scroll (supports window/iframes, documents and regular nodes)
75 | $.fn._scrollable = function(){
76 | return this.map(function(){
77 | var elem = this,
78 | isWin = !elem.nodeName || $.inArray( elem.nodeName.toLowerCase(), ['iframe','#document','html','body'] ) != -1;
79 |
80 | if( !isWin )
81 | return elem;
82 |
83 | var doc = (elem.contentWindow || elem).document || elem.ownerDocument || elem;
84 |
85 | return $.browser.safari || doc.compatMode == 'BackCompat' ?
86 | doc.body :
87 | doc.documentElement;
88 | });
89 | };
90 |
91 | $.fn.scrollTo = function( target, duration, settings ){
92 | if( typeof duration == 'object' ){
93 | settings = duration;
94 | duration = 0;
95 | }
96 | if( typeof settings == 'function' )
97 | settings = { onAfter:settings };
98 |
99 | if( target == 'max' )
100 | target = 9e9;
101 |
102 | settings = $.extend( {}, $scrollTo.defaults, settings );
103 | // Speed is still recognized for backwards compatibility
104 | duration = duration || settings.speed || settings.duration;
105 | // Make sure the settings are given right
106 | settings.queue = settings.queue && settings.axis.length > 1;
107 |
108 | if( settings.queue )
109 | // Let's keep the overall duration
110 | duration /= 2;
111 | settings.offset = both( settings.offset );
112 | settings.over = both( settings.over );
113 |
114 | return this._scrollable().each(function(){
115 | var elem = this,
116 | $elem = $(elem),
117 | targ = target, toff, attr = {},
118 | win = $elem.is('html,body');
119 |
120 | switch( typeof targ ){
121 | // A number will pass the regex
122 | case 'number':
123 | case 'string':
124 | if( /^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(targ) ){
125 | targ = both( targ );
126 | // We are done
127 | break;
128 | }
129 | // Relative selector, no break!
130 | targ = $(targ,this);
131 | case 'object':
132 | // DOMElement / jQuery
133 | if( targ.is || targ.style )
134 | // Get the real position of the target
135 | toff = (targ = $(targ)).offset();
136 | }
137 | $.each( settings.axis.split(''), function( i, axis ){
138 | var Pos = axis == 'x' ? 'Left' : 'Top',
139 | pos = Pos.toLowerCase(),
140 | key = 'scroll' + Pos,
141 | old = elem[key],
142 | max = $scrollTo.max(elem, axis);
143 |
144 | if( toff ){// jQuery / DOMElement
145 | attr[key] = toff[pos] + ( win ? 0 : old - $elem.offset()[pos] );
146 |
147 | // If it's a dom element, reduce the margin
148 | if( settings.margin ){
149 | attr[key] -= parseInt(targ.css('margin'+Pos)) || 0;
150 | attr[key] -= parseInt(targ.css('border'+Pos+'Width')) || 0;
151 | }
152 |
153 | attr[key] += settings.offset[pos] || 0;
154 |
155 | if( settings.over[pos] )
156 | // Scroll to a fraction of its width/height
157 | attr[key] += targ[axis=='x'?'width':'height']() * settings.over[pos];
158 | }else{
159 | var val = targ[pos];
160 | // Handle percentage values
161 | attr[key] = val.slice && val.slice(-1) == '%' ?
162 | parseFloat(val) / 100 * max
163 | : val;
164 | }
165 |
166 | // Number or 'number'
167 | if( /^\d+$/.test(attr[key]) )
168 | // Check the limits
169 | attr[key] = attr[key] <= 0 ? 0 : Math.min( attr[key], max );
170 |
171 | // Queueing axes
172 | if( !i && settings.queue ){
173 | // Don't waste time animating, if there's no need.
174 | if( old != attr[key] )
175 | // Intermediate animation
176 | animate( settings.onAfterFirst );
177 | // Don't animate this axis again in the next iteration.
178 | delete attr[key];
179 | }
180 | });
181 |
182 | animate( settings.onAfter );
183 |
184 | function animate( callback ){
185 | $elem.animate( attr, duration, settings.easing, callback && function(){
186 | callback.call(this, target, settings);
187 | });
188 | };
189 |
190 | }).end();
191 | };
192 |
193 | // Max scrolling position, works on quirks mode
194 | // It only fails (not too badly) on IE, quirks mode.
195 | $scrollTo.max = function( elem, axis ){
196 | var Dim = axis == 'x' ? 'Width' : 'Height',
197 | scroll = 'scroll'+Dim;
198 |
199 | if( !$(elem).is('html,body') )
200 | return elem[scroll] - $(elem)[Dim.toLowerCase()]();
201 |
202 | var size = 'client' + Dim,
203 | html = elem.ownerDocument.documentElement,
204 | body = elem.ownerDocument.body;
205 |
206 | return Math.max( html[scroll], body[scroll] )
207 | - Math.min( html[size] , body[size] );
208 |
209 | };
210 |
211 | function both( val ){
212 | return typeof val == 'object' ? val : { top:val, left:val };
213 | };
214 |
215 | })( jQuery );
--------------------------------------------------------------------------------
/test/example/media/js/sha1.lib.js:
--------------------------------------------------------------------------------
1 | /*
2 | * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
3 | * in FIPS 180-1
4 | * Version 2.2 Copyright Paul Johnston 2000 - 2009.
5 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
6 | * Distributed under the BSD License
7 | * See http://pajhome.org.uk/crypt/md5 for details.
8 | */
9 |
10 | /*
11 | * Configurable variables. You may need to tweak these to be compatible with
12 | * the server-side, but the defaults work in most cases.
13 | */
14 | var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
15 | var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
16 |
17 | /*
18 | * These are the functions you'll usually want to call
19 | * They take string arguments and return either hex or base-64 encoded strings
20 | */
21 | function hex_sha1(s) { return rstr2hex(rstr_sha1(str2rstr_utf8(s))); }
22 | function b64_sha1(s) { return rstr2b64(rstr_sha1(str2rstr_utf8(s))); }
23 | function any_sha1(s, e) { return rstr2any(rstr_sha1(str2rstr_utf8(s)), e); }
24 | function hex_hmac_sha1(k, d)
25 | { return rstr2hex(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); }
26 | function b64_hmac_sha1(k, d)
27 | { return rstr2b64(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); }
28 | function any_hmac_sha1(k, d, e)
29 | { return rstr2any(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
30 |
31 | /*
32 | * Perform a simple self-test to see if the VM is working
33 | */
34 | function sha1_vm_test()
35 | {
36 | return hex_sha1("abc").toLowerCase() == "a9993e364706816aba3e25717850c26c9cd0d89d";
37 | }
38 |
39 | /*
40 | * Calculate the SHA1 of a raw string
41 | */
42 | function rstr_sha1(s)
43 | {
44 | return binb2rstr(binb_sha1(rstr2binb(s), s.length * 8));
45 | }
46 |
47 | /*
48 | * Calculate the HMAC-SHA1 of a key and some data (raw strings)
49 | */
50 | function rstr_hmac_sha1(key, data)
51 | {
52 | var bkey = rstr2binb(key);
53 | if(bkey.length > 16) bkey = binb_sha1(bkey, key.length * 8);
54 |
55 | var ipad = Array(16), opad = Array(16);
56 | for(var i = 0; i < 16; i++)
57 | {
58 | ipad[i] = bkey[i] ^ 0x36363636;
59 | opad[i] = bkey[i] ^ 0x5C5C5C5C;
60 | }
61 |
62 | var hash = binb_sha1(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
63 | return binb2rstr(binb_sha1(opad.concat(hash), 512 + 160));
64 | }
65 |
66 | /*
67 | * Convert a raw string to a hex string
68 | */
69 | function rstr2hex(input)
70 | {
71 | try { hexcase } catch(e) { hexcase=0; }
72 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
73 | var output = "";
74 | var x;
75 | for(var i = 0; i < input.length; i++)
76 | {
77 | x = input.charCodeAt(i);
78 | output += hex_tab.charAt((x >>> 4) & 0x0F)
79 | + hex_tab.charAt( x & 0x0F);
80 | }
81 | return output;
82 | }
83 |
84 | /*
85 | * Convert a raw string to a base-64 string
86 | */
87 | function rstr2b64(input)
88 | {
89 | try { b64pad } catch(e) { b64pad=''; }
90 | var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
91 | var output = "";
92 | var len = input.length;
93 | for(var i = 0; i < len; i += 3)
94 | {
95 | var triplet = (input.charCodeAt(i) << 16)
96 | | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
97 | | (i + 2 < len ? input.charCodeAt(i+2) : 0);
98 | for(var j = 0; j < 4; j++)
99 | {
100 | if(i * 8 + j * 6 > input.length * 8) output += b64pad;
101 | else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
102 | }
103 | }
104 | return output;
105 | }
106 |
107 | /*
108 | * Convert a raw string to an arbitrary string encoding
109 | */
110 | function rstr2any(input, encoding)
111 | {
112 | var divisor = encoding.length;
113 | var remainders = Array();
114 | var i, q, x, quotient;
115 |
116 | /* Convert to an array of 16-bit big-endian values, forming the dividend */
117 | var dividend = Array(Math.ceil(input.length / 2));
118 | for(i = 0; i < dividend.length; i++)
119 | {
120 | dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
121 | }
122 |
123 | /*
124 | * Repeatedly perform a long division. The binary array forms the dividend,
125 | * the length of the encoding is the divisor. Once computed, the quotient
126 | * forms the dividend for the next step. We stop when the dividend is zero.
127 | * All remainders are stored for later use.
128 | */
129 | while(dividend.length > 0)
130 | {
131 | quotient = Array();
132 | x = 0;
133 | for(i = 0; i < dividend.length; i++)
134 | {
135 | x = (x << 16) + dividend[i];
136 | q = Math.floor(x / divisor);
137 | x -= q * divisor;
138 | if(quotient.length > 0 || q > 0)
139 | quotient[quotient.length] = q;
140 | }
141 | remainders[remainders.length] = x;
142 | dividend = quotient;
143 | }
144 |
145 | /* Convert the remainders to the output string */
146 | var output = "";
147 | for(i = remainders.length - 1; i >= 0; i--)
148 | output += encoding.charAt(remainders[i]);
149 |
150 | /* Append leading zero equivalents */
151 | var full_length = Math.ceil(input.length * 8 /
152 | (Math.log(encoding.length) / Math.log(2)))
153 | for(i = output.length; i < full_length; i++)
154 | output = encoding[0] + output;
155 |
156 | return output;
157 | }
158 |
159 | /*
160 | * Encode a string as utf-8.
161 | * For efficiency, this assumes the input is valid utf-16.
162 | */
163 | function str2rstr_utf8(input)
164 | {
165 | var output = "";
166 | var i = -1;
167 | var x, y;
168 |
169 | while(++i < input.length)
170 | {
171 | /* Decode utf-16 surrogate pairs */
172 | x = input.charCodeAt(i);
173 | y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
174 | if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
175 | {
176 | x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
177 | i++;
178 | }
179 |
180 | /* Encode output as utf-8 */
181 | if(x <= 0x7F)
182 | output += String.fromCharCode(x);
183 | else if(x <= 0x7FF)
184 | output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
185 | 0x80 | ( x & 0x3F));
186 | else if(x <= 0xFFFF)
187 | output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
188 | 0x80 | ((x >>> 6 ) & 0x3F),
189 | 0x80 | ( x & 0x3F));
190 | else if(x <= 0x1FFFFF)
191 | output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
192 | 0x80 | ((x >>> 12) & 0x3F),
193 | 0x80 | ((x >>> 6 ) & 0x3F),
194 | 0x80 | ( x & 0x3F));
195 | }
196 | return output;
197 | }
198 |
199 | /*
200 | * Encode a string as utf-16
201 | */
202 | function str2rstr_utf16le(input)
203 | {
204 | var output = "";
205 | for(var i = 0; i < input.length; i++)
206 | output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
207 | (input.charCodeAt(i) >>> 8) & 0xFF);
208 | return output;
209 | }
210 |
211 | function str2rstr_utf16be(input)
212 | {
213 | var output = "";
214 | for(var i = 0; i < input.length; i++)
215 | output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
216 | input.charCodeAt(i) & 0xFF);
217 | return output;
218 | }
219 |
220 | /*
221 | * Convert a raw string to an array of big-endian words
222 | * Characters >255 have their high-byte silently ignored.
223 | */
224 | function rstr2binb(input)
225 | {
226 | var output = Array(input.length >> 2);
227 | for(var i = 0; i < output.length; i++)
228 | output[i] = 0;
229 | for(var i = 0; i < input.length * 8; i += 8)
230 | output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
231 | return output;
232 | }
233 |
234 | /*
235 | * Convert an array of big-endian words to a string
236 | */
237 | function binb2rstr(input)
238 | {
239 | var output = "";
240 | for(var i = 0; i < input.length * 32; i += 8)
241 | output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
242 | return output;
243 | }
244 |
245 | /*
246 | * Calculate the SHA-1 of an array of big-endian words, and a bit length
247 | */
248 | function binb_sha1(x, len)
249 | {
250 | /* append padding */
251 | x[len >> 5] |= 0x80 << (24 - len % 32);
252 | x[((len + 64 >> 9) << 4) + 15] = len;
253 |
254 | var w = Array(80);
255 | var a = 1732584193;
256 | var b = -271733879;
257 | var c = -1732584194;
258 | var d = 271733878;
259 | var e = -1009589776;
260 |
261 | for(var i = 0; i < x.length; i += 16)
262 | {
263 | var olda = a;
264 | var oldb = b;
265 | var oldc = c;
266 | var oldd = d;
267 | var olde = e;
268 |
269 | for(var j = 0; j < 80; j++)
270 | {
271 | if(j < 16) w[j] = x[i + j];
272 | else w[j] = bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
273 | var t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)),
274 | safe_add(safe_add(e, w[j]), sha1_kt(j)));
275 | e = d;
276 | d = c;
277 | c = bit_rol(b, 30);
278 | b = a;
279 | a = t;
280 | }
281 |
282 | a = safe_add(a, olda);
283 | b = safe_add(b, oldb);
284 | c = safe_add(c, oldc);
285 | d = safe_add(d, oldd);
286 | e = safe_add(e, olde);
287 | }
288 | return Array(a, b, c, d, e);
289 |
290 | }
291 |
292 | /*
293 | * Perform the appropriate triplet combination function for the current
294 | * iteration
295 | */
296 | function sha1_ft(t, b, c, d)
297 | {
298 | if(t < 20) return (b & c) | ((~b) & d);
299 | if(t < 40) return b ^ c ^ d;
300 | if(t < 60) return (b & c) | (b & d) | (c & d);
301 | return b ^ c ^ d;
302 | }
303 |
304 | /*
305 | * Determine the appropriate additive constant for the current iteration
306 | */
307 | function sha1_kt(t)
308 | {
309 | return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
310 | (t < 60) ? -1894007588 : -899497514;
311 | }
312 |
313 | /*
314 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally
315 | * to work around bugs in some JS interpreters.
316 | */
317 | function safe_add(x, y)
318 | {
319 | var lsw = (x & 0xFFFF) + (y & 0xFFFF);
320 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
321 | return (msw << 16) | (lsw & 0xFFFF);
322 | }
323 |
324 | /*
325 | * Bitwise rotate a 32-bit number to the left.
326 | */
327 | function bit_rol(num, cnt)
328 | {
329 | return (num << cnt) | (num >>> (32 - cnt));
330 | }
331 |
--------------------------------------------------------------------------------
/test/example/media/js/md5.lib.js:
--------------------------------------------------------------------------------
1 | /*
2 | * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
3 | * Digest Algorithm, as defined in RFC 1321.
4 | * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
5 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
6 | * Distributed under the BSD License
7 | * See http://pajhome.org.uk/crypt/md5 for more info.
8 | */
9 |
10 | /*
11 | * Configurable variables. You may need to tweak these to be compatible with
12 | * the server-side, but the defaults work in most cases.
13 | */
14 | var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
15 | var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
16 |
17 | /*
18 | * These are the functions you'll usually want to call
19 | * They take string arguments and return either hex or base-64 encoded strings
20 | */
21 | function hex_md5(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); }
22 | function b64_md5(s) { return rstr2b64(rstr_md5(str2rstr_utf8(s))); }
23 | function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); }
24 | function hex_hmac_md5(k, d)
25 | { return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
26 | function b64_hmac_md5(k, d)
27 | { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
28 | function any_hmac_md5(k, d, e)
29 | { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
30 |
31 | /*
32 | * Perform a simple self-test to see if the VM is working
33 | */
34 | function md5_vm_test()
35 | {
36 | return hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72";
37 | }
38 |
39 | /*
40 | * Calculate the MD5 of a raw string
41 | */
42 | function rstr_md5(s)
43 | {
44 | return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
45 | }
46 |
47 | /*
48 | * Calculate the HMAC-MD5, of a key and some data (raw strings)
49 | */
50 | function rstr_hmac_md5(key, data)
51 | {
52 | var bkey = rstr2binl(key);
53 | if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8);
54 |
55 | var ipad = Array(16), opad = Array(16);
56 | for(var i = 0; i < 16; i++)
57 | {
58 | ipad[i] = bkey[i] ^ 0x36363636;
59 | opad[i] = bkey[i] ^ 0x5C5C5C5C;
60 | }
61 |
62 | var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
63 | return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
64 | }
65 |
66 | /*
67 | * Convert a raw string to a hex string
68 | */
69 | function rstr2hex(input)
70 | {
71 | try { hexcase } catch(e) { hexcase=0; }
72 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
73 | var output = "";
74 | var x;
75 | for(var i = 0; i < input.length; i++)
76 | {
77 | x = input.charCodeAt(i);
78 | output += hex_tab.charAt((x >>> 4) & 0x0F)
79 | + hex_tab.charAt( x & 0x0F);
80 | }
81 | return output;
82 | }
83 |
84 | /*
85 | * Convert a raw string to a base-64 string
86 | */
87 | function rstr2b64(input)
88 | {
89 | try { b64pad } catch(e) { b64pad=''; }
90 | var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
91 | var output = "";
92 | var len = input.length;
93 | for(var i = 0; i < len; i += 3)
94 | {
95 | var triplet = (input.charCodeAt(i) << 16)
96 | | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
97 | | (i + 2 < len ? input.charCodeAt(i+2) : 0);
98 | for(var j = 0; j < 4; j++)
99 | {
100 | if(i * 8 + j * 6 > input.length * 8) output += b64pad;
101 | else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
102 | }
103 | }
104 | return output;
105 | }
106 |
107 | /*
108 | * Convert a raw string to an arbitrary string encoding
109 | */
110 | function rstr2any(input, encoding)
111 | {
112 | var divisor = encoding.length;
113 | var i, j, q, x, quotient;
114 |
115 | /* Convert to an array of 16-bit big-endian values, forming the dividend */
116 | var dividend = Array(Math.ceil(input.length / 2));
117 | for(i = 0; i < dividend.length; i++)
118 | {
119 | dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
120 | }
121 |
122 | /*
123 | * Repeatedly perform a long division. The binary array forms the dividend,
124 | * the length of the encoding is the divisor. Once computed, the quotient
125 | * forms the dividend for the next step. All remainders are stored for later
126 | * use.
127 | */
128 | var full_length = Math.ceil(input.length * 8 /
129 | (Math.log(encoding.length) / Math.log(2)));
130 | var remainders = Array(full_length);
131 | for(j = 0; j < full_length; j++)
132 | {
133 | quotient = Array();
134 | x = 0;
135 | for(i = 0; i < dividend.length; i++)
136 | {
137 | x = (x << 16) + dividend[i];
138 | q = Math.floor(x / divisor);
139 | x -= q * divisor;
140 | if(quotient.length > 0 || q > 0)
141 | quotient[quotient.length] = q;
142 | }
143 | remainders[j] = x;
144 | dividend = quotient;
145 | }
146 |
147 | /* Convert the remainders to the output string */
148 | var output = "";
149 | for(i = remainders.length - 1; i >= 0; i--)
150 | output += encoding.charAt(remainders[i]);
151 |
152 | return output;
153 | }
154 |
155 | /*
156 | * Encode a string as utf-8.
157 | * For efficiency, this assumes the input is valid utf-16.
158 | */
159 | function str2rstr_utf8(input)
160 | {
161 | var output = "";
162 | var i = -1;
163 | var x, y;
164 |
165 | while(++i < input.length)
166 | {
167 | /* Decode utf-16 surrogate pairs */
168 | x = input.charCodeAt(i);
169 | y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
170 | if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
171 | {
172 | x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
173 | i++;
174 | }
175 |
176 | /* Encode output as utf-8 */
177 | if(x <= 0x7F)
178 | output += String.fromCharCode(x);
179 | else if(x <= 0x7FF)
180 | output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
181 | 0x80 | ( x & 0x3F));
182 | else if(x <= 0xFFFF)
183 | output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
184 | 0x80 | ((x >>> 6 ) & 0x3F),
185 | 0x80 | ( x & 0x3F));
186 | else if(x <= 0x1FFFFF)
187 | output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
188 | 0x80 | ((x >>> 12) & 0x3F),
189 | 0x80 | ((x >>> 6 ) & 0x3F),
190 | 0x80 | ( x & 0x3F));
191 | }
192 | return output;
193 | }
194 |
195 | /*
196 | * Encode a string as utf-16
197 | */
198 | function str2rstr_utf16le(input)
199 | {
200 | var output = "";
201 | for(var i = 0; i < input.length; i++)
202 | output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
203 | (input.charCodeAt(i) >>> 8) & 0xFF);
204 | return output;
205 | }
206 |
207 | function str2rstr_utf16be(input)
208 | {
209 | var output = "";
210 | for(var i = 0; i < input.length; i++)
211 | output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
212 | input.charCodeAt(i) & 0xFF);
213 | return output;
214 | }
215 |
216 | /*
217 | * Convert a raw string to an array of little-endian words
218 | * Characters >255 have their high-byte silently ignored.
219 | */
220 | function rstr2binl(input)
221 | {
222 | var output = Array(input.length >> 2);
223 | for(var i = 0; i < output.length; i++)
224 | output[i] = 0;
225 | for(var i = 0; i < input.length * 8; i += 8)
226 | output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
227 | return output;
228 | }
229 |
230 | /*
231 | * Convert an array of little-endian words to a string
232 | */
233 | function binl2rstr(input)
234 | {
235 | var output = "";
236 | for(var i = 0; i < input.length * 32; i += 8)
237 | output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
238 | return output;
239 | }
240 |
241 | /*
242 | * Calculate the MD5 of an array of little-endian words, and a bit length.
243 | */
244 | function binl_md5(x, len)
245 | {
246 | /* append padding */
247 | x[len >> 5] |= 0x80 << ((len) % 32);
248 | x[(((len + 64) >>> 9) << 4) + 14] = len;
249 |
250 | var a = 1732584193;
251 | var b = -271733879;
252 | var c = -1732584194;
253 | var d = 271733878;
254 |
255 | for(var i = 0; i < x.length; i += 16)
256 | {
257 | var olda = a;
258 | var oldb = b;
259 | var oldc = c;
260 | var oldd = d;
261 |
262 | a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
263 | d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
264 | c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
265 | b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
266 | a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
267 | d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
268 | c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
269 | b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
270 | a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
271 | d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
272 | c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
273 | b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
274 | a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
275 | d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
276 | c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
277 | b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
278 |
279 | a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
280 | d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
281 | c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
282 | b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
283 | a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
284 | d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
285 | c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
286 | b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
287 | a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
288 | d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
289 | c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
290 | b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
291 | a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
292 | d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
293 | c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
294 | b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
295 |
296 | a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
297 | d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
298 | c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
299 | b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
300 | a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
301 | d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
302 | c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
303 | b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
304 | a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
305 | d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
306 | c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
307 | b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
308 | a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
309 | d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
310 | c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
311 | b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
312 |
313 | a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
314 | d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
315 | c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
316 | b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
317 | a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
318 | d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
319 | c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
320 | b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
321 | a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
322 | d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
323 | c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
324 | b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
325 | a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
326 | d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
327 | c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
328 | b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
329 |
330 | a = safe_add(a, olda);
331 | b = safe_add(b, oldb);
332 | c = safe_add(c, oldc);
333 | d = safe_add(d, oldd);
334 | }
335 | return Array(a, b, c, d);
336 | }
337 |
338 | /*
339 | * These functions implement the four basic operations the algorithm uses.
340 | */
341 | function md5_cmn(q, a, b, x, s, t)
342 | {
343 | return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
344 | }
345 | function md5_ff(a, b, c, d, x, s, t)
346 | {
347 | return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
348 | }
349 | function md5_gg(a, b, c, d, x, s, t)
350 | {
351 | return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
352 | }
353 | function md5_hh(a, b, c, d, x, s, t)
354 | {
355 | return md5_cmn(b ^ c ^ d, a, b, x, s, t);
356 | }
357 | function md5_ii(a, b, c, d, x, s, t)
358 | {
359 | return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
360 | }
361 |
362 | /*
363 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally
364 | * to work around bugs in some JS interpreters.
365 | */
366 | function safe_add(x, y)
367 | {
368 | var lsw = (x & 0xFFFF) + (y & 0xFFFF);
369 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
370 | return (msw << 16) | (lsw & 0xFFFF);
371 | }
372 |
373 | /*
374 | * Bitwise rotate a 32-bit number to the left.
375 | */
376 | function bit_rol(num, cnt)
377 | {
378 | return (num << cnt) | (num >>> (32 - cnt));
379 | }
380 |
--------------------------------------------------------------------------------
/distribute_setup.py:
--------------------------------------------------------------------------------
1 | #!python
2 | """Bootstrap distribute installation
3 |
4 | If you want to use setuptools in your package's setup.py, just include this
5 | file in the same directory with it, and add this to the top of your setup.py::
6 |
7 | from distribute_setup import use_setuptools
8 | use_setuptools()
9 |
10 | If you want to require a specific version of setuptools, set a download
11 | mirror, or use an alternate download directory, you can do so by supplying
12 | the appropriate options to ``use_setuptools()``.
13 |
14 | This file can also be run as a script to install or upgrade setuptools.
15 | """
16 | import os
17 | import sys
18 | import time
19 | import fnmatch
20 | import tempfile
21 | import tarfile
22 | from distutils import log
23 |
24 | try:
25 | from site import USER_SITE
26 | except ImportError:
27 | USER_SITE = None
28 |
29 | try:
30 | import subprocess
31 |
32 | def _python_cmd(*args):
33 | args = (sys.executable,) + args
34 | return subprocess.call(args) == 0
35 |
36 | except ImportError:
37 | # will be used for python 2.3
38 | def _python_cmd(*args):
39 | args = (sys.executable,) + args
40 | # quoting arguments if windows
41 | if sys.platform == 'win32':
42 | def quote(arg):
43 | if ' ' in arg:
44 | return '"%s"' % arg
45 | return arg
46 | args = [quote(arg) for arg in args]
47 | return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
48 |
49 | DEFAULT_VERSION = "0.6.10"
50 | DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
51 | SETUPTOOLS_FAKED_VERSION = "0.6c11"
52 |
53 | SETUPTOOLS_PKG_INFO = """\
54 | Metadata-Version: 1.0
55 | Name: setuptools
56 | Version: %s
57 | Summary: xxxx
58 | Home-page: xxx
59 | Author: xxx
60 | Author-email: xxx
61 | License: xxx
62 | Description: xxx
63 | """ % SETUPTOOLS_FAKED_VERSION
64 |
65 |
66 | def _install(tarball):
67 | # extracting the tarball
68 | tmpdir = tempfile.mkdtemp()
69 | log.warn('Extracting in %s', tmpdir)
70 | old_wd = os.getcwd()
71 | try:
72 | os.chdir(tmpdir)
73 | tar = tarfile.open(tarball)
74 | _extractall(tar)
75 | tar.close()
76 |
77 | # going in the directory
78 | subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
79 | os.chdir(subdir)
80 | log.warn('Now working in %s', subdir)
81 |
82 | # installing
83 | log.warn('Installing Distribute')
84 | if not _python_cmd('setup.py', 'install'):
85 | log.warn('Something went wrong during the installation.')
86 | log.warn('See the error message above.')
87 | finally:
88 | os.chdir(old_wd)
89 |
90 |
91 | def _build_egg(egg, tarball, to_dir):
92 | # extracting the tarball
93 | tmpdir = tempfile.mkdtemp()
94 | log.warn('Extracting in %s', tmpdir)
95 | old_wd = os.getcwd()
96 | try:
97 | os.chdir(tmpdir)
98 | tar = tarfile.open(tarball)
99 | _extractall(tar)
100 | tar.close()
101 |
102 | # going in the directory
103 | subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
104 | os.chdir(subdir)
105 | log.warn('Now working in %s', subdir)
106 |
107 | # building an egg
108 | log.warn('Building a Distribute egg in %s', to_dir)
109 | _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
110 |
111 | finally:
112 | os.chdir(old_wd)
113 | # returning the result
114 | log.warn(egg)
115 | if not os.path.exists(egg):
116 | raise IOError('Could not build the egg.')
117 |
118 |
119 | def _do_download(version, download_base, to_dir, download_delay):
120 | egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
121 | % (version, sys.version_info[0], sys.version_info[1]))
122 | if not os.path.exists(egg):
123 | tarball = download_setuptools(version, download_base,
124 | to_dir, download_delay)
125 | _build_egg(egg, tarball, to_dir)
126 | sys.path.insert(0, egg)
127 | import setuptools
128 | setuptools.bootstrap_install_from = egg
129 |
130 |
131 | def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
132 | to_dir=os.curdir, download_delay=15, no_fake=True):
133 | # making sure we use the absolute path
134 | to_dir = os.path.abspath(to_dir)
135 | was_imported = 'pkg_resources' in sys.modules or \
136 | 'setuptools' in sys.modules
137 | try:
138 | try:
139 | import pkg_resources
140 | if not hasattr(pkg_resources, '_distribute'):
141 | if not no_fake:
142 | _fake_setuptools()
143 | raise ImportError
144 | except ImportError:
145 | return _do_download(version, download_base, to_dir, download_delay)
146 | try:
147 | pkg_resources.require("distribute>="+version)
148 | return
149 | except pkg_resources.VersionConflict:
150 | e = sys.exc_info()[1]
151 | if was_imported:
152 | sys.stderr.write(
153 | "The required version of distribute (>=%s) is not available,\n"
154 | "and can't be installed while this script is running. Please\n"
155 | "install a more recent version first, using\n"
156 | "'easy_install -U distribute'."
157 | "\n\n(Currently using %r)\n" % (version, e.args[0]))
158 | sys.exit(2)
159 | else:
160 | del pkg_resources, sys.modules['pkg_resources'] # reload ok
161 | return _do_download(version, download_base, to_dir,
162 | download_delay)
163 | except pkg_resources.DistributionNotFound:
164 | return _do_download(version, download_base, to_dir,
165 | download_delay)
166 | finally:
167 | if not no_fake:
168 | _create_fake_setuptools_pkg_info(to_dir)
169 |
170 | def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
171 | to_dir=os.curdir, delay=15):
172 | """Download distribute from a specified location and return its filename
173 |
174 | `version` should be a valid distribute version number that is available
175 | as an egg for download under the `download_base` URL (which should end
176 | with a '/'). `to_dir` is the directory where the egg will be downloaded.
177 | `delay` is the number of seconds to pause before an actual download
178 | attempt.
179 | """
180 | # making sure we use the absolute path
181 | to_dir = os.path.abspath(to_dir)
182 | try:
183 | from urllib.request import urlopen
184 | except ImportError:
185 | from urllib2 import urlopen
186 | tgz_name = "distribute-%s.tar.gz" % version
187 | url = download_base + tgz_name
188 | saveto = os.path.join(to_dir, tgz_name)
189 | src = dst = None
190 | if not os.path.exists(saveto): # Avoid repeated downloads
191 | try:
192 | log.warn("Downloading %s", url)
193 | src = urlopen(url)
194 | # Read/write all in one block, so we don't create a corrupt file
195 | # if the download is interrupted.
196 | data = src.read()
197 | dst = open(saveto, "wb")
198 | dst.write(data)
199 | finally:
200 | if src:
201 | src.close()
202 | if dst:
203 | dst.close()
204 | return os.path.realpath(saveto)
205 |
206 |
207 | def _patch_file(path, content):
208 | """Will backup the file then patch it"""
209 | existing_content = open(path).read()
210 | if existing_content == content:
211 | # already patched
212 | log.warn('Already patched.')
213 | return False
214 | log.warn('Patching...')
215 | _rename_path(path)
216 | f = open(path, 'w')
217 | try:
218 | f.write(content)
219 | finally:
220 | f.close()
221 | return True
222 |
223 |
224 | def _same_content(path, content):
225 | return open(path).read() == content
226 |
227 | def _no_sandbox(function):
228 | def __no_sandbox(*args, **kw):
229 | try:
230 | from setuptools.sandbox import DirectorySandbox
231 | def violation(*args):
232 | pass
233 | DirectorySandbox._old = DirectorySandbox._violation
234 | DirectorySandbox._violation = violation
235 | patched = True
236 | except ImportError:
237 | patched = False
238 |
239 | try:
240 | return function(*args, **kw)
241 | finally:
242 | if patched:
243 | DirectorySandbox._violation = DirectorySandbox._old
244 | del DirectorySandbox._old
245 |
246 | return __no_sandbox
247 |
248 | @_no_sandbox
249 | def _rename_path(path):
250 | new_name = path + '.OLD.%s' % time.time()
251 | log.warn('Renaming %s into %s', path, new_name)
252 | os.rename(path, new_name)
253 | return new_name
254 |
255 | def _remove_flat_installation(placeholder):
256 | if not os.path.isdir(placeholder):
257 | log.warn('Unkown installation at %s', placeholder)
258 | return False
259 | found = False
260 | for file in os.listdir(placeholder):
261 | if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
262 | found = True
263 | break
264 | if not found:
265 | log.warn('Could not locate setuptools*.egg-info')
266 | return
267 |
268 | log.warn('Removing elements out of the way...')
269 | pkg_info = os.path.join(placeholder, file)
270 | if os.path.isdir(pkg_info):
271 | patched = _patch_egg_dir(pkg_info)
272 | else:
273 | patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
274 |
275 | if not patched:
276 | log.warn('%s already patched.', pkg_info)
277 | return False
278 | # now let's move the files out of the way
279 | for element in ('setuptools', 'pkg_resources.py', 'site.py'):
280 | element = os.path.join(placeholder, element)
281 | if os.path.exists(element):
282 | _rename_path(element)
283 | else:
284 | log.warn('Could not find the %s element of the '
285 | 'Setuptools distribution', element)
286 | return True
287 |
288 |
289 | def _after_install(dist):
290 | log.warn('After install bootstrap.')
291 | placeholder = dist.get_command_obj('install').install_purelib
292 | _create_fake_setuptools_pkg_info(placeholder)
293 |
294 | @_no_sandbox
295 | def _create_fake_setuptools_pkg_info(placeholder):
296 | if not placeholder or not os.path.exists(placeholder):
297 | log.warn('Could not find the install location')
298 | return
299 | pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
300 | setuptools_file = 'setuptools-%s-py%s.egg-info' % \
301 | (SETUPTOOLS_FAKED_VERSION, pyver)
302 | pkg_info = os.path.join(placeholder, setuptools_file)
303 | if os.path.exists(pkg_info):
304 | log.warn('%s already exists', pkg_info)
305 | return
306 |
307 | log.warn('Creating %s', pkg_info)
308 | f = open(pkg_info, 'w')
309 | try:
310 | f.write(SETUPTOOLS_PKG_INFO)
311 | finally:
312 | f.close()
313 |
314 | pth_file = os.path.join(placeholder, 'setuptools.pth')
315 | log.warn('Creating %s', pth_file)
316 | f = open(pth_file, 'w')
317 | try:
318 | f.write(os.path.join(os.curdir, setuptools_file))
319 | finally:
320 | f.close()
321 |
322 | def _patch_egg_dir(path):
323 | # let's check if it's already patched
324 | pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
325 | if os.path.exists(pkg_info):
326 | if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
327 | log.warn('%s already patched.', pkg_info)
328 | return False
329 | _rename_path(path)
330 | os.mkdir(path)
331 | os.mkdir(os.path.join(path, 'EGG-INFO'))
332 | pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
333 | f = open(pkg_info, 'w')
334 | try:
335 | f.write(SETUPTOOLS_PKG_INFO)
336 | finally:
337 | f.close()
338 | return True
339 |
340 |
341 | def _before_install():
342 | log.warn('Before install bootstrap.')
343 | _fake_setuptools()
344 |
345 |
346 | def _under_prefix(location):
347 | if 'install' not in sys.argv:
348 | return True
349 | args = sys.argv[sys.argv.index('install')+1:]
350 | for index, arg in enumerate(args):
351 | for option in ('--root', '--prefix'):
352 | if arg.startswith('%s=' % option):
353 | top_dir = arg.split('root=')[-1]
354 | return location.startswith(top_dir)
355 | elif arg == option:
356 | if len(args) > index:
357 | top_dir = args[index+1]
358 | return location.startswith(top_dir)
359 | elif option == '--user' and USER_SITE is not None:
360 | return location.startswith(USER_SITE)
361 | return True
362 |
363 |
364 | def _fake_setuptools():
365 | log.warn('Scanning installed packages')
366 | try:
367 | import pkg_resources
368 | except ImportError:
369 | # we're cool
370 | log.warn('Setuptools or Distribute does not seem to be installed.')
371 | return
372 | ws = pkg_resources.working_set
373 | try:
374 | setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools',
375 | replacement=False))
376 | except TypeError:
377 | # old distribute API
378 | setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools'))
379 |
380 | if setuptools_dist is None:
381 | log.warn('No setuptools distribution found')
382 | return
383 | # detecting if it was already faked
384 | setuptools_location = setuptools_dist.location
385 | log.warn('Setuptools installation detected at %s', setuptools_location)
386 |
387 | # if --root or --preix was provided, and if
388 | # setuptools is not located in them, we don't patch it
389 | if not _under_prefix(setuptools_location):
390 | log.warn('Not patching, --root or --prefix is installing Distribute'
391 | ' in another location')
392 | return
393 |
394 | # let's see if its an egg
395 | if not setuptools_location.endswith('.egg'):
396 | log.warn('Non-egg installation')
397 | res = _remove_flat_installation(setuptools_location)
398 | if not res:
399 | return
400 | else:
401 | log.warn('Egg installation')
402 | pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
403 | if (os.path.exists(pkg_info) and
404 | _same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
405 | log.warn('Already patched.')
406 | return
407 | log.warn('Patching...')
408 | # let's create a fake egg replacing setuptools one
409 | res = _patch_egg_dir(setuptools_location)
410 | if not res:
411 | return
412 | log.warn('Patched done.')
413 | _relaunch()
414 |
415 |
416 | def _relaunch():
417 | log.warn('Relaunching...')
418 | # we have to relaunch the process
419 | args = [sys.executable] + sys.argv
420 | sys.exit(subprocess.call(args))
421 |
422 |
423 | def _extractall(self, path=".", members=None):
424 | """Extract all members from the archive to the current working
425 | directory and set owner, modification time and permissions on
426 | directories afterwards. `path' specifies a different directory
427 | to extract to. `members' is optional and must be a subset of the
428 | list returned by getmembers().
429 | """
430 | import copy
431 | import operator
432 | from tarfile import ExtractError
433 | directories = []
434 |
435 | if members is None:
436 | members = self
437 |
438 | for tarinfo in members:
439 | if tarinfo.isdir():
440 | # Extract directories with a safe mode.
441 | directories.append(tarinfo)
442 | tarinfo = copy.copy(tarinfo)
443 | tarinfo.mode = 448 # decimal for oct 0700
444 | self.extract(tarinfo, path)
445 |
446 | # Reverse sort directories.
447 | if sys.version_info < (2, 4):
448 | def sorter(dir1, dir2):
449 | return cmp(dir1.name, dir2.name)
450 | directories.sort(sorter)
451 | directories.reverse()
452 | else:
453 | directories.sort(key=operator.attrgetter('name'), reverse=True)
454 |
455 | # Set correct owner, mtime and filemode on directories.
456 | for tarinfo in directories:
457 | dirpath = os.path.join(path, tarinfo.name)
458 | try:
459 | self.chown(tarinfo, dirpath)
460 | self.utime(tarinfo, dirpath)
461 | self.chmod(tarinfo, dirpath)
462 | except ExtractError:
463 | e = sys.exc_info()[1]
464 | if self.errorlevel > 1:
465 | raise
466 | else:
467 | self._dbg(1, "tarfile: %s" % e)
468 |
469 |
470 | def main(argv, version=DEFAULT_VERSION):
471 | """Install or upgrade setuptools and EasyInstall"""
472 | tarball = download_setuptools()
473 | _install(tarball)
474 |
475 |
476 | if __name__ == '__main__':
477 | main(sys.argv[1:])
478 |
--------------------------------------------------------------------------------
/test/example/media/js/jquery.form.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery Form Plugin
3 | * version: 2.36 (07-NOV-2009)
4 | * @requires jQuery v1.2.6 or later
5 | *
6 | * Examples and documentation at: http://malsup.com/jquery/form/
7 | * Dual licensed under the MIT and GPL licenses:
8 | * http://www.opensource.org/licenses/mit-license.php
9 | * http://www.gnu.org/licenses/gpl.html
10 | */
11 | ;(function($) {
12 |
13 | /*
14 | Usage Note:
15 | -----------
16 | Do not use both ajaxSubmit and ajaxForm on the same form. These
17 | functions are intended to be exclusive. Use ajaxSubmit if you want
18 | to bind your own submit handler to the form. For example,
19 |
20 | $(document).ready(function() {
21 | $('#myForm').bind('submit', function() {
22 | $(this).ajaxSubmit({
23 | target: '#output'
24 | });
25 | return false; // <-- important!
26 | });
27 | });
28 |
29 | Use ajaxForm when you want the plugin to manage all the event binding
30 | for you. For example,
31 |
32 | $(document).ready(function() {
33 | $('#myForm').ajaxForm({
34 | target: '#output'
35 | });
36 | });
37 |
38 | When using ajaxForm, the ajaxSubmit function will be invoked for you
39 | at the appropriate time.
40 | */
41 |
42 | /**
43 | * ajaxSubmit() provides a mechanism for immediately submitting
44 | * an HTML form using AJAX.
45 | */
46 | $.fn.ajaxSubmit = function(options) {
47 | // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
48 | if (!this.length) {
49 | log('ajaxSubmit: skipping submit process - no element selected');
50 | return this;
51 | }
52 |
53 | if (typeof options == 'function')
54 | options = { success: options };
55 |
56 | var url = $.trim(this.attr('action'));
57 | if (url) {
58 | // clean url (don't include hash vaue)
59 | url = (url.match(/^([^#]+)/)||[])[1];
60 | }
61 | url = url || window.location.href || '';
62 |
63 | options = $.extend({
64 | url: url,
65 | type: this.attr('method') || 'GET',
66 | iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
67 | }, options || {});
68 |
69 | // hook for manipulating the form data before it is extracted;
70 | // convenient for use with rich editors like tinyMCE or FCKEditor
71 | var veto = {};
72 | this.trigger('form-pre-serialize', [this, options, veto]);
73 | if (veto.veto) {
74 | log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
75 | return this;
76 | }
77 |
78 | // provide opportunity to alter form data before it is serialized
79 | if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
80 | log('ajaxSubmit: submit aborted via beforeSerialize callback');
81 | return this;
82 | }
83 |
84 | var a = this.formToArray(options.semantic);
85 | if (options.data) {
86 | options.extraData = options.data;
87 | for (var n in options.data) {
88 | if(options.data[n] instanceof Array) {
89 | for (var k in options.data[n])
90 | a.push( { name: n, value: options.data[n][k] } );
91 | }
92 | else
93 | a.push( { name: n, value: options.data[n] } );
94 | }
95 | }
96 |
97 | // give pre-submit callback an opportunity to abort the submit
98 | if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
99 | log('ajaxSubmit: submit aborted via beforeSubmit callback');
100 | return this;
101 | }
102 |
103 | // fire vetoable 'validate' event
104 | this.trigger('form-submit-validate', [a, this, options, veto]);
105 | if (veto.veto) {
106 | log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
107 | return this;
108 | }
109 |
110 | var q = $.param(a);
111 |
112 | if (options.type.toUpperCase() == 'GET') {
113 | options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
114 | options.data = null; // data is null for 'get'
115 | }
116 | else
117 | options.data = q; // data is the query string for 'post'
118 |
119 | var $form = this, callbacks = [];
120 | if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
121 | if (options.clearForm) callbacks.push(function() { $form.clearForm(); });
122 |
123 | // perform a load on the target only if dataType is not provided
124 | if (!options.dataType && options.target) {
125 | var oldSuccess = options.success || function(){};
126 | callbacks.push(function(data) {
127 | $(options.target).html(data).each(oldSuccess, arguments);
128 | });
129 | }
130 | else if (options.success)
131 | callbacks.push(options.success);
132 |
133 | options.success = function(data, status) {
134 | for (var i=0, max=callbacks.length; i < max; i++)
135 | callbacks[i].apply(options, [data, status, $form]);
136 | };
137 |
138 | // are there files to upload?
139 | var files = $('input:file', this).fieldValue();
140 | var found = false;
141 | for (var j=0; j < files.length; j++)
142 | if (files[j])
143 | found = true;
144 |
145 | var multipart = false;
146 | // var mp = 'multipart/form-data';
147 | // multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
148 |
149 | // options.iframe allows user to force iframe mode
150 | // 06-NOV-09: now defaulting to iframe mode if file input is detected
151 | if ((files.length && options.iframe !== false) || options.iframe || found || multipart) {
152 | // hack to fix Safari hang (thanks to Tim Molendijk for this)
153 | // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
154 | if (options.closeKeepAlive)
155 | $.get(options.closeKeepAlive, fileUpload);
156 | else
157 | fileUpload();
158 | }
159 | else
160 | $.ajax(options);
161 |
162 | // fire 'notify' event
163 | this.trigger('form-submit-notify', [this, options]);
164 | return this;
165 |
166 |
167 | // private function for handling file uploads (hat tip to YAHOO!)
168 | function fileUpload() {
169 | var form = $form[0];
170 |
171 | if ($(':input[name=submit]', form).length) {
172 | alert('Error: Form elements must not be named "submit".');
173 | return;
174 | }
175 |
176 | var opts = $.extend({}, $.ajaxSettings, options);
177 | var s = $.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts);
178 |
179 | var id = 'jqFormIO' + (new Date().getTime());
180 | var $io = $('');
181 | var io = $io[0];
182 |
183 | $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
184 |
185 | var xhr = { // mock object
186 | aborted: 0,
187 | responseText: null,
188 | responseXML: null,
189 | status: 0,
190 | statusText: 'n/a',
191 | getAllResponseHeaders: function() {},
192 | getResponseHeader: function() {},
193 | setRequestHeader: function() {},
194 | abort: function() {
195 | this.aborted = 1;
196 | $io.attr('src', opts.iframeSrc); // abort op in progress
197 | }
198 | };
199 |
200 | var g = opts.global;
201 | // trigger ajax global events so that activity/block indicators work like normal
202 | if (g && ! $.active++) $.event.trigger("ajaxStart");
203 | if (g) $.event.trigger("ajaxSend", [xhr, opts]);
204 |
205 | if (s.beforeSend && s.beforeSend(xhr, s) === false) {
206 | s.global && $.active--;
207 | return;
208 | }
209 | if (xhr.aborted)
210 | return;
211 |
212 | var cbInvoked = 0;
213 | var timedOut = 0;
214 |
215 | // add submitting element to data if we know it
216 | var sub = form.clk;
217 | if (sub) {
218 | var n = sub.name;
219 | if (n && !sub.disabled) {
220 | options.extraData = options.extraData || {};
221 | options.extraData[n] = sub.value;
222 | if (sub.type == "image") {
223 | options.extraData[name+'.x'] = form.clk_x;
224 | options.extraData[name+'.y'] = form.clk_y;
225 | }
226 | }
227 | }
228 |
229 | // take a breath so that pending repaints get some cpu time before the upload starts
230 | setTimeout(function() {
231 | // make sure form attrs are set
232 | var t = $form.attr('target'), a = $form.attr('action');
233 |
234 | // update form attrs in IE friendly way
235 | form.setAttribute('target',id);
236 | if (form.getAttribute('method') != 'POST')
237 | form.setAttribute('method', 'POST');
238 | if (form.getAttribute('action') != opts.url)
239 | form.setAttribute('action', opts.url);
240 |
241 | // ie borks in some cases when setting encoding
242 | if (! options.skipEncodingOverride) {
243 | $form.attr({
244 | encoding: 'multipart/form-data',
245 | enctype: 'multipart/form-data'
246 | });
247 | }
248 |
249 | // support timout
250 | if (opts.timeout)
251 | setTimeout(function() { timedOut = true; cb(); }, opts.timeout);
252 |
253 | // add "extra" data to form if provided in options
254 | var extraInputs = [];
255 | try {
256 | if (options.extraData)
257 | for (var n in options.extraData)
258 | extraInputs.push(
259 | $('')
260 | .appendTo(form)[0]);
261 |
262 | // add iframe to doc and submit the form
263 | $io.appendTo('body');
264 | io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
265 | form.submit();
266 | }
267 | finally {
268 | // reset attrs and remove "extra" input elements
269 | form.setAttribute('action',a);
270 | t ? form.setAttribute('target', t) : $form.removeAttr('target');
271 | $(extraInputs).remove();
272 | }
273 | }, 10);
274 |
275 | var domCheckCount = 50;
276 |
277 | function cb() {
278 | if (cbInvoked++) return;
279 |
280 | io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
281 |
282 | var ok = true;
283 | try {
284 | if (timedOut) throw 'timeout';
285 | // extract the server response from the iframe
286 | var data, doc;
287 |
288 | doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
289 |
290 | var isXml = opts.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
291 | log('isXml='+isXml);
292 | if (!isXml && (doc.body == null || doc.body.innerHTML == '')) {
293 | if (--domCheckCount) {
294 | // in some browsers (Opera) the iframe DOM is not always traversable when
295 | // the onload callback fires, so we loop a bit to accommodate
296 | cbInvoked = 0;
297 | setTimeout(cb, 100);
298 | return;
299 | }
300 | log('Could not access iframe DOM after 50 tries.');
301 | return;
302 | }
303 |
304 | xhr.responseText = doc.body ? doc.body.innerHTML : null;
305 | xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
306 | xhr.getResponseHeader = function(header){
307 | var headers = {'content-type': opts.dataType};
308 | return headers[header];
309 | };
310 |
311 | if (opts.dataType == 'json' || opts.dataType == 'script') {
312 | // see if user embedded response in textarea
313 | var ta = doc.getElementsByTagName('textarea')[0];
314 | if (ta)
315 | xhr.responseText = ta.value;
316 | else {
317 | // account for browsers injecting pre around json response
318 | var pre = doc.getElementsByTagName('pre')[0];
319 | if (pre)
320 | xhr.responseText = pre.innerHTML;
321 | }
322 | }
323 | else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
324 | xhr.responseXML = toXml(xhr.responseText);
325 | }
326 | data = $.httpData(xhr, opts.dataType);
327 | }
328 | catch(e){
329 | ok = false;
330 | $.handleError(opts, xhr, 'error', e);
331 | }
332 |
333 | // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
334 | if (ok) {
335 | opts.success(data, 'success');
336 | if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
337 | }
338 | if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
339 | if (g && ! --$.active) $.event.trigger("ajaxStop");
340 | if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');
341 |
342 | // clean up
343 | setTimeout(function() {
344 | $io.remove();
345 | xhr.responseXML = null;
346 | }, 100);
347 | };
348 |
349 | function toXml(s, doc) {
350 | if (window.ActiveXObject) {
351 | doc = new ActiveXObject('Microsoft.XMLDOM');
352 | doc.async = 'false';
353 | doc.loadXML(s);
354 | }
355 | else
356 | doc = (new DOMParser()).parseFromString(s, 'text/xml');
357 | return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
358 | };
359 | };
360 | };
361 |
362 | /**
363 | * ajaxForm() provides a mechanism for fully automating form submission.
364 | *
365 | * The advantages of using this method instead of ajaxSubmit() are:
366 | *
367 | * 1: This method will include coordinates for elements (if the element
368 | * is used to submit the form).
369 | * 2. This method will include the submit element's name/value data (for the element that was
370 | * used to submit the form).
371 | * 3. This method binds the submit() method to the form for you.
372 | *
373 | * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
374 | * passes the options argument along after properly binding events for submit elements and
375 | * the form itself.
376 | */
377 | $.fn.ajaxForm = function(options) {
378 | return this.ajaxFormUnbind().bind('submit.form-plugin', function() {
379 | $(this).ajaxSubmit(options);
380 | return false;
381 | }).bind('click.form-plugin', function(e) {
382 | var target = e.target;
383 | var $el = $(target);
384 | if (!($el.is(":submit,input:image"))) {
385 | // is this a child element of the submit el? (ex: a span within a button)
386 | var t = $el.closest(':submit');
387 | if (t.length == 0)
388 | return;
389 | target = t[0];
390 | }
391 | var form = this;
392 | form.clk = target;
393 | if (target.type == 'image') {
394 | if (e.offsetX != undefined) {
395 | form.clk_x = e.offsetX;
396 | form.clk_y = e.offsetY;
397 | } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
398 | var offset = $el.offset();
399 | form.clk_x = e.pageX - offset.left;
400 | form.clk_y = e.pageY - offset.top;
401 | } else {
402 | form.clk_x = e.pageX - target.offsetLeft;
403 | form.clk_y = e.pageY - target.offsetTop;
404 | }
405 | }
406 | // clear form vars
407 | setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
408 | });
409 | };
410 |
411 | // ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
412 | $.fn.ajaxFormUnbind = function() {
413 | return this.unbind('submit.form-plugin click.form-plugin');
414 | };
415 |
416 | /**
417 | * formToArray() gathers form element data into an array of objects that can
418 | * be passed to any of the following ajax functions: $.get, $.post, or load.
419 | * Each object in the array has both a 'name' and 'value' property. An example of
420 | * an array for a simple login form might be:
421 | *
422 | * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
423 | *
424 | * It is this array that is passed to pre-submit callback functions provided to the
425 | * ajaxSubmit() and ajaxForm() methods.
426 | */
427 | $.fn.formToArray = function(semantic) {
428 | var a = [];
429 | if (this.length == 0) return a;
430 |
431 | var form = this[0];
432 | var els = semantic ? form.getElementsByTagName('*') : form.elements;
433 | if (!els) return a;
434 | for(var i=0, max=els.length; i < max; i++) {
435 | var el = els[i];
436 | var n = el.name;
437 | if (!n) continue;
438 |
439 | if (semantic && form.clk && el.type == "image") {
440 | // handle image inputs on the fly when semantic == true
441 | if(!el.disabled && form.clk == el) {
442 | a.push({name: n, value: $(el).val()});
443 | a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
444 | }
445 | continue;
446 | }
447 |
448 | var v = $.fieldValue(el, true);
449 | if (v && v.constructor == Array) {
450 | for(var j=0, jmax=v.length; j < jmax; j++)
451 | a.push({name: n, value: v[j]});
452 | }
453 | else if (v !== null && typeof v != 'undefined')
454 | a.push({name: n, value: v});
455 | }
456 |
457 | if (!semantic && form.clk) {
458 | // input type=='image' are not found in elements array! handle it here
459 | var $input = $(form.clk), input = $input[0], n = input.name;
460 | if (n && !input.disabled && input.type == 'image') {
461 | a.push({name: n, value: $input.val()});
462 | a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
463 | }
464 | }
465 | return a;
466 | };
467 |
468 | /**
469 | * Serializes form data into a 'submittable' string. This method will return a string
470 | * in the format: name1=value1&name2=value2
471 | */
472 | $.fn.formSerialize = function(semantic) {
473 | //hand off to jQuery.param for proper encoding
474 | return $.param(this.formToArray(semantic));
475 | };
476 |
477 | /**
478 | * Serializes all field elements in the jQuery object into a query string.
479 | * This method will return a string in the format: name1=value1&name2=value2
480 | */
481 | $.fn.fieldSerialize = function(successful) {
482 | var a = [];
483 | this.each(function() {
484 | var n = this.name;
485 | if (!n) return;
486 | var v = $.fieldValue(this, successful);
487 | if (v && v.constructor == Array) {
488 | for (var i=0,max=v.length; i < max; i++)
489 | a.push({name: n, value: v[i]});
490 | }
491 | else if (v !== null && typeof v != 'undefined')
492 | a.push({name: this.name, value: v});
493 | });
494 | //hand off to jQuery.param for proper encoding
495 | return $.param(a);
496 | };
497 |
498 | /**
499 | * Returns the value(s) of the element in the matched set. For example, consider the following form:
500 | *
501 | *
509 | *
510 | * var v = $(':text').fieldValue();
511 | * // if no values are entered into the text inputs
512 | * v == ['','']
513 | * // if values entered into the text inputs are 'foo' and 'bar'
514 | * v == ['foo','bar']
515 | *
516 | * var v = $(':checkbox').fieldValue();
517 | * // if neither checkbox is checked
518 | * v === undefined
519 | * // if both checkboxes are checked
520 | * v == ['B1', 'B2']
521 | *
522 | * var v = $(':radio').fieldValue();
523 | * // if neither radio is checked
524 | * v === undefined
525 | * // if first radio is checked
526 | * v == ['C1']
527 | *
528 | * The successful argument controls whether or not the field element must be 'successful'
529 | * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
530 | * The default value of the successful argument is true. If this value is false the value(s)
531 | * for each element is returned.
532 | *
533 | * Note: This method *always* returns an array. If no valid value can be determined the
534 | * array will be empty, otherwise it will contain one or more values.
535 | */
536 | $.fn.fieldValue = function(successful) {
537 | for (var val=[], i=0, max=this.length; i < max; i++) {
538 | var el = this[i];
539 | var v = $.fieldValue(el, successful);
540 | if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
541 | continue;
542 | v.constructor == Array ? $.merge(val, v) : val.push(v);
543 | }
544 | return val;
545 | };
546 |
547 | /**
548 | * Returns the value of the field element.
549 | */
550 | $.fieldValue = function(el, successful) {
551 | var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
552 | if (typeof successful == 'undefined') successful = true;
553 |
554 | if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
555 | (t == 'checkbox' || t == 'radio') && !el.checked ||
556 | (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
557 | tag == 'select' && el.selectedIndex == -1))
558 | return null;
559 |
560 | if (tag == 'select') {
561 | var index = el.selectedIndex;
562 | if (index < 0) return null;
563 | var a = [], ops = el.options;
564 | var one = (t == 'select-one');
565 | var max = (one ? index+1 : ops.length);
566 | for(var i=(one ? index : 0); i < max; i++) {
567 | var op = ops[i];
568 | if (op.selected) {
569 | var v = op.value;
570 | if (!v) // extra pain for IE...
571 | v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
572 | if (one) return v;
573 | a.push(v);
574 | }
575 | }
576 | return a;
577 | }
578 | return el.value;
579 | };
580 |
581 | /**
582 | * Clears the form data. Takes the following actions on the form's input fields:
583 | * - input text fields will have their 'value' property set to the empty string
584 | * - select elements will have their 'selectedIndex' property set to -1
585 | * - checkbox and radio inputs will have their 'checked' property set to false
586 | * - inputs of type submit, button, reset, and hidden will *not* be effected
587 | * - button elements will *not* be effected
588 | */
589 | $.fn.clearForm = function() {
590 | return this.each(function() {
591 | $('input,select,textarea', this).clearFields();
592 | });
593 | };
594 |
595 | /**
596 | * Clears the selected form elements.
597 | */
598 | $.fn.clearFields = $.fn.clearInputs = function() {
599 | return this.each(function() {
600 | var t = this.type, tag = this.tagName.toLowerCase();
601 | if (t == 'text' || t == 'password' || tag == 'textarea')
602 | this.value = '';
603 | else if (t == 'checkbox' || t == 'radio')
604 | this.checked = false;
605 | else if (tag == 'select')
606 | this.selectedIndex = -1;
607 | });
608 | };
609 |
610 | /**
611 | * Resets the form data. Causes all form elements to be reset to their original value.
612 | */
613 | $.fn.resetForm = function() {
614 | return this.each(function() {
615 | // guard against an input with the name of 'reset'
616 | // note that IE reports the reset function as an 'object'
617 | if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
618 | this.reset();
619 | });
620 | };
621 |
622 | /**
623 | * Enables or disables any matching elements.
624 | */
625 | $.fn.enable = function(b) {
626 | if (b == undefined) b = true;
627 | return this.each(function() {
628 | this.disabled = !b;
629 | });
630 | };
631 |
632 | /**
633 | * Checks/unchecks any matching checkboxes or radio buttons and
634 | * selects/deselects and matching option elements.
635 | */
636 | $.fn.selected = function(select) {
637 | if (select == undefined) select = true;
638 | return this.each(function() {
639 | var t = this.type;
640 | if (t == 'checkbox' || t == 'radio')
641 | this.checked = select;
642 | else if (this.tagName.toLowerCase() == 'option') {
643 | var $sel = $(this).parent('select');
644 | if (select && $sel[0] && $sel[0].type == 'select-one') {
645 | // deselect all other options
646 | $sel.find('option').selected(false);
647 | }
648 | this.selected = select;
649 | }
650 | });
651 | };
652 |
653 | // helper fn for console logging
654 | // set $.fn.ajaxSubmit.debug to true to enable debug logging
655 | function log() {
656 | if ($.fn.ajaxSubmit.debug && window.console && window.console.log)
657 | window.console.log('[jquery.form] ' + Array.prototype.join.call(arguments,''));
658 | };
659 |
660 | })(jQuery);
661 |
--------------------------------------------------------------------------------