merge master and fixed conflict in typography.scss

This commit is contained in:
Dave Cranwell 2014-07-18 13:04:11 +01:00
commit b4087b489c
27 changed files with 8796 additions and 1378 deletions

View file

@ -4,6 +4,7 @@ Changelog
0.5 (xx.xx.20xx)
~~~~~~~~~~~~~~~~
* Added decorator syntax for hooks
* Replaced lxml dependency with html5lib, to simplify installation
0.4.1 (14.07.2014)
~~~~~~~~~~~~~~~~~~

View file

@ -7,8 +7,8 @@ Wagtail 0.5 release notes - IN DEVELOPMENT
:depth: 1
Whats new
=========
What's new
==========
Minor features
@ -27,6 +27,8 @@ Core
MenuItem('Kittens!', '/kittens/', classnames='icon icon-folder-inverse', order=1000)
)
* The lxml library (used for whitelisting and rewriting of rich text fields) has been replaced with the pure-python html5lib library, to simplify installation.
Bug fixes
~~~~~~~~~

View file

@ -92,26 +92,49 @@ Then in your own page templates, you can include your snippet template tag with:
{% endblock %}
Binding Pages to Snippets
-------------------------
An alternate strategy for including snippets might involve explicitly binding a specific page object to a specific snippet object. Lets add another snippet class to see how that might work:
In the above example, the list of adverts is a fixed list, displayed as part of the template independently of the page content. This might be what you want for a common panel in a sidebar, say - but in other scenarios you may wish to refer to a snippet within page content. This can be done by defining a foreign key to the snippet model within your page model, and adding a ``SnippetChooserPanel`` to the page's ``content_panels`` definitions. For example, if you wanted to be able to specify an advert to appear on ``BookPage``:
.. code-block:: python
from wagtail.wagtailsnippets.edit_handlers import SnippetChooserPanel
# ...
class BookPage(Page):
advert = models.ForeignKey(
'demo.Advert',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+'
)
BookPage.content_panels = [
SnippetChooserPanel('advert', Advert),
# ...
]
The snippet could then be accessed within your template as ``self.advert``.
To attach multiple adverts to a page, the ``SnippetChooserPanel`` can be placed on an inline child object of ``BookPage``, rather than on ``BookPage`` itself. Here this child model is named ``BookPageAdvertPlacement`` (so called because there is one such object for each time that an advert is placed on a BookPage):
.. code-block:: python
from django.db import models
from wagtail.wagtailcore.models import Page
from wagtail.wagtailadmin.edit_handlers import PageChooserPanel
from wagtail.wagtailsnippets.models import register_snippet
from wagtail.wagtailsnippets.edit_handlers import SnippetChooserPanel
from modelcluster.fields import ParentalKey
...
class AdvertPlacement(models.Model):
page = ParentalKey('wagtailcore.Page', related_name='advert_placements')
class BookPageAdvertPlacement(Orderable, models.Model):
page = ParentalKey('demo.BookPage', related_name='advert_placements')
advert = models.ForeignKey('demo.Advert', related_name='+')
class Meta:
@ -119,25 +142,27 @@ An alternate strategy for including snippets might involve explicitly binding a
verbose_name_plural = "Advert Placements"
panels = [
PageChooserPanel('page'),
SnippetChooserPanel('advert', Advert),
]
def __unicode__(self):
return self.page.title + " -> " + self.advert.text
register_snippet(AdvertPlacement)
class BookPage(Page):
...
The class ``AdvertPlacement`` has two properties, ``page`` and ``advert``, which point to other models. Wagtail provides a ``PageChooserPanel`` and ``SnippetChooserPanel`` to let us make painless selection of those properties in the Wagtail admin. Note also the ``Meta`` class, which you can stock with the ``verbose_name`` and ``verbose_name_plural`` properties to override the snippet labels in the Wagtail admin. The text representation of the class has also gotten fancy, using both properties to construct a compound label showing the relationship it forms between a page and an Advert.
BookPage.content_panels = [
InlinePanel(BookPage, 'advert_placements', label="Adverts"),
# ...
]
With this snippet in place, we can use the reverse ``related_name`` lookup label ``advert_placements`` to iterate over any placements within our template files. In the template for a ``Page``-derived model, we could include the following:
These child objects are now accessible through the page's ``advert_placements`` property, and from there we can access the linked Advert snippet as ``advert``. In the template for ``BookPage``, we could include the following:
.. code-block:: django
{% if self.advert_placements %}
{% for advert_placement in self.advert_placements.all %}
<p><a href="{{ advert_placement.advert.url }}">{{ advert_placement.advert.text }}</a></p>
{% endfor %}
{% endif %}
{% for advert_placement in self.advert_placements.all %}
<p><a href="{{ advert_placement.advert.url }}">{{ advert_placement.advert.text }}</a></p>
{% endfor %}

View file

@ -1,3 +1,4 @@
#!/usr/bin/env bash
# Production-configured Wagtail installation.
# BUT, SECURE SERVICES/ACCOUNT FOR FULL PRODUCTION USE!
# For a non-dummy email backend configure Django's EMAIL_BACKEND
@ -12,7 +13,7 @@ PROJECT_ROOT=/usr/local/django
echo "This script overwrites key files, and should only be run on a new box."
read -p "Type 'yes' to confirm: " CONFIRM
[ $CONFIRM== “yes” ] || exit
[ "$CONFIRM" == "yes" ] || exit
read -p "Enter a name for your project [$PROJECT]: " U_PROJECT
if [ ! -z "$U_PROJECT" ]; then
@ -35,7 +36,7 @@ SERVER_IP=`ifconfig eth0 |grep "inet addr" | cut -d: -f2 | cut -d" " -f1`
aptitude update
aptitude -y install git python-pip nginx postgresql redis-server
aptitude -y install postgresql-server-dev-all python-dev libxml2-dev libxslt-dev libjpeg62-dev
aptitude -y install postgresql-server-dev-all python-dev libjpeg62-dev
perl -pi -e "s/^(local\s+all\s+postgres\s+)peer$/\1trust/" /etc/postgresql/9.1/main/pg_hba.conf
service postgresql reload

View file

@ -1,3 +1,4 @@
#!/usr/bin/env bash
# Production-configured Wagtail installation.
# BUT, SECURE SERVICES/ACCOUNT FOR FULL PRODUCTION USE!
# For a non-dummy email backend configure Django's EMAIL_BACKEND
@ -10,7 +11,7 @@ PROJECT_ROOT=/usr/local/django
echo "This script overwrites key files, and should only be run on a new box."
read -p "Type 'yes' to confirm: " CONFIRM
[ $CONFIRM== “yes” ] || exit
[ "$CONFIRM" == "yes" ] || exit
read -p "Enter a name for your project [$PROJECT]: " U_PROJECT
if [ ! -z "$U_PROJECT" ]; then
@ -33,7 +34,7 @@ SERVER_IP=`ifconfig eth0 |grep "inet addr" | cut -d: -f2 | cut -d" " -f1`
aptitude update
aptitude -y install git python-pip nginx postgresql redis-server
aptitude -y install postgresql-server-dev-all python-dev libxml2-dev libxslt-dev libjpeg62-dev
aptitude -y install postgresql-server-dev-all python-dev libjpeg62-dev
perl -pi -e "s/^(local\s+all\s+postgres\s+)peer$/\1trust/" /etc/postgresql/9.1/main/pg_hba.conf
service postgresql reload

View file

@ -32,7 +32,7 @@ install_requires = [
"django-treebeard==2.0",
"Pillow>=2.3.0",
"beautifulsoup4>=4.3.2",
"lxml>=3.3.0",
"html5lib==0.999",
"Unidecode>=0.04.14",
"six==1.7.3",
'requests==2.3.0',

View file

@ -1,6 +1,6 @@
@import "../variables.scss";
@import "../mixins.scss";
@import "../grid.scss";
@import "wagtailadmin/scss/variables.scss";
@import "wagtailadmin/scss/mixins.scss";
@import "wagtailadmin/scss/grid.scss";
section{
border-top:1px solid $color-grey-3;
@ -50,6 +50,9 @@ section{
.color-green{
background-color:$color-green;
}
.color-blue{
background-color:$color-blue;
}
.color-grey-1{
background-color:$color-grey-1;
}

View file

@ -3,7 +3,7 @@
{% block extra_css %}
{% compress css %}
<link rel="stylesheet" href="{{ STATIC_URL }}wagtailadmin/scss/layouts/styleguide.scss" type="text/x-scss" />
<link rel="stylesheet" href="{{ STATIC_URL }}wagtailstyleguide/scss/styleguide.scss" type="text/x-scss" />
{% endcompress %}
{% endblock %}
@ -20,6 +20,7 @@
<ul class="unlist">
<li><a href="#palette">Colour palette</a></li>
<li><a href="#typography">Typography</a></li>
<li><a href="#help">Help text</a></li>
<li><a href="#listings">Listings</a></li>
<li><a href="#buttons">Buttons</a></li>
<li><a href="#dropdowns">Dropdown buttons</a></li>
@ -57,6 +58,7 @@
<li class="color-red">color-red</li>
<li class="color-orange">color-orange</li>
<li class="color-green">color-green</li>
<li class="color-blue">color-blue</li>
</ul>
</section>
@ -86,6 +88,26 @@
</section>
<section id="help">
<h2>Help text</h2>
<p>Help text is not to be confused with the messages that appear in a banner drop down from the top of the screen. Help text are permanent instructions, visible on every page view, that explain or warn about something.
<div class="help-block help-info">
<p>This is help text that might be just for information, explaining what happens next, or drawing the user's attention to something they're about to do</p>
<p>It could be multiple lines</p>
</div>
<p class="help-block help-warning">
A warning message might be output in cases where a user's action could have serious consequences
</p>
<div class="help-block help-critical">
A critical message would probably be rare, in cases where a particularly brittle or dangerously destructive action could be performed and needs to be warned about.
</div>
</section>
<section id="listings">
<h2>Listings</h2>
@ -421,6 +443,7 @@
<li class="icon icon-date">date</li>
<li class="icon icon-time">time</li>
<li class="icon icon-form">form</li>
<li class="icon icon-site">site</li>
</ul>
</section>

View file

@ -29,7 +29,6 @@ STATICFILES_FINDERS = (
)
USE_TZ = True
TIME_ZONE = 'UTC'
TEMPLATE_CONTEXT_PROCESSORS = global_settings.TEMPLATE_CONTEXT_PROCESSORS + (
'django.core.context_processors.request',

View file

@ -229,6 +229,14 @@ a.tag:hover{
}
/* general image style */
img{
max-width:100%;
height:auto;
border: 3px solid $color-grey-4;
}
/* make a block-level element inline */
.inline{
display:inline;

View file

@ -250,6 +250,9 @@
.icon-form:before{
content:"$";
}
.icon-site:before{
content:"@";
}
.icon.text-replace{
font-size:0em;

View file

@ -1,3 +1,10 @@
/*
Messages are specific to Django's "Messaging" system which adds messages into the session,
for display on the next page visited. These appear as an animated banner at the top of the page.
For inline help text, see typography.scss
*/
.messages{
position:relative;
z-index:5;

View file

@ -0,0 +1,110 @@
h1,h2,h3,h4,h5,h6{
font-weight:normal;
}
h1{
line-height:1.3em;
font-size:1.5em;
text-transform:uppercase;
color:$color-grey-1;
font-weight:600;
span{
text-transform:none;
font-weight:300;
}
.homepage &{
text-transform:none;
}
}
h2{
text-transform:uppercase;
font-size:1.3em;
font-family:Open Sans;
font-weight:600;
color:$color-grey-2;
.page-explorer &{
text-transform:none;
}
}
a{
outline:none;
color:$color-link;
text-decoration:none;
&:hover{
color:$color-link-hover;
}
}
code{
@include box-shadow(inset 0px 0px 4px 0px rgba(0, 0, 0, 0.2));
background-color:$color-fieldset-hover;
padding:2px 5px;
}
kbd{
@include border-radius(3px);
font-family:Open Sans, Arial, sans-serif;
border:1px solid $color-grey-2;
border-color:rgba(0,0,0,0.2);
padding:0.3em 0.5em;
}
/* Help text formatters */
.help-block{
padding:1em;
margin:1em 0;
p{
margin-top:0;
&:last-child{
margin-bottom:0;
}
}
}
.help-info, .help-warning, .help-critical{
@include border-radius(3px);
border:1px solid $color-grey-4;
padding-left:3.5em;
position:relative;
&:before{
font-family:wagtail;
position:absolute;
left:1em;
top:0.7em;
content:"?";
font-size:1.4em;
}
}
.help-info{
border-color:$color-blue;
&:before{
color:$color-blue;
}
}
.help-warning{
border-color:$color-orange;
&:before{
color:$color-orange;
content:"!";
}
}
.help-critical{
border-color:$color-red;
&:before{
color:$color-red;
content:"!";
}
}

View file

@ -4,6 +4,7 @@
@import "components/explorer.scss";
@import "components/icons.scss";
@import "components/typography.scss";
@import "components/tabs.scss";
@import "components/dropdowns.scss";
@import "components/modals.scss";
@ -35,67 +36,6 @@ body{
}
}
h1,h2,h3,h4,h5,h6{
font-weight:normal;
}
h1{
line-height:1.3em;
font-size:1.5em;
text-transform:uppercase;
color:$color-grey-1;
font-weight:600;
span{
text-transform:none;
font-weight:300;
}
.homepage &{
text-transform:none;
}
}
h2{
text-transform:uppercase;
font-size:1.3em;
font-family:Open Sans;
font-weight:600;
color:$color-grey-2;
.page-explorer &{
text-transform:none;
}
}
a{
outline:none;
color:$color-link;
text-decoration:none;
&:hover{
color:$color-link-hover;
}
}
code{
@include box-shadow(inset 0px 0px 4px 0px rgba(0, 0, 0, 0.2));
background-color:$color-fieldset-hover;
padding:2px 5px;
}
kbd{
@include border-radius(3px);
font-family:Open Sans, Arial, sans-serif;
border:1px solid $color-grey-2;
border-color:rgba(0,0,0,0.2);
padding:0.3em 0.5em;
}
img{
max-width:100%;
height:auto;
border: 3px solid $color-grey-4;
}
.browsermessage{
background-color:$color-red;
color:white;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View file

@ -27,6 +27,7 @@ $breakpoint-desktop-larger: 100em; /* 1600px */
$color-teal: #43b1b0;
$color-teal-darker: darken($color-teal, 10%);
$color-teal-dark: #246060;
$color-blue: #71b2d4;
$color-red: #cd3238;
$color-orange:#e9b04d;
$color-green: #189370;

View file

@ -14,6 +14,17 @@ from wagtail.wagtailcore.signals import page_published
from wagtail.wagtailusers.models import UserProfile
def submittable_timestamp(timestamp):
"""
Helper function to translate a possibly-timezone-aware datetime into the format used in the
go_live_at / expire_at form fields - "YYYY-MM-DD hh:mm", with no timezone indicator.
This will be interpreted as being in the server's timezone (settings.TIME_ZONE), so we
need to pass it through timezone.localtime to ensure that the client and server are in
agreement about what the timestamp means.
"""
return str(timezone.localtime(timestamp)).split('.')[0]
class TestPageExplorer(TestCase, WagtailTestUtils):
def setUp(self):
# Find root page
@ -180,8 +191,8 @@ class TestPageCreation(TestCase, WagtailTestUtils):
'title': "New page!",
'content': "Some content",
'slug': 'hello-world',
'go_live_at': str(go_live_at).split('.')[0],
'expire_at': str(expire_at).split('.')[0],
'go_live_at': submittable_timestamp(go_live_at),
'expire_at': submittable_timestamp(expire_at),
}
response = self.client.post(reverse('wagtailadmin_pages_create', args=('tests', 'simplepage', self.root_page.id)), post_data)
@ -203,8 +214,8 @@ class TestPageCreation(TestCase, WagtailTestUtils):
'title': "New page!",
'content': "Some content",
'slug': 'hello-world',
'go_live_at': str(timezone.now() + timedelta(days=2)).split('.')[0],
'expire_at': str(timezone.now() + timedelta(days=1)).split('.')[0],
'go_live_at': submittable_timestamp(timezone.now() + timedelta(days=2)),
'expire_at': submittable_timestamp(timezone.now() + timedelta(days=1)),
}
response = self.client.post(reverse('wagtailadmin_pages_create', args=('tests', 'simplepage', self.root_page.id)), post_data)
@ -219,7 +230,7 @@ class TestPageCreation(TestCase, WagtailTestUtils):
'title': "New page!",
'content': "Some content",
'slug': 'hello-world',
'expire_at': str(timezone.now() + timedelta(days=-1)).split('.')[0],
'expire_at': submittable_timestamp(timezone.now() + timedelta(days=-1)),
}
response = self.client.post(reverse('wagtailadmin_pages_create', args=('tests', 'simplepage', self.root_page.id)), post_data)
@ -268,8 +279,8 @@ class TestPageCreation(TestCase, WagtailTestUtils):
'content': "Some content",
'slug': 'hello-world',
'action-publish': "Publish",
'go_live_at': str(go_live_at).split('.')[0],
'expire_at': str(expire_at).split('.')[0],
'go_live_at': submittable_timestamp(go_live_at),
'expire_at': submittable_timestamp(expire_at),
}
response = self.client.post(reverse('wagtailadmin_pages_create', args=('tests', 'simplepage', self.root_page.id)), post_data)
@ -428,14 +439,16 @@ class TestPageEdit(TestCase, WagtailTestUtils):
self.assertTrue(child_page_new.has_unpublished_changes)
def test_edit_post_scheduled(self):
go_live_at = timezone.now() + timedelta(days=1)
expire_at = timezone.now() + timedelta(days=2)
# put go_live_at and expire_at several days away from the current date, to avoid
# false matches in content_json__contains tests
go_live_at = timezone.now() + timedelta(days=10)
expire_at = timezone.now() + timedelta(days=20)
post_data = {
'title': "I've been edited!",
'content': "Some content",
'slug': 'hello-world',
'go_live_at': str(go_live_at).split('.')[0],
'expire_at': str(expire_at).split('.')[0],
'go_live_at': submittable_timestamp(go_live_at),
'expire_at': submittable_timestamp(expire_at),
}
response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.child_page.id, )), post_data)
@ -459,8 +472,8 @@ class TestPageEdit(TestCase, WagtailTestUtils):
'title': "I've been edited!",
'content': "Some content",
'slug': 'hello-world',
'go_live_at': str(timezone.now() + timedelta(days=2)).split('.')[0],
'expire_at': str(timezone.now() + timedelta(days=1)).split('.')[0],
'go_live_at': submittable_timestamp(timezone.now() + timedelta(days=2)),
'expire_at': submittable_timestamp(timezone.now() + timedelta(days=1)),
}
response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.child_page.id, )), post_data)
@ -475,7 +488,7 @@ class TestPageEdit(TestCase, WagtailTestUtils):
'title': "I've been edited!",
'content': "Some content",
'slug': 'hello-world',
'expire_at': str(timezone.now() + timedelta(days=-1)).split('.')[0],
'expire_at': submittable_timestamp(timezone.now() + timedelta(days=-1)),
}
response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.child_page.id, )), post_data)
@ -525,8 +538,8 @@ class TestPageEdit(TestCase, WagtailTestUtils):
'content': "Some content",
'slug': 'hello-world',
'action-publish': "Publish",
'go_live_at': str(go_live_at).split('.')[0],
'expire_at': str(expire_at).split('.')[0],
'go_live_at': submittable_timestamp(go_live_at),
'expire_at': submittable_timestamp(expire_at),
}
response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.child_page.id, )), post_data)
@ -550,8 +563,8 @@ class TestPageEdit(TestCase, WagtailTestUtils):
'content': "Some content",
'slug': 'hello-world',
'action-publish': "Publish",
'go_live_at': str(go_live_at).split('.')[0],
'expire_at': str(expire_at).split('.')[0],
'go_live_at': submittable_timestamp(go_live_at),
'expire_at': submittable_timestamp(expire_at),
}
response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.child_page.id, )), post_data)

View file

@ -25,9 +25,9 @@ class TestDbWhitelister(TestCase):
self.assertHtmlEqual(expected, output_html)
def test_image_embed_is_rewritten(self):
input_html = '<p>OMG look at this picture of a kitten: <figure data-embedtype="image" data-id="5" data-format="image-with-caption" data-alt="A cute kitten" class="fancy-image"><img src="/media/images/kitten.jpg" width="320" height="200" alt="A cute kitten" /><figcaption>A kitten, yesterday.</figcaption></figure></p>'
input_html = '<p>OMG look at this picture of a kitten:</p><figure data-embedtype="image" data-id="5" data-format="image-with-caption" data-alt="A cute kitten" class="fancy-image"><img src="/media/images/kitten.jpg" width="320" height="200" alt="A cute kitten" /><figcaption>A kitten, yesterday.</figcaption></figure>'
output_html = DbWhitelister.clean(input_html)
expected = '<p>OMG look at this picture of a kitten: <embed embedtype="image" id="5" format="image-with-caption" alt="A cute kitten" /></p>'
expected = '<p>OMG look at this picture of a kitten:</p><embed embedtype="image" id="5" format="image-with-caption" alt="A cute kitten" />'
self.assertHtmlEqual(expected, output_html)
def test_media_embed_is_rewritten(self):

View file

@ -81,7 +81,7 @@ class Whitelister(object):
def clean(cls, html):
"""Clean up an HTML string to contain just the allowed elements /
attributes"""
doc = BeautifulSoup(html, 'lxml')
doc = BeautifulSoup(html, 'html5lib')
cls.clean_node(doc, doc)
return doc.decode()

View file

@ -5,4 +5,4 @@ warnings.warn(
"Use {% load wagtailembeds_tags %} instead.", DeprecationWarning)
from wagtail.wagtailembeds.templatetags.wagtailembeds_tags import register, embed, embedly
from wagtail.wagtailembeds.templatetags.wagtailembeds_tags import register, embed

View file

@ -19,12 +19,3 @@ def embed(url, max_width=None):
return ''
except:
return ''
@register.filter
def embedly(url, max_width=None):
warnings.warn(
"The 'embedly' filter has been renamed. "
"Use 'embed' instead.", DeprecationWarning)
return embed(url, max_width)

View file

@ -22,7 +22,7 @@ from wagtail.wagtailembeds.embeds import (
AccessDeniedEmbedlyException,
)
from wagtail.wagtailembeds.embeds import embedly as wagtail_embedly, oembed as wagtail_oembed
from wagtail.wagtailembeds.templatetags.wagtailembeds_tags import embed as embed_filter, embedly as embedly_filter
from wagtail.wagtailembeds.templatetags.wagtailembeds_tags import embed as embed_filter
class TestEmbeds(TestCase):

View file

@ -22,13 +22,14 @@
</ul>
</form>
<h2>URL</h2>
<h2 class="icon icon-link">{% trans "URL" %}</h2>
<textarea id="result-url" rows="1"></textarea>
<h2>Preview</h2>
<h2 class="icon icon-view">{% trans "Preview" %}</h2>
<div class="loading-mask inline-block">
<img class="preview" src="" alt="Preview" />
</div>
<p class="help-block help-info">{% trans "Note that images generated larger than the screen will appear smaller when previewed here, so they fit the screen." %}</p>
</div>
{% endblock %}