├── .gitignore
├── MANIFEST.in
├── README.md
├── examples
├── bootswatch_example
│ ├── README.md
│ ├── bootswatch_example
│ │ ├── __init__.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ ├── views.py
│ │ └── wsgi.py
│ ├── manage.py
│ └── templates
│ │ └── home.html
└── simple_example
│ ├── README.md
│ ├── manage.py
│ ├── simple_example
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ ├── views.py
│ └── wsgi.py
│ ├── static
│ └── simple_example
│ │ └── css
│ │ ├── green.css
│ │ └── red.css
│ └── templates
│ └── home.html
├── requirements.txt
├── setup.py
└── themeswitch
├── __init__.py
├── context_processors.py
├── models.py
├── runtests
├── __init__.py
├── runcoverage.py
├── runtests.py
├── settings.py
└── urls.py
├── settings.py
├── templatetags
├── __init__.py
└── themeswitch_tags.py
├── tests.py
├── urls.py
└── views.py
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | /.idea/
3 |
4 | build/
5 | dist/
6 | *.egg-info/
7 | MANIFEST
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.md
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # django-themeswitch
2 |
3 | _django-themeswitch_ is a django app that allows users to easily switch between a set of predefined stylings.
4 |
5 | ## Usage
6 |
7 | To use _django-themeswitch_ update your `settings.py`:
8 |
9 | - add `themeswitch` to your `INSTALLED_APPS`
10 | - add 'themeswitch.context_processors.selected_theme' to your `TEMPLATE_CONTEXT_PROCESSORS`
11 |
12 | Then add an entry in your `urls.py` to include `themeswitch.urls`.
13 |
14 | In your templates after you `{% load themeswitch_tags %}` you have access to the template tags `{% get_available_themes as VARIABLENAME %}`
15 | and `{% render_selected_theme_css %}`. Place the `{% render_selected_theme_css %}` somewhere in your template's `
`.
16 |
17 | Now add an entry `THEMESWITCHER_THEMES` to your `settings.py`. `THEMESWITCHER_THEMES` should be a dictionary that contains mappings of `: `.
18 | The URLs must be absolute, but can exclude the host. Example:
19 |
20 | ```python
21 | THEMESWITCHER_THEMES = {
22 | 'green': '/static/green.css'
23 | }
24 | ```
25 |
26 | This would make `get_available_themes` return just one theme, named 'green'.
27 |
28 | Check out the [examples subdirectory](https://github.com/nschlemm/django-themeswitch/tree/master/examples).
29 |
30 | # License
31 |
32 | Copyright (c) 2013-2014, Nikolaus Schlemm
33 | All rights reserved.
34 |
35 | Redistribution and use in source and binary forms, with or without
36 | modification, are permitted provided that the following conditions are met:
37 |
38 | Redistributions of source code must retain the above copyright notice, this
39 | list of conditions and the following disclaimer.
40 | Redistributions in binary form must reproduce the above copyright notice, this
41 | list of conditions and the following disclaimer in the documentation and/or
42 | other materials provided with the distribution.
43 |
44 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
45 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
46 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
47 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
48 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
50 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
51 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
52 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
53 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54 |
--------------------------------------------------------------------------------
/examples/bootswatch_example/README.md:
--------------------------------------------------------------------------------
1 | # Simple Example
2 |
3 | A very basic django app that includes _django-themeswitch_ and shows how to switch between bootswatch themes.
--------------------------------------------------------------------------------
/examples/bootswatch_example/bootswatch_example/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nschlemm/django-themeswitch/371495b05abe14fddc2cabc9468f4fb2aedf77f7/examples/bootswatch_example/bootswatch_example/__init__.py
--------------------------------------------------------------------------------
/examples/bootswatch_example/bootswatch_example/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for bootswatch_example project.
3 |
4 | For more information on this file, see
5 | https://docs.djangoproject.com/en/1.6/topics/settings/
6 |
7 | For the full list of settings and their values, see
8 | https://docs.djangoproject.com/en/1.6/ref/settings/
9 | """
10 |
11 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
12 | import os
13 | BASE_DIR = os.path.dirname(os.path.dirname(__file__))
14 |
15 |
16 | # Quick-start development settings - unsuitable for production
17 | # See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/
18 |
19 | # SECURITY WARNING: keep the secret key used in production secret!
20 | SECRET_KEY = '=fbvn45kes+#g1y4=&)ks$1ftfu_5tnu!ed8s4e__)nu*2*6cc'
21 |
22 | # SECURITY WARNING: don't run with debug turned on in production!
23 | DEBUG = True
24 |
25 | TEMPLATE_DEBUG = True
26 |
27 | ALLOWED_HOSTS = []
28 |
29 |
30 | # Application definition
31 |
32 | INSTALLED_APPS = (
33 | 'django.contrib.admin',
34 | 'django.contrib.auth',
35 | 'django.contrib.contenttypes',
36 | 'django.contrib.sessions',
37 | 'django.contrib.messages',
38 | 'django.contrib.staticfiles',
39 |
40 | 'themeswitch'
41 | )
42 |
43 | TEMPLATE_DIRS = (
44 | os.path.join(BASE_DIR, 'templates'),
45 | )
46 |
47 | MIDDLEWARE_CLASSES = (
48 | 'django.contrib.sessions.middleware.SessionMiddleware',
49 | 'django.middleware.common.CommonMiddleware',
50 | 'django.middleware.csrf.CsrfViewMiddleware',
51 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
52 | 'django.contrib.messages.middleware.MessageMiddleware',
53 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
54 | )
55 |
56 | TEMPLATE_CONTEXT_PROCESSORS = (
57 | 'django.contrib.auth.context_processors.auth',
58 | 'django.core.context_processors.debug',
59 | 'django.core.context_processors.i18n',
60 | 'django.core.context_processors.media',
61 | 'django.core.context_processors.request',
62 | 'django.core.context_processors.static',
63 | 'django.core.context_processors.tz',
64 | 'django.contrib.messages.context_processors.messages',
65 | 'themeswitch.context_processors.selected_theme'
66 | )
67 |
68 | ROOT_URLCONF = 'bootswatch_example.urls'
69 |
70 | WSGI_APPLICATION = 'bootswatch_example.wsgi.application'
71 |
72 |
73 | # Database
74 | # https://docs.djangoproject.com/en/1.6/ref/settings/#databases
75 |
76 | DATABASES = {
77 | 'default': {
78 | 'ENGINE': 'django.db.backends.sqlite3',
79 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
80 | }
81 | }
82 |
83 | # Internationalization
84 | # https://docs.djangoproject.com/en/1.6/topics/i18n/
85 |
86 | LANGUAGE_CODE = 'en-us'
87 |
88 | TIME_ZONE = 'UTC'
89 |
90 | USE_I18N = True
91 |
92 | USE_L10N = True
93 |
94 | USE_TZ = True
95 |
96 |
97 | # Static files (CSS, JavaScript, Images)
98 | # https://docs.djangoproject.com/en/1.6/howto/static-files/
99 |
100 | STATIC_URL = '/static/'
101 |
102 |
103 | def _get_bootswatch_css_url(theme, bootstrap_version='3.1.1'):
104 | """
105 | A helper function to generate CDN URLs for bootswatch themes.
106 | """
107 | css_url = '//netdna.bootstrapcdn.com/bootswatch/%s/%s/bootstrap.min.css'
108 | return css_url % (bootstrap_version, theme)
109 |
110 |
111 | BOOTSWATCHES = (
112 | 'amelia',
113 | 'cerulean',
114 | 'cosmo',
115 | 'cyborg',
116 | 'darkly',
117 | 'flatly',
118 | 'journal',
119 | 'lumen',
120 | 'readable',
121 | 'shamrock',
122 | 'simplex',
123 | 'slate',
124 | 'spacelab',
125 | 'superhero',
126 | 'united',
127 | 'yeti',
128 | )
129 |
130 | BOOTSWATCH_THEMES = dict(
131 | (theme, _get_bootswatch_css_url(theme))
132 | for theme in BOOTSWATCHES
133 | )
134 |
135 | THEMESWITCHER_THEMES = dict(
136 | BOOTSWATCH_THEMES,
137 | )
138 |
--------------------------------------------------------------------------------
/examples/bootswatch_example/bootswatch_example/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import patterns, include, url
2 |
3 | urlpatterns = patterns(
4 | '',
5 | url(r'', include('themeswitch.urls')),
6 | url(r'^$', 'bootswatch_example.views.home', name='home'),
7 | )
8 |
--------------------------------------------------------------------------------
/examples/bootswatch_example/bootswatch_example/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render
2 |
3 |
4 | def home(request):
5 | return render(request, 'home.html')
6 |
--------------------------------------------------------------------------------
/examples/bootswatch_example/bootswatch_example/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for simple_example project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "bootswatch_example.settings")
12 |
13 | from django.core.wsgi import get_wsgi_application
14 | application = get_wsgi_application()
15 |
--------------------------------------------------------------------------------
/examples/bootswatch_example/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 | if __name__ == "__main__":
6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE",
7 | "bootswatch_example.settings")
8 |
9 | from django.core.management import execute_from_command_line
10 |
11 | execute_from_command_line(sys.argv)
12 |
--------------------------------------------------------------------------------
/examples/bootswatch_example/templates/home.html:
--------------------------------------------------------------------------------
1 |
2 | {% load themeswitch_tags %}
3 | {% get_available_themes as themes %}
4 |
5 |
6 | A bootswatch example
7 | {% render_selected_theme_css %}
8 |
17 |
18 |
19 |
20 |
Pick a Theme!
21 |
27 |
django-themeswitch is a simple way to allow users to style your content to their liking!
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/examples/simple_example/README.md:
--------------------------------------------------------------------------------
1 | # Simple Example
2 |
3 | A very basic django app that includes _django-themeswitch_ and shows how to switch between local themes.
--------------------------------------------------------------------------------
/examples/simple_example/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 | if __name__ == "__main__":
6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "simple_example.settings")
7 |
8 | from django.core.management import execute_from_command_line
9 |
10 | execute_from_command_line(sys.argv)
11 |
--------------------------------------------------------------------------------
/examples/simple_example/simple_example/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nschlemm/django-themeswitch/371495b05abe14fddc2cabc9468f4fb2aedf77f7/examples/simple_example/simple_example/__init__.py
--------------------------------------------------------------------------------
/examples/simple_example/simple_example/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for simple_example project.
3 |
4 | For more information on this file, see
5 | https://docs.djangoproject.com/en/1.6/topics/settings/
6 |
7 | For the full list of settings and their values, see
8 | https://docs.djangoproject.com/en/1.6/ref/settings/
9 | """
10 |
11 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
12 | import os
13 | BASE_DIR = os.path.dirname(os.path.dirname(__file__))
14 |
15 |
16 | # Quick-start development settings - unsuitable for production
17 | # See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/
18 |
19 | # SECURITY WARNING: keep the secret key used in production secret!
20 | SECRET_KEY = '=fbvn45kes+#g1y4=&)ks$1ftfu_5tnu!ed8s4e__)nu*2*6cc'
21 |
22 | # SECURITY WARNING: don't run with debug turned on in production!
23 | DEBUG = True
24 |
25 | TEMPLATE_DEBUG = True
26 |
27 | ALLOWED_HOSTS = []
28 |
29 |
30 | # Application definition
31 |
32 | INSTALLED_APPS = (
33 | 'django.contrib.admin',
34 | 'django.contrib.auth',
35 | 'django.contrib.contenttypes',
36 | 'django.contrib.sessions',
37 | 'django.contrib.messages',
38 | 'django.contrib.staticfiles',
39 |
40 | 'themeswitch'
41 | )
42 |
43 | TEMPLATE_DIRS = (
44 | os.path.join(BASE_DIR, 'templates'),
45 | )
46 |
47 | MIDDLEWARE_CLASSES = (
48 | 'django.contrib.sessions.middleware.SessionMiddleware',
49 | 'django.middleware.common.CommonMiddleware',
50 | 'django.middleware.csrf.CsrfViewMiddleware',
51 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
52 | 'django.contrib.messages.middleware.MessageMiddleware',
53 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
54 | )
55 |
56 | TEMPLATE_CONTEXT_PROCESSORS = (
57 | 'django.contrib.auth.context_processors.auth',
58 | 'django.core.context_processors.debug',
59 | 'django.core.context_processors.i18n',
60 | 'django.core.context_processors.media',
61 | 'django.core.context_processors.request',
62 | 'django.core.context_processors.static',
63 | 'django.core.context_processors.tz',
64 | 'django.contrib.messages.context_processors.messages',
65 |
66 | 'themeswitch.context_processors.selected_theme'
67 | )
68 |
69 | ROOT_URLCONF = 'simple_example.urls'
70 |
71 | WSGI_APPLICATION = 'simple_example.wsgi.application'
72 |
73 |
74 | # Database
75 | # https://docs.djangoproject.com/en/1.6/ref/settings/#databases
76 |
77 | DATABASES = {
78 | 'default': {
79 | 'ENGINE': 'django.db.backends.sqlite3',
80 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
81 | }
82 | }
83 |
84 | # Internationalization
85 | # https://docs.djangoproject.com/en/1.6/topics/i18n/
86 |
87 | LANGUAGE_CODE = 'en-us'
88 |
89 | TIME_ZONE = 'UTC'
90 |
91 | USE_I18N = True
92 |
93 | USE_L10N = True
94 |
95 | USE_TZ = True
96 |
97 |
98 | # Static files (CSS, JavaScript, Images)
99 | # https://docs.djangoproject.com/en/1.6/howto/static-files/
100 |
101 | STATIC_URL = '/static/'
102 |
103 | STATICFILES_DIRS = (
104 | os.path.join(BASE_DIR, 'static'),
105 | )
106 |
107 | THEMESWITCHER_THEMES = {
108 | 'red': '/static/simple_example/css/red.css',
109 | 'green': '/static/simple_example/css/green.css'
110 | }
111 |
--------------------------------------------------------------------------------
/examples/simple_example/simple_example/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf import settings
2 | from django.conf.urls import patterns, include, url
3 | from django.conf.urls.static import static
4 |
5 | urlpatterns = patterns(
6 | '',
7 | url(r'', include('themeswitch.urls')),
8 | url(r'^$', 'simple_example.views.home', name='home'),
9 | ) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
10 |
--------------------------------------------------------------------------------
/examples/simple_example/simple_example/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render
2 |
3 |
4 | def home(request):
5 | return render(request, 'home.html')
6 |
--------------------------------------------------------------------------------
/examples/simple_example/simple_example/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for simple_example project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "simple_example.settings")
12 |
13 | from django.core.wsgi import get_wsgi_application
14 | application = get_wsgi_application()
15 |
--------------------------------------------------------------------------------
/examples/simple_example/static/simple_example/css/green.css:
--------------------------------------------------------------------------------
1 | h1 {
2 | color: green;
3 | }
--------------------------------------------------------------------------------
/examples/simple_example/static/simple_example/css/red.css:
--------------------------------------------------------------------------------
1 | h1 {
2 | color: red;
3 | }
--------------------------------------------------------------------------------
/examples/simple_example/templates/home.html:
--------------------------------------------------------------------------------
1 |
2 | {% load themeswitch_tags %}
3 | {% get_available_themes as themes %}
4 |
5 |
6 | A very basic example
7 | {% render_selected_theme_css %}
8 |
17 |
18 |
19 |
20 |
Pick a Theme!
21 |
27 |
django-themeswitch is a simple way to allow users to style your content to their liking!
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Django
2 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import os
2 | import re
3 | from setuptools import setup
4 | import sys
5 |
6 |
7 | def get_packages(package):
8 | """
9 | Return root package and all sub-packages.
10 | """
11 | return [dirpath
12 | for dirpath, dirnames, filenames in os.walk(package)
13 | if os.path.exists(os.path.join(dirpath, '__init__.py'))]
14 |
15 |
16 | def get_package_data(package):
17 | """
18 | Return all files under the root package, that are not in a
19 | package themselves.
20 | """
21 | walk = [(dirpath.replace(package + os.sep, '', 1), filenames)
22 | for dirpath, dirnames, filenames in os.walk(package)
23 | if not os.path.exists(os.path.join(dirpath, '__init__.py'))]
24 |
25 | filepaths = []
26 | for base, filenames in walk:
27 | filepaths.extend([os.path.join(base, filename)
28 | for filename in filenames])
29 | return {package: filepaths}
30 |
31 |
32 | version = '0.3.1'
33 |
34 | README = open(os.path.join(os.path.dirname(__file__), 'README.md')).read()
35 |
36 | # allow setup.py to be run from any path
37 | os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir)))
38 |
39 |
40 | if sys.argv[-1] == 'publish':
41 | os.system("python setup.py sdist upload")
42 | # os.system("python setup.py bdist_wheel upload")
43 | print("You probably want to also tag the version now:")
44 | print(" git tag -a %s -m 'version %s'" % (version, version))
45 | print(" git push --tags")
46 | sys.exit()
47 |
48 | setup(
49 | name='django-themeswitch',
50 | version=version,
51 | packages=get_packages('themeswitch'),
52 | package_data=get_package_data('themeswitch'),
53 | test_suite='themeswitch.runtests.runtests.main',
54 | license='BSD License',
55 | description='a django app that allows for easy switch between themes',
56 | long_description=README,
57 | url='https://github.com/nschlemm/django-themeswitch',
58 | author='Nikolaus Schlemm',
59 | author_email='capo@coder-nostra.org',
60 | classifiers=[
61 | 'Environment :: Web Environment',
62 | 'Framework :: Django',
63 | 'Intended Audience :: Developers',
64 | 'License :: OSI Approved :: BSD License',
65 | 'Operating System :: OS Independent',
66 | 'Programming Language :: Python',
67 | 'Programming Language :: Python :: 2.6',
68 | 'Programming Language :: Python :: 2.7',
69 | 'Topic :: Internet :: WWW/HTTP',
70 | 'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
71 | ],
72 | )
73 |
--------------------------------------------------------------------------------
/themeswitch/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nschlemm/django-themeswitch/371495b05abe14fddc2cabc9468f4fb2aedf77f7/themeswitch/__init__.py
--------------------------------------------------------------------------------
/themeswitch/context_processors.py:
--------------------------------------------------------------------------------
1 | from django.core.exceptions import ImproperlyConfigured
2 |
3 | from .settings import DEFAULT_THEME, THEMES
4 |
5 |
6 | def selected_theme(request):
7 | theme = request.COOKIES.get('selected_theme', DEFAULT_THEME)
8 | if theme not in THEMES:
9 | theme = DEFAULT_THEME
10 |
11 | return {'selected_theme': theme}
12 |
--------------------------------------------------------------------------------
/themeswitch/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | # Create your models here.
4 |
--------------------------------------------------------------------------------
/themeswitch/runtests/__init__.py:
--------------------------------------------------------------------------------
1 | __author__ = 'nschlemm'
2 |
--------------------------------------------------------------------------------
/themeswitch/runtests/runcoverage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """
3 | Useful tool to run the test suite for rest_framework and generate a coverage
4 | report.
5 | """
6 |
7 | # http://ericholscher.com/blog/2009/jun/29/enable-setuppy-test-your-django-apps/
8 | # http://www.travisswicegood.com/2010/01/17/django-virtualenv-pip-and-fabric/
9 | # http://code.djangoproject.com/svn/django/trunk/tests/runtests.py
10 | # https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/runtests/runcoverage.py
11 | import os
12 | import sys
13 |
14 | # fix sys path so we don't need to setup PYTHONPATH
15 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../.."))
16 | os.environ['DJANGO_SETTINGS_MODULE'] = 'themeswitch.runtests.settings'
17 |
18 | from coverage import coverage
19 |
20 |
21 | def main():
22 | """Run the tests for themeswitch and generate a coverage report."""
23 |
24 | cov = coverage()
25 | cov.erase()
26 | cov.start()
27 |
28 | from django.conf import settings
29 | from django.test.utils import get_runner
30 | TestRunner = get_runner(settings)
31 |
32 | if hasattr(TestRunner, 'func_name'):
33 | # Pre 1.2 test runners were just functions,
34 | # and did not support the 'failfast' option.
35 | import warnings
36 | warnings.warn(
37 | 'Function-based test runners are deprecated. Test runners should '
38 | 'be classes with a run_tests() method.',
39 | DeprecationWarning
40 | )
41 | failures = TestRunner(['tests'])
42 | else:
43 | test_runner = TestRunner()
44 | failures = test_runner.run_tests(['themeswitch.tests'])
45 | cov.stop()
46 |
47 | # Discover the list of all modules that we should test coverage for
48 | import themeswitch
49 |
50 | project_dir = os.path.dirname(themeswitch.__file__)
51 | cov_files = []
52 |
53 | for (path, dirs, files) in os.walk(project_dir):
54 | # Drop tests and runtests directories from the test coverage report
55 | if os.path.basename(path) in ['tests', 'runtests', 'migrations']:
56 | continue
57 |
58 | # Drop the compat and six modules from coverage, since we're not
59 | # interested in the coverage of modules which are specifically for
60 | # resolving environment dependant imports. (Because we'll end up
61 | # getting different coverage reports for it for each environment)
62 | if 'compat.py' in files:
63 | files.remove('compat.py')
64 |
65 | if 'six.py' in files:
66 | files.remove('six.py')
67 |
68 | # Same applies to template tags module.
69 | # This module has to include branching on Django versions,
70 | # so it's never possible for it to have full coverage.
71 | if 'themeswitch_tags.py' in files:
72 | files.remove('themeswitch_tags.py')
73 |
74 | cov_files.extend([os.path.join(path, file)
75 | for file in files if file.endswith('.py')])
76 |
77 | cov.report(cov_files)
78 | if '--html' in sys.argv:
79 | cov.html_report(cov_files, directory='coverage')
80 | sys.exit(failures)
81 |
82 | if __name__ == '__main__':
83 | main()
84 |
--------------------------------------------------------------------------------
/themeswitch/runtests/runtests.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # http://ericholscher.com/blog/2009/jun/29/enable-setuppy-test-your-django-apps/
4 | # http://www.travisswicegood.com/2010/01/17/django-virtualenv-pip-and-fabric/
5 | # http://code.djangoproject.com/svn/django/trunk/tests/runtests.py
6 | # https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/runtests/runtests.py
7 | import os
8 | import sys
9 |
10 | # fix sys path so we don't need to setup PYTHONPATH
11 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../.."))
12 | os.environ['DJANGO_SETTINGS_MODULE'] = 'themeswitch.runtests.settings'
13 |
14 | import django
15 | from django.conf import settings
16 | from django.test.utils import get_runner
17 |
18 |
19 | def usage():
20 | return """
21 | Usage: python runtests.py [UnitTestClass].[method]
22 |
23 | You can pass the Class name of the `UnitTestClass` you want to test.
24 |
25 | Append a method name if you only want to test a specific method of that
26 | class.
27 | """
28 |
29 |
30 | def main():
31 | try:
32 | django.setup()
33 | except AttributeError:
34 | pass
35 | TestRunner = get_runner(settings)
36 |
37 | test_runner = TestRunner()
38 | if len(sys.argv) == 2:
39 | test_case = '.' + sys.argv[1]
40 | elif len(sys.argv) == 1:
41 | test_case = ''
42 | else:
43 | print(usage())
44 | sys.exit(1)
45 | test_module_name = 'themeswitch.tests'
46 | if django.VERSION[0] == 1 and django.VERSION[1] < 6:
47 | test_module_name = 'tests'
48 |
49 | failures = test_runner.run_tests([test_module_name + test_case])
50 |
51 | sys.exit(failures)
52 |
53 | if __name__ == '__main__':
54 | main()
55 |
--------------------------------------------------------------------------------
/themeswitch/runtests/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for runtests project.
3 |
4 | For more information on this file, see
5 | https://docs.djangoproject.com/en/1.6/topics/settings/
6 |
7 | For the full list of settings and their values, see
8 | https://docs.djangoproject.com/en/1.6/ref/settings/
9 | """
10 |
11 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
12 | import os
13 | BASE_DIR = os.path.dirname(os.path.dirname(__file__))
14 |
15 |
16 | # Quick-start development settings - unsuitable for production
17 | # See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/
18 |
19 | # SECURITY WARNING: keep the secret key used in production secret!
20 | SECRET_KEY = '@_sb=hk_qqburc))z!dbd59ia9_ev$7_qjz2fw4vp+xo6)=fud'
21 |
22 | # SECURITY WARNING: don't run with debug turned on in production!
23 | DEBUG = True
24 |
25 | TEMPLATE_DEBUG = True
26 |
27 | ALLOWED_HOSTS = []
28 |
29 |
30 | # Application definition
31 |
32 | INSTALLED_APPS = (
33 | 'django.contrib.auth',
34 | 'django.contrib.contenttypes',
35 | 'django.contrib.sessions',
36 | 'django.contrib.messages',
37 |
38 | 'themeswitch',
39 | )
40 |
41 | MIDDLEWARE_CLASSES = (
42 | 'django.contrib.sessions.middleware.SessionMiddleware',
43 | 'django.middleware.common.CommonMiddleware',
44 | 'django.middleware.csrf.CsrfViewMiddleware',
45 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
46 | 'django.contrib.messages.middleware.MessageMiddleware',
47 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
48 | )
49 |
50 | ROOT_URLCONF = 'urls'
51 |
52 | # Database
53 | # https://docs.djangoproject.com/en/1.6/ref/settings/#databases
54 |
55 | DATABASES = {
56 | 'default': {
57 | 'ENGINE': 'django.db.backends.sqlite3',
58 | 'NAME': ':memory:', # os.path.join(BASE_DIR, 'db.sqlite3'),
59 | }
60 | }
61 |
62 | # Internationalization
63 | # https://docs.djangoproject.com/en/1.6/topics/i18n/
64 |
65 | LANGUAGE_CODE = 'en-us'
66 |
67 | TIME_ZONE = 'UTC'
68 |
69 | USE_I18N = True
70 |
71 | USE_L10N = True
72 |
73 | USE_TZ = True
74 |
75 |
76 | # Static files (CSS, JavaScript, Images)
77 | # https://docs.djangoproject.com/en/1.6/howto/static-files/
78 |
79 | STATIC_URL = '/static/'
80 |
81 | THEMESWITCHER_DEFAULT_THEME = 'foo'
82 | THEMESWITCHER_THEMES = dict(foo='foo.css', bar='bar.css')
83 |
84 |
85 | # If we're running on the Jenkins server we want to archive the coverage
86 | # reports as XML.
87 | import os
88 | if os.environ.get('HUDSON_URL', None):
89 | TEST_RUNNER = 'xmlrunner.extra.djangotestrunner.XMLTestRunner'
90 | TEST_OUTPUT_VERBOSE = True
91 | TEST_OUTPUT_DESCRIPTIONS = True
92 | TEST_OUTPUT_DIR = 'xmlrunner'
93 |
--------------------------------------------------------------------------------
/themeswitch/runtests/urls.py:
--------------------------------------------------------------------------------
1 | """
2 | Blank URLConf just to keep runtests.py happy.
3 | """
4 | from rest_framework.compat import patterns
5 |
6 | urlpatterns = patterns('',)
7 |
--------------------------------------------------------------------------------
/themeswitch/settings.py:
--------------------------------------------------------------------------------
1 | from django.conf import settings
2 |
3 | DEFAULT_THEME = getattr(settings, 'THEMESWITCHER_DEFAULT_THEME', None)
4 | THEMES = getattr(settings, 'THEMESWITCHER_THEMES', dict())
5 |
--------------------------------------------------------------------------------
/themeswitch/templatetags/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nschlemm/django-themeswitch/371495b05abe14fddc2cabc9468f4fb2aedf77f7/themeswitch/templatetags/__init__.py
--------------------------------------------------------------------------------
/themeswitch/templatetags/themeswitch_tags.py:
--------------------------------------------------------------------------------
1 | from django.conf import settings
2 | from django.core.exceptions import ImproperlyConfigured
3 | from django.template.base import Library
4 |
5 | from themeswitch.settings import THEMES
6 |
7 |
8 | register = Library()
9 |
10 |
11 | @register.simple_tag(takes_context=True)
12 | def render_selected_theme_css(context):
13 | if 'selected_theme' not in context:
14 | context_processor = 'themeswitch.context_processors.selected_theme'
15 | if context_processor not in settings.TEMPLATE_CONTEXT_PROCESSORS:
16 | raise ImproperlyConfigured(
17 | 'Add %s to TEMPLATE_CONTEXT_PROCESSORS' % context_processor
18 | )
19 | selected_theme = context['selected_theme']
20 | if selected_theme and selected_theme in THEMES:
21 | return u'' % THEMES[selected_theme]
22 |
23 | return u''
24 |
25 |
26 | @register.assignment_tag()
27 | def get_available_themes():
28 | available_themes = THEMES.keys()
29 | available_themes.sort()
30 | return available_themes
31 |
--------------------------------------------------------------------------------
/themeswitch/tests.py:
--------------------------------------------------------------------------------
1 | """
2 | This file demonstrates writing tests using the unittest module. These will pass
3 | when you run "manage.py test".
4 |
5 | Replace this with more appropriate tests for your application.
6 | """
7 |
8 | from django.test import TestCase
9 | from django.test.client import RequestFactory
10 | from themeswitch.settings import THEMES
11 | from themeswitch.context_processors import selected_theme
12 |
13 |
14 | class ContextProcessorTest(TestCase):
15 | def setUp(self):
16 | self.factory = RequestFactory()
17 |
18 | def test_selected_theme(self):
19 | """
20 | Tests that "selected_theme" is added to context
21 | """
22 | request = self.factory.get('/')
23 | ctx = selected_theme(request)
24 | self.assertIn('selected_theme', ctx)
25 |
26 | self.assertNotIn('bogus', THEMES)
27 | self.factory.cookies['selected_theme'] = 'bogus'
28 | request = self.factory.get('/')
29 | ctx = selected_theme(request)
30 | self.assertIn('selected_theme', ctx)
31 | self.assertDictEqual(dict(selected_theme='foo'), ctx)
32 |
33 | self.assertIn('bar', THEMES)
34 | self.factory.cookies['selected_theme'] = 'bar'
35 | request = self.factory.get('/')
36 | ctx = selected_theme(request)
37 | self.assertDictEqual(dict(selected_theme='bar'), ctx)
38 |
--------------------------------------------------------------------------------
/themeswitch/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import patterns, url
2 |
3 | from .views import switch
4 |
5 | urlpatterns = patterns(
6 | '',
7 | url(r'^switch/$', switch, name='themeswitch-switch'),
8 | )
9 |
--------------------------------------------------------------------------------
/themeswitch/views.py:
--------------------------------------------------------------------------------
1 | from django.http import HttpResponseBadRequest, HttpResponseRedirect
2 |
3 | from .settings import THEMES
4 |
5 |
6 | def switch(request):
7 | if 'theme' not in request.GET:
8 | return HttpResponseBadRequest('No theme defined')
9 |
10 | theme = request.GET.get('theme')
11 | if theme and theme not in THEMES:
12 | return HttpResponseBadRequest('Unknown theme: "%s"' % theme)
13 |
14 | response = HttpResponseRedirect(
15 | request.GET.get('next', request.META.get('HTTP_REFERER', '/'), ))
16 | if theme:
17 | response.set_cookie('selected_theme', theme)
18 | else:
19 | response.delete_cookie('selected_theme')
20 | return response
21 |
--------------------------------------------------------------------------------