Compare commits

...

36 Commits

Author SHA1 Message Date
Fabio Caccamo bc9d200461 Added README.rst to MANIFEST.in 2017-09-27 14:47:42 +02:00
Fabio Caccamo 8c903d5f4c Updated version 2017-09-27 14:47:14 +02:00
Fabio Caccamo c253617346 Updated Python code to be PEP8 compliant 2017-09-27 14:47:03 +02:00
Fabio Caccamo 0fd8469d9a Updated version 2017-09-27 14:34:28 +02:00
Fabio Caccamo 5cce94eefc Added README.rst [ci skip] 2017-09-27 14:33:52 +02:00
Fabio Caccamo c4c6a2b0f2 Updated README.md [ci skip] 2017-09-11 11:48:57 +02:00
Fabio Caccamo 73a61080ae Added code-quality badge to README - [ci skip] 2017-09-04 17:19:12 +02:00
Fabio Caccamo 0164e5b791 Fixed fieldset collapse show/hide link style [ci skip] 2017-08-29 12:41:29 +02:00
Fabio Caccamo bb29c637ff Fixed tests error 2017-08-24 18:37:28 +02:00
Fabio Caccamo a8e9fffdac Increased coverage 2017-08-24 18:23:35 +02:00
Fabio Caccamo d81c7fcdd8 Updated version 2017-08-24 14:28:54 +02:00
Fabio Caccamo 4d07e9fec5 Added favicon support #28 2017-08-24 14:28:36 +02:00
Fabio Caccamo 3b982a84c3 Improved coverage 2017-08-24 14:27:34 +02:00
Fabio Caccamo 072fdcdc95 Fixed duplicated admin queries #19 2017-08-24 14:27:01 +02:00
Fabio Caccamo 07c38baa83 Updated version 2017-07-13 18:01:10 +02:00
Fabio Caccamo ed669a88be Fixed django 1.7 and django 1.9 compatibility 2017-07-13 18:00:56 +02:00
Fabio Caccamo 71ad991ba7 Fixed modals closing in older django versions. 2017-07-13 15:53:00 +02:00
Fabio Caccamo 05128a997e Added version parameter to prevent css/js caching. 2017-07-13 15:50:58 +02:00
Fabio Caccamo 92a816b9ae Updated README.md [ci skip] 2017-06-13 12:57:07 +02:00
Fabio Caccamo 4a9b6e5e5c Updated version 2017-06-13 11:45:28 +02:00
Fabio Caccamo 0e69ccdba6 Changed dependencies versions from strict to ranges 2017-06-13 11:45:17 +02:00
Fabio Caccamo 3f9dc0c58e Merge pull request #26 from 18F/uswds-theme
Add USWDS color scheme.
2017-06-13 10:38:12 +02:00
CM Lubinski cbd414485f Add USWDS color scheme.
As a first draft of a U.S. Web Design Standards theme, this selects uses
reasonable colors from its 508-compliant color pallet.
2017-06-12 17:48:42 -04:00
Fabio Caccamo ccb818043c Merge pull request #23 from 18F/bytes2unicode
Add migration to convert bytes to unicode.
2017-06-12 15:50:37 +02:00
Fabio Caccamo 07d4fd65ef Merge pull request #21 from 18F/future-safe
Specify a max_length on all ColorFields.
2017-06-12 15:49:44 +02:00
Fabio Caccamo 4dd7a9dd3d Merge pull request #20 from founders4schools/deprecation-warnings
Fix a Django deprecation warning
2017-06-12 11:42:05 +02:00
CM Lubinski 9ecaa3836c Add migration to convert bytes to unicode.
Python 2 and 3 treat strings differently; in 2 they are bytes and in 3 they
are unicode objects. The Theme fields' attributes were encoded as bytes in the
initial migration (0001) but should be unicode values, leading to a missing
migration whenever the code is ran on Python 3. This changeset "alters" all
the fields to set them to have unicode attributes rather than bytes.

For more context, we've more or less followed the steps outlined here:
https://docs.djangoproject.com/en/1.11/topics/migrations/#supporting-python-2-and-3
2017-06-09 11:41:15 -04:00
Bruno Alla 511ad909bf Run tests on Python 3.6 for Django 1.11+ 2017-06-09 16:27:13 +01:00
CM Lubinski 8fe6ffd3b2 Specify a max_length on all ColorFields.
Django-colorfield bumped up its default max_length from 10 to 18 characters in
bfe421b8. Though we've pinned the version of colorfields we're depending on,
we can make the future version upgrade easier now by locking our fields to
having a max length of 10 chars.
2017-06-09 11:26:46 -04:00
Bruno Alla d0f8d7514a Fix allow_failures 2017-06-09 15:56:05 +01:00
Bruno Alla 78d80bc129 Run tests against Django master 2017-06-09 15:49:54 +01:00
Bruno Alla 09bd082759 Fix the error on older versions of Django 2017-06-09 15:44:23 +01:00
Bruno Alla 70b4be757d Fix a Django deprecation warning
Replace deprecated assignment_tag:

`python/lib/python3.5/site-packages/admin_interface/templatetags/admin_interface_tags.py:11: RemovedInDjango20Warning: assignment_tag() is deprecated. Use simple_tag() instead`
2017-06-09 15:12:00 +01:00
Fabio Caccamo 486bfa9aba Updated version 2017-06-09 11:58:26 +02:00
Fabio Caccamo e19cd51803 Added per-request cache to get_admin_interface_theme template tag #19 2017-06-09 11:58:10 +02:00
Fabio Caccamo 2d8eeee425 Updated README [ci skip] 2017-05-24 12:46:42 +02:00
23 changed files with 734 additions and 121 deletions
+13 -4
View File
@@ -9,14 +9,23 @@ env:
- TOX_ENV=py34-18 - TOX_ENV=py34-18
- TOX_ENV=py34-19 - TOX_ENV=py34-19
- TOX_ENV=py34-110 - TOX_ENV=py34-110
- TOX_ENV=py34-master
- TOX_ENV=py35-18 - TOX_ENV=py35-18
- TOX_ENV=py35-19 - TOX_ENV=py35-19
- TOX_ENV=py35-110 - TOX_ENV=py35-110
#- TOX_ENV=py36-18 - TOX_ENV=py35-master
#- TOX_ENV=py36-19 matrix:
#- TOX_ENV=py36-110 include:
- python: "3.6"
env: TOX_ENV=py36-111
- python: "3.6"
env: TOX_ENV=py36-master
allow_failures:
- env: TOX_ENV=py34-master
- env: TOX_ENV=py35-master
- env: TOX_ENV=py36-master
install: install:
- pip install tox - pip install tox
script: script:
- tox -e $TOX_ENV - tox -e $TOX_ENV
sudo: false sudo: false
+1
View File
@@ -1,4 +1,5 @@
include LICENSE.txt include LICENSE.txt
include README.md include README.md
include README.rst
recursive-include admin_interface * recursive-include admin_interface *
recursive-exclude * *.pyc __pycache__ .DS_Store recursive-exclude * *.pyc __pycache__ .DS_Store
+34 -1
View File
@@ -1,5 +1,6 @@
[![Build Status](https://travis-ci.org/fabiocaccamo/django-admin-interface.svg?branch=master)](https://travis-ci.org/fabiocaccamo/django-admin-interface) [![Build Status](https://travis-ci.org/fabiocaccamo/django-admin-interface.svg?branch=master)](https://travis-ci.org/fabiocaccamo/django-admin-interface)
[![codecov](https://codecov.io/gh/fabiocaccamo/django-admin-interface/branch/master/graph/badge.svg)](https://codecov.io/gh/fabiocaccamo/django-admin-interface) [![codecov](https://codecov.io/gh/fabiocaccamo/django-admin-interface/branch/master/graph/badge.svg)](https://codecov.io/gh/fabiocaccamo/django-admin-interface)
[![Code Health](https://landscape.io/github/fabiocaccamo/django-admin-interface/master/landscape.svg?style=flat)](https://landscape.io/github/fabiocaccamo/django-admin-interface/master)
[![PyPI version](https://badge.fury.io/py/django-admin-interface.svg)](https://badge.fury.io/py/django-admin-interface) [![PyPI version](https://badge.fury.io/py/django-admin-interface.svg)](https://badge.fury.io/py/django-admin-interface)
[![Py versions](https://img.shields.io/pypi/pyversions/django-admin-interface.svg)](https://img.shields.io/pypi/pyversions/django-admin-interface.svg) [![Py versions](https://img.shields.io/pypi/pyversions/django-admin-interface.svg)](https://img.shields.io/pypi/pyversions/django-admin-interface.svg)
[![License](https://img.shields.io/pypi/l/django-admin-interface.svg)](https://img.shields.io/pypi/l/django-admin-interface.svg) [![License](https://img.shields.io/pypi/l/django-admin-interface.svg)](https://img.shields.io/pypi/l/django-admin-interface.svg)
@@ -27,7 +28,7 @@ INSTALLED_APPS = (
#... #...
'admin_interface', 'admin_interface',
'flat_responsive', 'flat_responsive',
'flat', #if django version < 1.9 'flat', # only if django version < 1.9
'colorfield', 'colorfield',
#... #...
'django.contrib.admin', 'django.contrib.admin',
@@ -44,6 +45,32 @@ INSTALLED_APPS = (
- Run ``python manage.py collectstatic --clear`` - Run ``python manage.py collectstatic --clear``
- Restart your application server - Restart your application server
## Optional themes
This package ships with optional themes as fixtures, they can be installed using the [loaddata admin command](https://docs.djangoproject.com/en/1.11/ref/django-admin/#django-admin-loaddata). Optional themes are activated on installation.
##### [Django](https://www.djangoproject.com/) theme (default):
Run ``python manage.py loaddata admin_interface_theme_django.json``
##### [Bootstrap](http://getbootstrap.com/) theme:
Run ``python manage.py loaddata admin_interface_theme_bootstrap.json``
##### [Foundation](http://foundation.zurb.com/) theme:
Run ``python manage.py loaddata admin_interface_theme_foundation.json``
##### [U.S. Web Design Standards](https://standards.usa.gov/) theme:
Run ``python manage.py loaddata admin_interface_theme_uswds.json``
### Add more themes
You can add a theme you've created through the admin to this repository by [sending us a PR](http://makeapullrequest.com/). Here are the steps to follow to add :
1. Export your exact theme as fixture using the `dumpdata` admin command:
``python manage.py dumpdata admin_interface.Theme --indent 4 -o admin_interface_theme_{{name}}.json --pks=N``
2. Copy the generated json file into the fixtures folder *(making sure its name starts with `admin_interface_theme_` to avoid clashes with fixtures that might be provided by other third party apps)*.
3. Remove the `"pk"` from the fixture and make sure the `active` field is set to `true` *(in this way a theme is automatically activated when installed)*.
4. Edit the section above to document your theme.
## Screenshots ## Screenshots
###### Admin login ###### Admin login
@@ -58,6 +85,12 @@ INSTALLED_APPS = (
###### Admin theme customization ###### Admin theme customization
![django-admin-interface_theme_customization](https://cloud.githubusercontent.com/assets/1035294/11240250/7350d942-8df1-11e5-9b28-f2f54c333cdc.gif) ![django-admin-interface_theme_customization](https://cloud.githubusercontent.com/assets/1035294/11240250/7350d942-8df1-11e5-9b28-f2f54c333cdc.gif)
## FAQ
- #### I already have a custom `base_site.html`, how can I make it work?
You can use [django-apptemplates](https://github.com/bittner/django-apptemplates), then add **`{% extends "admin_interface:admin/base_site.html" %}`** to your `base_site.html`
---
#### Thanks #### Thanks
- [django-flat-theme](https://github.com/elky/django-flat-theme/) - [django-flat-theme](https://github.com/elky/django-flat-theme/)
- [django-flat-responsive](https://github.com/elky/django-flat-responsive) - [django-flat-responsive](https://github.com/elky/django-flat-responsive)
+181
View File
@@ -0,0 +1,181 @@
|Build Status| |codecov| |Code Health| |PyPI version| |Py versions|
|License|
django-admin-interface
======================
django-admin-interface is a modern **responsive flat admin interface
customizable by the admin itself**.
Features
--------
- Beautiful default **django-theme**
- Themes management and customization *(you can **customize admin
title, logo and colors**)*
- Responsive
- List filter dropdown *(optional)*
- **``NEW``** **Related modal** *(instead of the old popup window,
optional)*
- Style optimizations for: ``django-ckeditor``,
``django-modeltranslation``, ``sorl-thumbnail``
Requirements
------------
- Python 2.7, 3.4, 3.5, 3.6
- Django 1.7, 1.8, 1.9, 1.10, 1.11
Installation
------------
- Run ``pip install django-admin-interface``
- Add ``admin_interface``, ``flat_responsive``, ``flat`` and
``colorfield`` to ``settings.INSTALLED_APPS`` **before**
``django.contrib.admin``
.. code:: python
INSTALLED_APPS = (
#...
'admin_interface',
'flat_responsive',
'flat', # only if django version < 1.9
'colorfield',
#...
'django.contrib.admin',
#...
)
- Run ``python manage.py migrate``
- Run ``python manage.py collectstatic``
- Restart your application server
Upgrade
~~~~~~~
- Run ``pip install django-admin-interface --upgrade``
- Run ``python manage.py migrate`` *(add ``--fake-initial`` if you are
upgrading from 0.1.0 version)*
- Run ``python manage.py collectstatic --clear``
- Restart your application server
Optional themes
---------------
This package ships with optional themes as fixtures, they can be
installed using the `loaddata admin
command <https://docs.djangoproject.com/en/1.11/ref/django-admin/#django-admin-loaddata>`__.
Optional themes are activated on installation.
`Django <https://www.djangoproject.com/>`__ theme (default):
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run ``python manage.py loaddata admin_interface_theme_django.json``
`Bootstrap <http://getbootstrap.com/>`__ theme:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run ``python manage.py loaddata admin_interface_theme_bootstrap.json``
`Foundation <http://foundation.zurb.com/>`__ theme:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run ``python manage.py loaddata admin_interface_theme_foundation.json``
`U.S. Web Design Standards <https://standards.usa.gov/>`__ theme:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run ``python manage.py loaddata admin_interface_theme_uswds.json``
Add more themes
~~~~~~~~~~~~~~~
You can add a theme you've created through the admin to this repository
by `sending us a PR <http://makeapullrequest.com/>`__. Here are the
steps to follow to add :
1. Export your exact theme as fixture using the ``dumpdata`` admin
command:
``python manage.py dumpdata admin_interface.Theme --indent 4 -o admin_interface_theme_{{name}}.json --pks=N``
2. Copy the generated json file into the fixtures folder *(making sure
its name starts with ``admin_interface_theme_`` to avoid clashes with
fixtures that might be provided by other third party apps)*.
3. Remove the ``"pk"`` from the fixture and make sure the ``active``
field is set to ``true`` *(in this way a theme is automatically
activated when installed)*.
4. Edit the section above to document your theme.
Screenshots
-----------
Admin login
~~~~~~~~~~~
|django-admin-interface\_login|
-------------------------------
Admin dashboard
~~~~~~~~~~~~~~~
|django-admin-interface\_dashboard|
-----------------------------------
Admin themes management
~~~~~~~~~~~~~~~~~~~~~~~
|django-admin-interface\_themes\_management|
--------------------------------------------
Admin theme customization
~~~~~~~~~~~~~~~~~~~~~~~~~
.. figure:: https://cloud.githubusercontent.com/assets/1035294/11240250/7350d942-8df1-11e5-9b28-f2f54c333cdc.gif
:alt: django-admin-interface\_theme\_customization
django-admin-interface\_theme\_customization
FAQ
---
- .. rubric:: I already have a custom ``base_site.html``, how can I
make it work?
:name: i-already-have-a-custom-base_site.html-how-can-i-make-it-work
You can use
`django-apptemplates <https://github.com/bittner/django-apptemplates>`__,
then add **``{% extends "admin_interface:admin/base_site.html" %}``** to
your ``base_site.html``
--------------
Thanks
~~~~~~
- `django-flat-theme <https://github.com/elky/django-flat-theme/>`__
- `django-flat-responsive <https://github.com/elky/django-flat-responsive>`__
- `django-colorfield <https://github.com/jaredly/django-colorfield/>`__
License
-------
Released under `MIT License <LICENSE>`__.
.. |Build Status| image:: https://travis-ci.org/fabiocaccamo/django-admin-interface.svg?branch=master
:target: https://travis-ci.org/fabiocaccamo/django-admin-interface
.. |codecov| image:: https://codecov.io/gh/fabiocaccamo/django-admin-interface/branch/master/graph/badge.svg
:target: https://codecov.io/gh/fabiocaccamo/django-admin-interface
.. |Code Health| image:: https://landscape.io/github/fabiocaccamo/django-admin-interface/master/landscape.svg?style=flat
:target: https://landscape.io/github/fabiocaccamo/django-admin-interface/master
.. |PyPI version| image:: https://badge.fury.io/py/django-admin-interface.svg
:target: https://badge.fury.io/py/django-admin-interface
.. |Py versions| image:: https://img.shields.io/pypi/pyversions/django-admin-interface.svg
:target: https://img.shields.io/pypi/pyversions/django-admin-interface.svg
.. |License| image:: https://img.shields.io/pypi/l/django-admin-interface.svg
:target: https://img.shields.io/pypi/l/django-admin-interface.svg
.. |django-admin-interface\_login| image:: https://cloud.githubusercontent.com/assets/1035294/11240233/55c8d4ba-8df1-11e5-9568-00fdc987ede8.gif
.. |django-admin-interface\_dashboard| image:: https://cloud.githubusercontent.com/assets/1035294/11240239/627c0362-8df1-11e5-81fa-216366a5d8da.gif
.. |django-admin-interface\_themes\_management| image:: https://cloud.githubusercontent.com/assets/1035294/11240245/6cd1c342-8df1-11e5-928b-f22217474d3d.gif
-1
View File
@@ -3,4 +3,3 @@
from admin_interface.version import __version__ from admin_interface.version import __version__
default_app_config = 'admin_interface.apps.AdminInterfaceConfig' default_app_config = 'admin_interface.apps.AdminInterfaceConfig'
+47 -9
View File
@@ -17,35 +17,74 @@ class ThemeAdmin(admin.ModelAdmin):
}), }),
('Logo', { ('Logo', {
'classes': ('wide', ), 'classes': ('wide', ),
'fields': ('logo', 'logo_color', 'logo_visible', ) 'fields': (
'logo',
'logo_color',
'logo_visible',
)
}),
('Favicon', {
'classes': ('wide', ),
'fields': ('favicon', )
}), }),
('Title', { ('Title', {
'classes': ('wide', ), 'classes': ('wide', ),
'fields': ('title', 'title_color', 'title_visible', ) 'fields': (
'title',
'title_color',
'title_visible',
)
}), }),
('Header', { ('Header', {
'classes': ('wide', ), 'classes': ('wide', ),
'fields': ('css_header_background_color', 'css_header_text_color', 'css_header_link_color', 'css_header_link_hover_color', ) 'fields': (
'css_header_background_color',
'css_header_text_color',
'css_header_link_color',
'css_header_link_hover_color',
)
}), }),
('Breadcrumbs / Module headers', { ('Breadcrumbs / Module headers', {
'classes': ('wide', ), 'classes': ('wide', ),
'fields': ('css_module_background_color', 'css_module_text_color', 'css_module_link_color', 'css_module_link_hover_color', 'css_module_rounded_corners', ) 'fields': (
'css_module_background_color',
'css_module_text_color',
'css_module_link_color',
'css_module_link_hover_color',
'css_module_rounded_corners',
)
}), }),
('Generic Links', { ('Generic Links', {
'classes': ('wide', ), 'classes': ('wide', ),
'fields': ('css_generic_link_color', 'css_generic_link_hover_color', ) 'fields': (
'css_generic_link_color',
'css_generic_link_hover_color',
)
}), }),
('Save Buttons', { ('Save Buttons', {
'classes': ('wide', ), 'classes': ('wide', ),
'fields': ('css_save_button_background_color', 'css_save_button_background_hover_color', 'css_save_button_text_color', ) 'fields': (
'css_save_button_background_color',
'css_save_button_background_hover_color',
'css_save_button_text_color',
)
}), }),
('Delete Buttons', { ('Delete Buttons', {
'classes': ('wide', ), 'classes': ('wide', ),
'fields': ('css_delete_button_background_color', 'css_delete_button_background_hover_color', 'css_delete_button_text_color', ) 'fields': (
'css_delete_button_background_color',
'css_delete_button_background_hover_color',
'css_delete_button_text_color',
)
}), }),
('Related Modal', { ('Related Modal', {
'classes': ('wide', ), 'classes': ('wide', ),
'fields': ('related_modal_active', 'related_modal_background_color', 'related_modal_background_opacity', 'related_modal_rounded_corners', ) 'fields': (
'related_modal_active',
'related_modal_background_color',
'related_modal_background_opacity',
'related_modal_rounded_corners',
)
}), }),
('List Filter', { ('List Filter', {
'classes': ('wide', ), 'classes': ('wide', ),
@@ -60,4 +99,3 @@ class ThemeAdmin(admin.ModelAdmin):
save_on_top = True save_on_top = True
admin.site.register(Theme, ThemeAdmin) admin.site.register(Theme, ThemeAdmin)
+2 -1
View File
@@ -12,5 +12,6 @@ class AdminInterfaceConfig(AppConfig):
def ready(self): def ready(self):
from admin_interface.models import Theme from admin_interface.models import Theme
post_migrate.connect(Theme.post_migrate_handler, sender = self)
post_migrate.connect(
Theme.post_migrate_handler, sender=self)
@@ -0,0 +1,39 @@
[
{
"model": "admin_interface.theme",
"fields": {
"name": "USWDS",
"active": true,
"title": "Site administration",
"title_color": "#FFFFFF",
"title_visible": true,
"logo": "",
"logo_color": "#FFFFFF",
"logo_visible": false,
"css_header_background_color": "#112E51",
"css_header_text_color": "#FFFFFF",
"css_header_link_color": "#FFFFFF",
"css_header_link_hover_color": "#E1F3F8",
"css_module_background_color": "#205493",
"css_module_text_color": "#FFFFFF",
"css_module_link_color": "#FFFFFF",
"css_module_link_hover_color": "#E1F3F8",
"css_module_rounded_corners": true,
"css_generic_link_color": "#205493",
"css_generic_link_hover_color": "#0071BC",
"css_save_button_background_color": "#205493",
"css_save_button_background_hover_color": "#112E51",
"css_save_button_text_color": "#FFFFFF",
"css_delete_button_background_color": "#CD2026",
"css_delete_button_background_hover_color": "#981B1E",
"css_delete_button_text_color": "#FFFFFF",
"css": "",
"related_modal_active": true,
"related_modal_background_color": "#000000",
"related_modal_background_opacity": 0.8,
"related_modal_rounded_corners": true,
"list_filter_dropdown": false,
"recent_actions_visible": true
}
}
]
@@ -0,0 +1,151 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.2 on 2017-06-09 14:52
from __future__ import unicode_literals
import colorfield.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('admin_interface', '0005_add_recent_actions_visible'),
]
operations = [
migrations.AlterField(
model_name='theme',
name='css_delete_button_background_color',
field=colorfield.fields.ColorField(blank=True, default='#BA2121', help_text='#BA2121', max_length=10, verbose_name='background color'),
),
migrations.AlterField(
model_name='theme',
name='css_delete_button_background_hover_color',
field=colorfield.fields.ColorField(blank=True, default='#A41515', help_text='#A41515', max_length=10, verbose_name='background hover color'),
),
migrations.AlterField(
model_name='theme',
name='css_delete_button_text_color',
field=colorfield.fields.ColorField(blank=True, default='#FFFFFF', help_text='#FFFFFF', max_length=10, verbose_name='text color'),
),
migrations.AlterField(
model_name='theme',
name='css_generic_link_color',
field=colorfield.fields.ColorField(blank=True, default='#0C3C26', help_text='#0C3C26', max_length=10, verbose_name='link color'),
),
migrations.AlterField(
model_name='theme',
name='css_generic_link_hover_color',
field=colorfield.fields.ColorField(blank=True, default='#156641', help_text='#156641', max_length=10, verbose_name='link hover color'),
),
migrations.AlterField(
model_name='theme',
name='css_header_background_color',
field=colorfield.fields.ColorField(blank=True, default='#0C4B33', help_text='#0C4B33', max_length=10, verbose_name='background color'),
),
migrations.AlterField(
model_name='theme',
name='css_header_link_color',
field=colorfield.fields.ColorField(blank=True, default='#FFFFFF', help_text='#FFFFFF', max_length=10, verbose_name='link color'),
),
migrations.AlterField(
model_name='theme',
name='css_header_link_hover_color',
field=colorfield.fields.ColorField(blank=True, default='#C9F0DD', help_text='#C9F0DD', max_length=10, verbose_name='link hover color'),
),
migrations.AlterField(
model_name='theme',
name='css_header_text_color',
field=colorfield.fields.ColorField(blank=True, default='#44B78B', help_text='#44B78B', max_length=10, verbose_name='text color'),
),
migrations.AlterField(
model_name='theme',
name='css_module_background_color',
field=colorfield.fields.ColorField(blank=True, default='#44B78B', help_text='#44B78B', max_length=10, verbose_name='background color'),
),
migrations.AlterField(
model_name='theme',
name='css_module_link_color',
field=colorfield.fields.ColorField(blank=True, default='#FFFFFF', help_text='#FFFFFF', max_length=10, verbose_name='link color'),
),
migrations.AlterField(
model_name='theme',
name='css_module_link_hover_color',
field=colorfield.fields.ColorField(blank=True, default='#C9F0DD', help_text='#C9F0DD', max_length=10, verbose_name='link hover color'),
),
migrations.AlterField(
model_name='theme',
name='css_module_rounded_corners',
field=models.BooleanField(default=True, verbose_name='rounded corners'),
),
migrations.AlterField(
model_name='theme',
name='css_module_text_color',
field=colorfield.fields.ColorField(blank=True, default='#FFFFFF', help_text='#FFFFFF', max_length=10, verbose_name='text color'),
),
migrations.AlterField(
model_name='theme',
name='css_save_button_background_color',
field=colorfield.fields.ColorField(blank=True, default='#0C4B33', help_text='#0C4B33', max_length=10, verbose_name='background color'),
),
migrations.AlterField(
model_name='theme',
name='css_save_button_background_hover_color',
field=colorfield.fields.ColorField(blank=True, default='#0C3C26', help_text='#0C3C26', max_length=10, verbose_name='background hover color'),
),
migrations.AlterField(
model_name='theme',
name='css_save_button_text_color',
field=colorfield.fields.ColorField(blank=True, default='#FFFFFF', help_text='#FFFFFF', max_length=10, verbose_name='text color'),
),
migrations.AlterField(
model_name='theme',
name='list_filter_dropdown',
field=models.BooleanField(default=False, verbose_name='use dropdown'),
),
migrations.AlterField(
model_name='theme',
name='logo_visible',
field=models.BooleanField(default=True, verbose_name='visible'),
),
migrations.AlterField(
model_name='theme',
name='name',
field=models.CharField(default='Django', max_length=50),
),
migrations.AlterField(
model_name='theme',
name='related_modal_active',
field=models.BooleanField(default=True, verbose_name='active'),
),
migrations.AlterField(
model_name='theme',
name='related_modal_background_color',
field=colorfield.fields.ColorField(blank=True, default='#000000', help_text='#000000', max_length=10, verbose_name='background color'),
),
migrations.AlterField(
model_name='theme',
name='related_modal_background_opacity',
field=models.FloatField(choices=[(0.1, '10%'), (0.2, '20%'), (0.3, '30%'), (0.4, '40%'), (0.5, '50%'), (0.6, '60%'), (0.7, '70%'), (0.8, '80%'), (0.9, '90%')], default=0.2, help_text='20%', verbose_name='background opacity'),
),
migrations.AlterField(
model_name='theme',
name='related_modal_rounded_corners',
field=models.BooleanField(default=True, verbose_name='rounded corners'),
),
migrations.AlterField(
model_name='theme',
name='title',
field=models.CharField(blank=True, default='Django administration', max_length=50),
),
migrations.AlterField(
model_name='theme',
name='title_color',
field=colorfield.fields.ColorField(blank=True, default='#F5DD5D', help_text='#F5DD5D', max_length=10, verbose_name='title color'),
),
migrations.AlterField(
model_name='theme',
name='title_visible',
field=models.BooleanField(default=True, verbose_name='visible'),
),
]
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2017-08-24 10:49
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('admin_interface', '0006_bytes_to_str'),
]
operations = [
migrations.AddField(
model_name='theme',
name='favicon',
field=models.FileField(blank=True, help_text='(.ico|.png|.gif - 16x16|32x32 px)', upload_to='admin-interface/favicon/', verbose_name='favicon'),
),
]
+105 -49
View File
@@ -14,76 +14,128 @@ class Theme(models.Model):
@staticmethod @staticmethod
def post_migrate_handler(sender, **kwargs): def post_migrate_handler(sender, **kwargs):
Theme.get_active_theme() theme = Theme.get_active_theme()
@staticmethod @staticmethod
def post_delete_handler(instance, **kwargs): def post_delete_handler(instance, **kwargs):
Theme.get_active_theme() theme = Theme.get_active_theme()
@staticmethod @staticmethod
def post_save_handler(instance, created, **kwargs): def post_save_handler(instance, created, **kwargs):
theme = instance theme = instance
if theme.active: if theme.active:
Theme.objects.exclude( pk = theme.pk ).update( active = False ) Theme.objects.exclude(pk=theme.pk).update(active=False)
Theme.get_active_theme() theme = Theme.get_active_theme()
@staticmethod @staticmethod
def get_active_theme(): def get_active_theme():
objs_active_qs = Theme.objects.filter( active = True ) objs_active_qs = Theme.objects.filter(active=True)
objs_active_ls = list(objs_active_qs)
objs_active_count = len(objs_active_ls)
#get or create default theme and enforce default logo if deleted if objs_active_count == 0:
default_obj_active = (objs_active_qs.count() == 0) default_obj, default_obj_created = Theme.objects.get_or_create(
default_obj, default_obj_created = Theme.objects.get_or_create(pk = '1', defaults = { 'active':default_obj_active }) pk='1', defaults={'active': True})
if not default_obj_created:
default_obj.set_active()
obj = default_obj
if not default_obj_created and default_obj_active: elif objs_active_count == 1:
default_obj.set_active() obj = objs_active_ls[0]
obj = objs_active_qs.last() elif objs_active_count > 1:
objs_active_count = objs_active_qs.count() obj = objs_active_ls[-1]
if objs_active_count > 1:
obj.set_active() obj.set_active()
return obj return obj
name = models.CharField( max_length = 50, default = 'Django' ) name = models.CharField(max_length=50, default='Django')
active = models.BooleanField( default = True ) active = models.BooleanField(default=True)
title = models.CharField( max_length = 50, default = 'Django administration', blank = True ) title = models.CharField(
title_color = ColorField( blank = True, default = '#F5DD5D', help_text = '#F5DD5D', verbose_name = 'title color' ) max_length=50, default='Django administration', blank=True)
title_visible = models.BooleanField( default = True, verbose_name = 'visible' ) title_color = ColorField(
blank=True, default='#F5DD5D', help_text='#F5DD5D',
max_length=10, verbose_name='title color')
title_visible = models.BooleanField(
default=True, verbose_name='visible')
logo = models.FileField( upload_to = 'admin-interface/logo/', blank = True, help_text = '(leave blank to use the default Django logo)' ) logo = models.FileField(
logo_color = ColorField( blank = True, default = '#FFFFFF', help_text = '#FFFFFF', verbose_name = 'logo color' ) upload_to='admin-interface/logo/', blank=True,
logo_visible = models.BooleanField( default = True, verbose_name = 'visible' ) help_text='(leave blank to use the default Django logo)')
logo_color = ColorField(
blank=True, default='#FFFFFF', help_text='#FFFFFF',
max_length=10, verbose_name='logo color')
logo_visible = models.BooleanField(
default=True, verbose_name='visible')
css_header_background_color = ColorField( blank = True, default = '#0C4B33', help_text = '#0C4B33', verbose_name = 'background color' ) favicon = models.FileField(
css_header_text_color = ColorField( blank = True, default = '#44B78B', help_text = '#44B78B', verbose_name = 'text color' ) upload_to='admin-interface/favicon/', blank=True,
css_header_link_color = ColorField( blank = True, default = '#FFFFFF', help_text = '#FFFFFF', verbose_name = 'link color' ) help_text='(.ico|.png|.gif - 16x16|32x32 px)', verbose_name='favicon')
css_header_link_hover_color = ColorField( blank = True, default = '#C9F0DD', help_text = '#C9F0DD', verbose_name = 'link hover color' )
css_module_background_color = ColorField( blank = True, default = '#44B78B', help_text = '#44B78B', verbose_name = 'background color' ) css_header_background_color = ColorField(
css_module_text_color = ColorField( blank = True, default = '#FFFFFF', help_text = '#FFFFFF', verbose_name = 'text color' ) blank=True, default='#0C4B33', help_text='#0C4B33',
css_module_link_color = ColorField( blank = True, default = '#FFFFFF', help_text = '#FFFFFF', verbose_name = 'link color' ) max_length=10, verbose_name='background color')
css_module_link_hover_color = ColorField( blank = True, default = '#C9F0DD', help_text = '#C9F0DD', verbose_name = 'link hover color' ) css_header_text_color = ColorField(
css_module_rounded_corners = models.BooleanField( default = True, verbose_name = 'rounded corners' ) blank=True, default='#44B78B', help_text='#44B78B',
max_length=10, verbose_name='text color')
css_header_link_color = ColorField(
blank=True, default='#FFFFFF', help_text='#FFFFFF',
max_length=10, verbose_name='link color')
css_header_link_hover_color = ColorField(
blank=True, default='#C9F0DD', help_text='#C9F0DD',
max_length=10, verbose_name='link hover color')
css_generic_link_color = ColorField( blank = True, default = '#0C3C26', help_text = '#0C3C26', verbose_name = 'link color' ) css_module_background_color = ColorField(
css_generic_link_hover_color = ColorField( blank = True, default = '#156641', help_text = '#156641', verbose_name = 'link hover color' ) blank=True, default='#44B78B', help_text='#44B78B',
max_length=10, verbose_name='background color')
css_module_text_color = ColorField(
blank=True, default='#FFFFFF', help_text='#FFFFFF',
max_length=10, verbose_name='text color')
css_module_link_color = ColorField(
blank=True, default='#FFFFFF', help_text='#FFFFFF',
max_length=10, verbose_name='link color')
css_module_link_hover_color = ColorField(
blank=True, default='#C9F0DD', help_text='#C9F0DD',
max_length=10, verbose_name='link hover color')
css_module_rounded_corners = models.BooleanField(
default=True, verbose_name='rounded corners')
css_save_button_background_color = ColorField( blank = True, default = '#0C4B33', help_text = '#0C4B33', verbose_name = 'background color' ) css_generic_link_color = ColorField(
css_save_button_background_hover_color = ColorField( blank = True, default = '#0C3C26', help_text = '#0C3C26', verbose_name = 'background hover color' ) blank=True, default='#0C3C26', help_text='#0C3C26',
css_save_button_text_color = ColorField( blank = True, default = '#FFFFFF', help_text = '#FFFFFF', verbose_name = 'text color' ) max_length=10, verbose_name='link color')
css_generic_link_hover_color = ColorField(
blank=True, default='#156641', help_text='#156641',
max_length=10, verbose_name='link hover color')
css_delete_button_background_color = ColorField( blank = True, default = '#BA2121', help_text = '#BA2121', verbose_name = 'background color' ) css_save_button_background_color = ColorField(
css_delete_button_background_hover_color = ColorField( blank = True, default = '#A41515', help_text = '#A41515', verbose_name = 'background hover color' ) blank=True, default='#0C4B33', help_text='#0C4B33',
css_delete_button_text_color = ColorField( blank = True, default = '#FFFFFF', help_text = '#FFFFFF', verbose_name = 'text color' ) max_length=10, verbose_name='background color')
css_save_button_background_hover_color = ColorField(
blank=True, default='#0C3C26', help_text='#0C3C26',
max_length=10, verbose_name='background hover color')
css_save_button_text_color = ColorField(
blank=True, default='#FFFFFF', help_text='#FFFFFF',
max_length=10, verbose_name='text color')
css = models.TextField( blank = True ) css_delete_button_background_color = ColorField(
blank=True, default='#BA2121', help_text='#BA2121',
max_length=10, verbose_name='background color')
css_delete_button_background_hover_color = ColorField(
blank=True, default='#A41515', help_text='#A41515',
max_length=10, verbose_name='background hover color')
css_delete_button_text_color = ColorField(
blank=True, default='#FFFFFF', help_text='#FFFFFF',
max_length=10, verbose_name='text color')
related_modal_active = models.BooleanField( default = True, verbose_name = 'active' ) css = models.TextField(blank=True)
related_modal_background_color = ColorField( blank = True, default = '#000000', help_text = '#000000', verbose_name = 'background color' )
related_modal_active = models.BooleanField(
default=True, verbose_name='active')
related_modal_background_color = ColorField(
blank=True, default='#000000', help_text='#000000',
max_length=10, verbose_name='background color')
related_modal_background_opacity_choices = ( related_modal_background_opacity_choices = (
(0.1, '10%', ), (0.1, '10%', ),
(0.2, '20%', ), (0.2, '20%', ),
@@ -95,11 +147,16 @@ class Theme(models.Model):
(0.8, '80%', ), (0.8, '80%', ),
(0.9, '90%', ), (0.9, '90%', ),
) )
related_modal_background_opacity = models.FloatField( choices = related_modal_background_opacity_choices, default = 0.2, help_text = '20%', verbose_name = 'background opacity' ) related_modal_background_opacity = models.FloatField(
related_modal_rounded_corners = models.BooleanField( default = True, verbose_name = 'rounded corners' ) choices=related_modal_background_opacity_choices,
default=0.2, help_text='20%', verbose_name='background opacity')
related_modal_rounded_corners = models.BooleanField(
default=True, verbose_name='rounded corners')
list_filter_dropdown = models.BooleanField( default = False, verbose_name = 'use dropdown' ) list_filter_dropdown = models.BooleanField(
recent_actions_visible = models.BooleanField( default = True, verbose_name = 'visible' ) default=False, verbose_name='use dropdown')
recent_actions_visible = models.BooleanField(
default=True, verbose_name='visible')
def set_active(self): def set_active(self):
@@ -117,6 +174,5 @@ class Theme(models.Model):
return force_text(self.name) return force_text(self.name)
post_delete.connect(Theme.post_delete_handler, sender = Theme) post_delete.connect(Theme.post_delete_handler, sender=Theme)
post_save.connect(Theme.post_save_handler, sender = Theme) post_save.connect(Theme.post_save_handler, sender=Theme)
@@ -22,13 +22,23 @@
var initData = JSON.parse(document.getElementById('django-admin-popup-response-constants').dataset.popupResponse); var initData = JSON.parse(document.getElementById('django-admin-popup-response-constants').dataset.popupResponse);
switch(initData.action){ switch(initData.action){
case 'change': case 'change':
openerRef.dismissChangeRelatedObjectPopup(modalRef, initData.value, initData.obj, initData.new_value); if( typeof(openerRef.dismissChangeRelatedObjectPopup) == 'function' ){
openerRef.dismissChangeRelatedObjectPopup(modalRef, initData.value, initData.obj, initData.new_value);
}
break; break;
case 'delete': case 'delete':
openerRef.dismissDeleteRelatedObjectPopup(modalRef, initData.value); if( typeof(openerRef.dismissDeleteRelatedObjectPopup) == 'function' ){
openerRef.dismissDeleteRelatedObjectPopup(modalRef, initData.value);
}
break; break;
default: default:
openerRef.dismissAddRelatedObjectPopup(modalRef, initData.value, initData.obj); if( typeof(openerRef.dismissAddRelatedObjectPopup) == 'function' ){
openerRef.dismissAddRelatedObjectPopup(modalRef, initData.value, initData.obj);
}
else if( typeof(openerRef.dismissAddAnotherPopup) == 'function' ){
// django 1.7 compatibility
openerRef.dismissAddAnotherPopup(modalRef, initData.value, initData.obj);
}
break; break;
} }
})(); })();
@@ -7,18 +7,23 @@ if(typeof django !== 'undefined' && typeof django.jQuery !== 'undefined' )
// create the function that will close the modal // create the function that will close the modal
function dismissRelatedObjectModal() function dismissRelatedObjectModal()
{ {
// close the popup // close the popup as modal
$.magnificPopup.close(); $.magnificPopup.close();
} }
// assign the function to a global variable // assign the function to a global variable
window.dismissRelatedObjectModal = dismissRelatedObjectModal; window.dismissRelatedObjectModal = dismissRelatedObjectModal;
// listen click events on related links function presentRelatedObjectModal(e)
// (:link prevents to listen click event if href is not defined) {
$('a.related-widget-wrapper-link:link').click(function(e){ var href = ($(this).attr('href') || '');
if( href == '' ){
return;
}
// open the popup as modal
e.preventDefault(); e.preventDefault();
e.stopImmediatePropagation();
// remove focus from clicked link // remove focus from clicked link
$(this).blur(); $(this).blur();
@@ -26,16 +31,23 @@ if(typeof django !== 'undefined' && typeof django.jQuery !== 'undefined' )
// use the clicked link id as iframe name // use the clicked link id as iframe name
// it will be available as window.name in the loaded iframe // it will be available as window.name in the loaded iframe
var iframeName = $(this).attr('id'); var iframeName = $(this).attr('id');
//var iframeName = String(window.name + '____' + $(this).attr('id')); // var iframeName = String(window.name + '____' + $(this).attr('id'));
//console.log('open modal with name: "' + iframeName + '"'); // console.log('open modal with name: "' + iframeName + '"');
// browsers stop loading nested iframes having the same src url // browsers stop loading nested iframes having the same src url
// create a random parameter and append it to the src url to prevent it // create a random parameter and append it to the src url to prevent it
var iframeSrcRandom = String(Math.round(Math.random() * 999999)); var iframeSrcRandom = String(Math.round(Math.random() * 999999));
var iframeSrc = $(this).attr('href') + '&_modal=' + iframeSrcRandom; var iframeSrc = href;
// fix for django 1.7
if( iframeSrc.indexOf('_popup=1') == -1 ){
iframeSrc += '&_popup=1';
}
iframeSrc += '&_modal=' + iframeSrcRandom;
// build the iframe html // build the iframe html
//var iframeHTML = '<iframe id="related-modal" name="' + iframeName + '" src="' + iframeSrc + '"></iframe>'; // var iframeHTML = '<iframe id="related-modal" name="' + iframeName + '" src="' + iframeSrc + '"></iframe>';
var iframeHTML = '<iframe id="related-modal-iframe" name="' + iframeName + '" src="' + iframeSrc + '"></iframe>'; var iframeHTML = '<iframe id="related-modal-iframe" name="' + iframeName + '" src="' + iframeSrc + '"></iframe>';
// create the iframe jquery element // create the iframe jquery element
@@ -61,7 +73,16 @@ if(typeof django !== 'undefined' && typeof django.jQuery !== 'undefined' )
}); });
return false; return false;
}); }
// listen click events on related links
// django 1.7 compatibility
$('a.add-another').removeAttr('onclick');
$('a.add-another').click( presentRelatedObjectModal );
// django 1.8 and above
$('a.related-widget-wrapper-link').click( presentRelatedObjectModal );
}); });
})(django.jQuery); })(django.jQuery);
+14 -6
View File
@@ -8,8 +8,12 @@
{% block extrastyle %} {% block extrastyle %}
{% get_admin_interface_theme as theme %} {% get_admin_interface_theme as theme %}
{% get_admin_interface_version as version %}
<style type="text/css"> <style type="text/css">
/*
django-admin-interface {{ version }}
https://github.com/fabiocaccamo/django-admin-interface
*/
{% include "admin_interface/css/admin-interface.css" %} {% include "admin_interface/css/admin-interface.css" %}
{% include "admin_interface/css/admin-interface-fix.css" %} {% include "admin_interface/css/admin-interface-fix.css" %}
{% include "admin_interface/css/list-filter-dropdown.css" %} {% include "admin_interface/css/list-filter-dropdown.css" %}
@@ -29,14 +33,18 @@
{% block blockbots %} {% block blockbots %}
{{ block.super }} {{ block.super }}
{% get_admin_interface_theme as theme %}
{% get_admin_interface_version as version %}
{# https://github.com/elky/django-flat-responsive#important-note #} {# https://github.com/elky/django-flat-responsive#important-note #}
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0"> <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0">
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/responsive.css' %}" /> <link rel="stylesheet" type="text/css" href="{% static 'admin/css/responsive.css' %}?v={{ version }}" />
{% get_admin_interface_theme as theme %} {% if theme.favicon %}
<link rel="icon" type="image/x-icon" href="{{ theme.favicon.url }}?v={{ version }}" />
{% endif %}
{% if theme.related_modal_active %} {% if theme.related_modal_active %}
<link rel="stylesheet" type="text/css" href="{% static 'admin_interface/magnific-popup/magnific-popup.css' %}" /> <link rel="stylesheet" type="text/css" href="{% static 'admin_interface/magnific-popup/magnific-popup.css' %}?v={{ version }}" />
<script type="text/javascript" src="{% static 'admin_interface/magnific-popup/jquery.magnific-popup.js' %}"></script> <script type="text/javascript" src="{% static 'admin_interface/magnific-popup/jquery.magnific-popup.js' %}?v={{ version }}"></script>
<script type="text/javascript" src="{% static 'admin_interface/related-modal/related-modal.js' %}"></script> <script type="text/javascript" src="{% static 'admin_interface/related-modal/related-modal.js' %}?v={{ version }}"></script>
{% endif %} {% endif %}
{% endblock %} {% endblock %}
@@ -0,0 +1,15 @@
{% load i18n static %}<!DOCTYPE html>
<html>
<head><title>{% trans 'Popup closing...' %}</title></head>
<body>
<script type="text/javascript"
id="django-admin-popup-response-constants"
src="{% static "admin/js/popup_response.js" %}"
{% if popup_response_data %}
data-popup-response="{{ popup_response_data }}"
{% else %}
data-popup-response='{"action":"{{ action|escape }}","value":"{{ value|escape }}","obj":"{{ obj|escape }}","new_value":"{{ new_value|escape }}"}'
{% endif %}>
</script>
</body>
</html>
@@ -78,14 +78,13 @@
border: 1px solid transparent; border: 1px solid transparent;
} }
.admin-interface fieldset.collapse.collapsed a.collapse-toggle { .admin-interface fieldset.collapse.collapsed a.collapse-toggle,
font-weight: bold;
text-transform: lowercase;
}
.admin-interface fieldset.collapse a.collapse-toggle { .admin-interface fieldset.collapse a.collapse-toggle {
font-weight: bold; font-weight: normal;
text-transform: lowercase; text-transform: lowercase;
font-size: 12px;
text-decoration: underline;
padding: 0 1px;
} }
/* /*
@@ -58,12 +58,12 @@
} }
.admin-interface fieldset.collapse.collapsed a.collapse-toggle { .admin-interface fieldset.collapse.collapsed a.collapse-toggle {
color:{{ theme.css_generic_link_color }}; color:{{ theme.css_module_link_color }};
} }
.admin-interface fieldset.collapse.collapsed a.collapse-toggle:hover, .admin-interface fieldset.collapse.collapsed a.collapse-toggle:hover,
.admin-interface fieldset.collapse.collapsed a.collapse-toggle:active { .admin-interface fieldset.collapse.collapsed a.collapse-toggle:active {
color:{{ theme.css_generic_link_hover_color }}; color:{{ theme.css_module_link_hover_color }};
} }
.admin-interface fieldset.collapse a.collapse-toggle { .admin-interface fieldset.collapse a.collapse-toggle {
@@ -3,13 +3,34 @@
from django import template from django import template
from admin_interface.models import Theme from admin_interface.models import Theme
from admin_interface.version import __version__
register = template.Library() register = template.Library()
try:
assignment_tag = register.assignment_tag
except AttributeError:
assignment_tag = register.simple_tag
@register.assignment_tag(takes_context = True)
@assignment_tag(takes_context=True)
def get_admin_interface_theme(context): def get_admin_interface_theme(context):
return Theme.get_active_theme() theme = None
request = context.get('request', None)
if request:
theme = getattr(request, 'admin_interface_theme', None)
if not theme:
theme = Theme.get_active_theme()
if request:
request.admin_interface_theme = theme
return theme
@assignment_tag(takes_context=True)
def get_admin_interface_version(context):
return __version__
+1 -2
View File
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
__version__ = '0.4.5' __version__ = '0.5.4'
+1 -1
View File
@@ -1,2 +1,2 @@
[metadata] [metadata]
description-file = README.md description-file = README.rst
+3 -3
View File
@@ -17,9 +17,9 @@ setup(
keywords=['django', 'admin', 'interface', 'responsive', 'flat', 'theme', 'custom', 'ui'], keywords=['django', 'admin', 'interface', 'responsive', 'flat', 'theme', 'custom', 'ui'],
requires=['django(>=1.7)'], requires=['django(>=1.7)'],
install_requires=[ install_requires=[
'django-colorfield==0.1.12', 'django-colorfield>=0.1,<1.0',
'django-flat-theme==1.1.4', 'django-flat-theme>=1.0,<2.0',
'django-flat-responsive==1.3.0' 'django-flat-responsive>=1.0,<2.0',
], ],
classifiers=[ classifiers=[
'Development Status :: 5 - Production/Stable', 'Development Status :: 5 - Production/Stable',
+28 -17
View File
@@ -2,31 +2,31 @@
from django.conf import settings from django.conf import settings
from django.test import TestCase from django.test import TestCase
from django.test.client import RequestFactory
from django.template import Context, Template from django.template import Context, Template
import random import random
import shutil import shutil
from admin_interface.models import Theme from admin_interface.models import Theme
from admin_interface.templatetags import admin_interface_tags as templatetags
from admin_interface.version import __version__
class AdminInterfaceTestCase(TestCase): class AdminInterfaceTestCase(TestCase):
def setUp(self): def setUp(self):
self.request_factory = RequestFactory()
pass pass
def tearDown(self): def tearDown(self):
shutil.rmtree(settings.MEDIA_ROOT, ignore_errors=True) shutil.rmtree(settings.MEDIA_ROOT, ignore_errors=True)
pass pass
def __render_template(self, string, context=None): def __render_template(self, string, context):
context = context or {}
context = Context(context)
return Template(string).render(context) return Template(string).render(context)
def __test_active_theme(self): def __test_active_theme(self):
theme = Theme.get_active_theme() theme = Theme.get_active_theme()
print( theme ) print( theme )
self.assertTrue(theme != None) self.assertTrue(theme != None)
@@ -34,17 +34,14 @@ class AdminInterfaceTestCase(TestCase):
self.assertEqual(Theme.objects.filter( active = True ).count(), 1); self.assertEqual(Theme.objects.filter( active = True ).count(), 1);
def test_default_theme_created_if_no_themes(self): def test_default_theme_created_if_no_themes(self):
Theme.objects.all().delete() Theme.objects.all().delete()
self.__test_active_theme() self.__test_active_theme()
def test_default_theme_created_if_all_themes_deleted(self): def test_default_theme_created_if_all_themes_deleted(self):
Theme.objects.all().delete() Theme.objects.all().delete()
self.__test_active_theme() self.__test_active_theme()
def test_default_theme_activated_on_save_if_no_active_themes(self): def test_default_theme_activated_on_save_if_no_active_themes(self):
Theme.objects.all().delete() Theme.objects.all().delete()
theme = Theme.get_active_theme() theme = Theme.get_active_theme()
theme.active = False theme.active = False
@@ -52,13 +49,11 @@ class AdminInterfaceTestCase(TestCase):
self.__test_active_theme() self.__test_active_theme()
def test_default_theme_activated_after_update_if_no_active_themes(self): def test_default_theme_activated_after_update_if_no_active_themes(self):
Theme.objects.all().delete() Theme.objects.all().delete()
Theme.objects.all().update( active = False ) Theme.objects.all().update( active = False )
self.__test_active_theme() self.__test_active_theme()
def test_default_theme_activated_after_update_if_multiple_active_themes(self): def test_default_theme_activated_after_update_if_multiple_active_themes(self):
Theme.objects.all().delete() Theme.objects.all().delete()
theme_1 = Theme.objects.create( name = 'Custom 1', active = True ) theme_1 = Theme.objects.create( name = 'Custom 1', active = True )
theme_2 = Theme.objects.create( name = 'Custom 2', active = True ) theme_2 = Theme.objects.create( name = 'Custom 2', active = True )
@@ -68,7 +63,6 @@ class AdminInterfaceTestCase(TestCase):
self.__test_active_theme() self.__test_active_theme()
def test_default_theme_activated_on_active_theme_deleted(self): def test_default_theme_activated_on_active_theme_deleted(self):
Theme.objects.all().delete() Theme.objects.all().delete()
theme_1 = Theme.objects.create( name = 'Custom 1', active = True ) theme_1 = Theme.objects.create( name = 'Custom 1', active = True )
theme_2 = Theme.objects.create( name = 'Custom 2', active = True ) theme_2 = Theme.objects.create( name = 'Custom 2', active = True )
@@ -77,7 +71,6 @@ class AdminInterfaceTestCase(TestCase):
self.__test_active_theme() self.__test_active_theme()
def test_last_theme_activated_on_multiple_themes_created(self): def test_last_theme_activated_on_multiple_themes_created(self):
Theme.objects.all().delete() Theme.objects.all().delete()
theme_1 = Theme.objects.create( name = 'Custom 1', active = True ) theme_1 = Theme.objects.create( name = 'Custom 1', active = True )
theme_2 = Theme.objects.create( name = 'Custom 2', active = True ) theme_2 = Theme.objects.create( name = 'Custom 2', active = True )
@@ -86,7 +79,6 @@ class AdminInterfaceTestCase(TestCase):
self.__test_active_theme() self.__test_active_theme()
def test_last_theme_activated_on_multiple_themes_activated(self): def test_last_theme_activated_on_multiple_themes_activated(self):
Theme.objects.all().delete() Theme.objects.all().delete()
theme_1 = Theme.objects.create( name = 'Custom 1', active = True ) theme_1 = Theme.objects.create( name = 'Custom 1', active = True )
theme_2 = Theme.objects.create( name = 'Custom 2', active = True ) theme_2 = Theme.objects.create( name = 'Custom 2', active = True )
@@ -101,13 +93,32 @@ class AdminInterfaceTestCase(TestCase):
self.assertEqual( Theme.get_active_theme().pk, theme.pk ) self.assertEqual( Theme.get_active_theme().pk, theme.pk )
self.__test_active_theme() self.__test_active_theme()
def test_templatetags(self): def test_templatetags_get_theme(self):
Theme.objects.all().delete() Theme.objects.all().delete()
rendered = self.__render_template('{% load admin_interface_tags %}{% get_admin_interface_theme as theme %}{{ theme.name }}') context = Context({})
theme = templatetags.get_admin_interface_theme(context)
self.assertEqual(theme.name, 'Django')
rendered = self.__render_template('{% load admin_interface_tags %}{% get_admin_interface_theme as theme %}{{ theme.name }}', context)
self.assertEqual(rendered, 'Django') self.assertEqual(rendered, 'Django')
def test_templatetags_get_theme_with_request(self):
Theme.objects.all().delete()
context = Context({
'request': self.request_factory.get('/')
})
theme = templatetags.get_admin_interface_theme(context)
self.assertEqual(theme.name, 'Django')
rendered = self.__render_template('{% load admin_interface_tags %}{% get_admin_interface_theme as theme %}{{ theme.name }}', context)
self.assertEqual(rendered, 'Django')
def test_templatetags_get_version(self):
context = Context({})
version = templatetags.get_admin_interface_version(context)
self.assertEqual(version, __version__)
rendered = self.__render_template('{% load admin_interface_tags %}{% get_admin_interface_version as version %}{{ version }}', context)
self.assertEqual(rendered, __version__)
def test_repr(self): def test_repr(self):
theme = Theme.get_active_theme() theme = Theme.get_active_theme()
self.assertEqual( "{0}".format(theme), 'Django' ) self.assertEqual( '{0}'.format(theme), 'Django' )
+5 -4
View File
@@ -1,9 +1,9 @@
[tox] [tox]
envlist = envlist =
py27-{17,18,19,110,111}, py27-{17,18,19,110,111},
py34-{17,18,19,110,111}, py34-{17,18,19,110,111,master},
py35-{18,19,110,111}, py35-{18,19,110,111,master},
py36-{18,19,110,111}, py36-{18,19,110,111,master},
[testenv] [testenv]
passenv = CI TRAVIS TRAVIS_* passenv = CI TRAVIS TRAVIS_*
deps = deps =
@@ -12,9 +12,10 @@ deps =
19: Django >= 1.9, < 1.10 19: Django >= 1.9, < 1.10
110: Django >= 1.10, < 1.11 110: Django >= 1.10, < 1.11
111: Django >= 1.11, < 1.12 111: Django >= 1.11, < 1.12
master: https://github.com/django/django/archive/master.tar.gz
coverage coverage
codecov codecov
commands = commands =
coverage run --append --source=admin_interface setup.py test coverage run --append --source=admin_interface setup.py test
coverage report -m coverage report -m
codecov codecov