forked from CGM_Public/pretix_original
Compare commits
8 Commits
v3.17.0
...
release/1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3acc29f51a | ||
|
|
4bae0d1b81 | ||
|
|
c38a850294 | ||
|
|
a7ec475c40 | ||
|
|
ac1467bd4b | ||
|
|
3f0af67345 | ||
|
|
4d14b6c096 | ||
|
|
cb789bc06c |
@@ -5,7 +5,6 @@ tests:
|
|||||||
- virtualenv env
|
- virtualenv env
|
||||||
- source env/bin/activate
|
- source env/bin/activate
|
||||||
- pip install -U pip wheel setuptools
|
- pip install -U pip wheel setuptools
|
||||||
- XDG_CACHE_HOME=/cache bash .travis.sh style
|
|
||||||
- XDG_CACHE_HOME=/cache bash .travis.sh tests
|
- XDG_CACHE_HOME=/cache bash .travis.sh tests
|
||||||
tags:
|
tags:
|
||||||
- python3
|
- python3
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__ = "1.4.0"
|
__version__ = "1.4.1"
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import csv
|
|
||||||
import io
|
import io
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
|
from defusedcsv import csv
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.db.models import Sum
|
from django.db.models import Sum
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from django.contrib.contenttypes.models import ContentType
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
from django.utils.html import escape
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
@@ -66,7 +67,7 @@ class LogEntry(models.Model):
|
|||||||
'organizer': self.event.organizer.slug,
|
'organizer': self.event.organizer.slug,
|
||||||
'code': co.code
|
'code': co.code
|
||||||
}),
|
}),
|
||||||
'val': co.code,
|
'val': escape(co.code),
|
||||||
}
|
}
|
||||||
elif isinstance(co, Voucher):
|
elif isinstance(co, Voucher):
|
||||||
a_text = _('Voucher {val}…')
|
a_text = _('Voucher {val}…')
|
||||||
@@ -76,7 +77,7 @@ class LogEntry(models.Model):
|
|||||||
'organizer': self.event.organizer.slug,
|
'organizer': self.event.organizer.slug,
|
||||||
'voucher': co.id
|
'voucher': co.id
|
||||||
}),
|
}),
|
||||||
'val': co.code[:6],
|
'val': escape(co.code[:6]),
|
||||||
}
|
}
|
||||||
elif isinstance(co, Item):
|
elif isinstance(co, Item):
|
||||||
a_text = _('Product {val}')
|
a_text = _('Product {val}')
|
||||||
@@ -86,7 +87,7 @@ class LogEntry(models.Model):
|
|||||||
'organizer': self.event.organizer.slug,
|
'organizer': self.event.organizer.slug,
|
||||||
'item': co.id
|
'item': co.id
|
||||||
}),
|
}),
|
||||||
'val': co.name,
|
'val': escape(co.name),
|
||||||
}
|
}
|
||||||
elif isinstance(co, Quota):
|
elif isinstance(co, Quota):
|
||||||
a_text = _('Quota {val}')
|
a_text = _('Quota {val}')
|
||||||
@@ -96,7 +97,7 @@ class LogEntry(models.Model):
|
|||||||
'organizer': self.event.organizer.slug,
|
'organizer': self.event.organizer.slug,
|
||||||
'quota': co.id
|
'quota': co.id
|
||||||
}),
|
}),
|
||||||
'val': co.name,
|
'val': escape(co.name),
|
||||||
}
|
}
|
||||||
elif isinstance(co, ItemCategory):
|
elif isinstance(co, ItemCategory):
|
||||||
a_text = _('Category {val}')
|
a_text = _('Category {val}')
|
||||||
@@ -106,7 +107,7 @@ class LogEntry(models.Model):
|
|||||||
'organizer': self.event.organizer.slug,
|
'organizer': self.event.organizer.slug,
|
||||||
'category': co.id
|
'category': co.id
|
||||||
}),
|
}),
|
||||||
'val': co.name,
|
'val': escape(co.name),
|
||||||
}
|
}
|
||||||
elif isinstance(co, Question):
|
elif isinstance(co, Question):
|
||||||
a_text = _('Question {val}')
|
a_text = _('Question {val}')
|
||||||
@@ -116,7 +117,7 @@ class LogEntry(models.Model):
|
|||||||
'organizer': self.event.organizer.slug,
|
'organizer': self.event.organizer.slug,
|
||||||
'question': co.id
|
'question': co.id
|
||||||
}),
|
}),
|
||||||
'val': co.question,
|
'val': escape(co.question),
|
||||||
}
|
}
|
||||||
|
|
||||||
if a_text and a_map:
|
if a_text and a_map:
|
||||||
|
|||||||
13
src/pretix/base/templatetags/escapejson.py
Normal file
13
src/pretix/base/templatetags/escapejson.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from django import template
|
||||||
|
from django.template.defaultfilters import stringfilter
|
||||||
|
|
||||||
|
from pretix.helpers.escapejson import escapejson
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter("escapejson")
|
||||||
|
@stringfilter
|
||||||
|
def escapejs_filter(value):
|
||||||
|
"""Hex encodes characters for use in a application/json type script."""
|
||||||
|
return escapejson(value)
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
|
import urllib.parse
|
||||||
|
|
||||||
import bleach
|
import bleach
|
||||||
import markdown
|
import markdown
|
||||||
|
from bleach import DEFAULT_CALLBACKS
|
||||||
from django import template
|
from django import template
|
||||||
|
from django.core import signing
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils.http import is_safe_url
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
@@ -42,6 +48,15 @@ ALLOWED_ATTRIBUTES = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def safelink_callback(attrs, new=False):
|
||||||
|
url = attrs.get((None, 'href'), '/')
|
||||||
|
if not is_safe_url(url):
|
||||||
|
signer = signing.Signer(salt='safe-redirect')
|
||||||
|
attrs[None, 'href'] = reverse('redirect') + '?url=' + urllib.parse.quote(signer.sign(url))
|
||||||
|
attrs[None, 'target'] = '_blank'
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def rich_text(text: str, **kwargs):
|
def rich_text(text: str, **kwargs):
|
||||||
"""
|
"""
|
||||||
@@ -52,5 +67,5 @@ def rich_text(text: str, **kwargs):
|
|||||||
markdown.markdown(text),
|
markdown.markdown(text),
|
||||||
tags=ALLOWED_TAGS,
|
tags=ALLOWED_TAGS,
|
||||||
attributes=ALLOWED_ATTRIBUTES,
|
attributes=ALLOWED_ATTRIBUTES,
|
||||||
))
|
), callbacks=DEFAULT_CALLBACKS + [safelink_callback])
|
||||||
return mark_safe(body_md)
|
return mark_safe(body_md)
|
||||||
|
|||||||
@@ -612,7 +612,7 @@ class DisplaySettingsForm(SettingsForm):
|
|||||||
)
|
)
|
||||||
logo_image = ExtFileField(
|
logo_image = ExtFileField(
|
||||||
label=_('Logo image'),
|
label=_('Logo image'),
|
||||||
ext_whitelist=(".png", ".jpg", ".svg", ".gif", ".jpeg"),
|
ext_whitelist=(".png", ".jpg", ".gif", ".jpeg"),
|
||||||
required=False,
|
required=False,
|
||||||
help_text=_('If you provide a logo image, we will by default not show your events name and date '
|
help_text=_('If you provide a logo image, we will by default not show your events name and date '
|
||||||
'in the page header. We will show your logo with a maximal height of 120 pixels.')
|
'in the page header. We will show your logo with a maximal height of 120 pixels.')
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ class OrganizerSettingsForm(SettingsForm):
|
|||||||
|
|
||||||
organizer_logo_image = ExtFileField(
|
organizer_logo_image = ExtFileField(
|
||||||
label=_('Logo image'),
|
label=_('Logo image'),
|
||||||
ext_whitelist=(".png", ".jpg", ".svg", ".gif", ".jpeg"),
|
ext_whitelist=(".png", ".jpg", ".gif", ".jpeg"),
|
||||||
required=False,
|
required=False,
|
||||||
help_text=_('If you provide a logo image, we will by default not show your organization name '
|
help_text=_('If you provide a logo image, we will by default not show your organization name '
|
||||||
'in the page header. We will show your logo with a maximal height of 120 pixels.')
|
'in the page header. We will show your logo with a maximal height of 120 pixels.')
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{% extends "pretixcontrol/items/base.html" %}
|
{% extends "pretixcontrol/items/base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
|
{% load escapejson %}
|
||||||
{% load formset_tags %}
|
{% load formset_tags %}
|
||||||
{% block title %}{% blocktrans with name=question.question %}Question: {{ name }}{% endblocktrans %}{% endblock %}
|
{% block title %}{% blocktrans with name=question.question %}Question: {{ name }}{% endblocktrans %}{% endblock %}
|
||||||
{% block inside %}
|
{% block inside %}
|
||||||
@@ -58,7 +59,7 @@
|
|||||||
<div class="chart" id="question_chart" data-type="{{ question.type }}">
|
<div class="chart" id="question_chart" data-type="{{ question.type }}">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<script type="application/json" id="question-chart-data">{{ stats_json|safe }}</script>
|
<script type="application/json" id="question-chart-data">{{ stats_json|escapejson }}</script>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-5 col-xs-12">
|
<div class="col-md-5 col-xs-12">
|
||||||
<table class="table table-bordered table-hover">
|
<table class="table table-bordered table-hover">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{% extends "pretixcontrol/items/base.html" %}
|
{% extends "pretixcontrol/items/base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
|
{% load escapejson %}
|
||||||
{% load eventsignal %}
|
{% load eventsignal %}
|
||||||
{% block title %}{% blocktrans with name=quota.name %}Quota: {{ name }}{% endblocktrans %}{% endblock %}
|
{% block title %}{% blocktrans with name=quota.name %}Quota: {{ name }}{% endblocktrans %}{% endblock %}
|
||||||
{% block inside %}
|
{% block inside %}
|
||||||
@@ -20,7 +21,7 @@
|
|||||||
<div class="chart" id="quota_chart">
|
<div class="chart" id="quota_chart">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<script type="application/json" id="quota-chart-data">{{ quota_chart_data|safe }}</script>
|
<script type="application/json" id="quota-chart-data">{{ quota_chart_data|escapejson }}</script>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-5 col-xs-12">
|
<div class="col-md-5 col-xs-12">
|
||||||
<legend>{% trans "Availability calculation" %}</legend>
|
<legend>{% trans "Availability calculation" %}</legend>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from django.shortcuts import render
|
|||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
from django.utils import formats
|
from django.utils import formats
|
||||||
from django.utils.formats import date_format
|
from django.utils.formats import date_format
|
||||||
|
from django.utils.html import escape
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
@@ -138,7 +139,7 @@ def quota_widgets(sender, **kwargs):
|
|||||||
status, left = q.availability()
|
status, left = q.availability()
|
||||||
widgets.append({
|
widgets.append({
|
||||||
'content': NUM_WIDGET.format(num='{}/{}'.format(left, q.size) if q.size is not None else '\u221e',
|
'content': NUM_WIDGET.format(num='{}/{}'.format(left, q.size) if q.size is not None else '\u221e',
|
||||||
text=_('{quota} left').format(quota=q.name)),
|
text=_('{quota} left').format(quota=escape(q.name))),
|
||||||
'display_size': 'small',
|
'display_size': 'small',
|
||||||
'priority': 50,
|
'priority': 50,
|
||||||
'url': reverse('control:event.items.quotas.show', kwargs={
|
'url': reverse('control:event.items.quotas.show', kwargs={
|
||||||
@@ -269,7 +270,8 @@ def user_event_widgets(**kwargs):
|
|||||||
for event in events:
|
for event in events:
|
||||||
widgets.append({
|
widgets.append({
|
||||||
'content': '<div class="event">{event}<span class="from">{df}</span><span class="to">{dt}</span></div>'.format(
|
'content': '<div class="event">{event}<span class="from">{df}</span><span class="to">{dt}</span></div>'.format(
|
||||||
event=event.name, df=date_format(event.date_from, 'SHORT_DATE_FORMAT') if event.date_from else '',
|
event=escape(event.name),
|
||||||
|
df=date_format(event.date_from, 'SHORT_DATE_FORMAT') if event.date_from else '',
|
||||||
dt=date_format(event.date_to, 'SHORT_DATE_FORMAT') if event.date_to else ''
|
dt=date_format(event.date_to, 'SHORT_DATE_FORMAT') if event.date_to else ''
|
||||||
),
|
),
|
||||||
'display_size': 'small',
|
'display_size': 'small',
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import csv
|
|
||||||
import io
|
import io
|
||||||
|
|
||||||
|
from defusedcsv import csv
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.urlresolvers import resolve, reverse
|
from django.core.urlresolvers import resolve, reverse
|
||||||
|
|||||||
16
src/pretix/helpers/escapejson.py
Normal file
16
src/pretix/helpers/escapejson.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from django.utils import six
|
||||||
|
from django.utils.encoding import force_text
|
||||||
|
from django.utils.functional import keep_lazy
|
||||||
|
from django.utils.safestring import SafeText, mark_safe
|
||||||
|
|
||||||
|
_json_escapes = {
|
||||||
|
ord('>'): '\\u003E',
|
||||||
|
ord('<'): '\\u003C',
|
||||||
|
ord('&'): '\\u0026',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@keep_lazy(six.text_type, SafeText)
|
||||||
|
def escapejson(value):
|
||||||
|
"""Hex encodes characters for use in a application/json type script."""
|
||||||
|
return mark_safe(force_text(value).translate(_json_escapes))
|
||||||
@@ -2,8 +2,9 @@ import time
|
|||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.sessions.middleware import \
|
from django.contrib.sessions.middleware import (
|
||||||
SessionMiddleware as BaseSessionMiddleware
|
SessionMiddleware as BaseSessionMiddleware,
|
||||||
|
)
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.core.exceptions import DisallowedHost
|
from django.core.exceptions import DisallowedHost
|
||||||
from django.core.urlresolvers import set_urlconf
|
from django.core.urlresolvers import set_urlconf
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import csv
|
|
||||||
import io
|
import io
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
from defusedcsv import csv
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.db.models.functions import Coalesce
|
from django.db.models.functions import Coalesce
|
||||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||||
|
|||||||
@@ -17,8 +17,9 @@ from django.views.generic import TemplateView, View
|
|||||||
from pretix.base.models import Checkin, Event, Order, OrderPosition
|
from pretix.base.models import Checkin, Event, Order, OrderPosition
|
||||||
from pretix.control.permissions import EventPermissionRequiredMixin
|
from pretix.control.permissions import EventPermissionRequiredMixin
|
||||||
from pretix.helpers.urls import build_absolute_uri
|
from pretix.helpers.urls import build_absolute_uri
|
||||||
from pretix.multidomain.urlreverse import \
|
from pretix.multidomain.urlreverse import (
|
||||||
build_absolute_uri as event_absolute_uri
|
build_absolute_uri as event_absolute_uri,
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger('pretix.plugins.pretixdroid')
|
logger = logging.getLogger('pretix.plugins.pretixdroid')
|
||||||
API_VERSION = 3
|
API_VERSION = 3
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load compress %}
|
{% load compress %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
|
{% load escapejson %}
|
||||||
{% block title %}{% trans "Statistics" %}{% endblock %}
|
{% block title %}{% trans "Statistics" %}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{% trans "Statistics" %}</h1>
|
<h1>{% trans "Statistics" %}</h1>
|
||||||
@@ -30,9 +31,9 @@
|
|||||||
<div id="obp_chart" class="chart"></div>
|
<div id="obp_chart" class="chart"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script type="application/json" id="obd-data">{{ obd_data|safe }}</script>
|
<script type="application/json" id="obd-data">{{ obd_data|escapejson }}</script>
|
||||||
<script type="application/json" id="rev-data">{{ rev_data|safe }}</script>
|
<script type="application/json" id="rev-data">{{ rev_data|escapejson }}</script>
|
||||||
<script type="application/json" id="obp-data">{{ obp_data|safe }}</script>
|
<script type="application/json" id="obp-data">{{ obp_data|escapejson }}</script>
|
||||||
<script type="application/text" id="currency">{{ request.event.currency }}</script>
|
<script type="application/text" id="currency">{{ request.event.currency }}</script>
|
||||||
<script type="application/javascript" src="{% static "pretixplugins/statistics/statistics.js" %}"></script>
|
<script type="application/javascript" src="{% static "pretixplugins/statistics/statistics.js" %}"></script>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
@@ -132,7 +132,8 @@
|
|||||||
<div class="col-md-8 col-xs-12">
|
<div class="col-md-8 col-xs-12">
|
||||||
{% if item.picture %}
|
{% if item.picture %}
|
||||||
<a href="{{ item.picture.url }}" class="productpicture"
|
<a href="{{ item.picture.url }}" class="productpicture"
|
||||||
data-title="{{ item.name }}"
|
data-title="{{ item.name|force_escape|force_escape }}"
|
||||||
|
{# Yes, double-escape to prevent XSS in lightbox #}
|
||||||
data-lightbox="{{ item.id }}">
|
data-lightbox="{{ item.id }}">
|
||||||
<img src="{{ item.picture|thumbnail_url:'productlist' }}"
|
<img src="{{ item.picture|thumbnail_url:'productlist' }}"
|
||||||
alt="{{ item.name }}"/>
|
alt="{{ item.name }}"/>
|
||||||
@@ -243,7 +244,7 @@
|
|||||||
<div class="col-md-8 col-xs-12">
|
<div class="col-md-8 col-xs-12">
|
||||||
{% if item.picture %}
|
{% if item.picture %}
|
||||||
<a href="{{ item.picture.url }}" class="productpicture"
|
<a href="{{ item.picture.url }}" class="productpicture"
|
||||||
data-title="{{ item.name }}"
|
data-title="{{ item.name|force_escape|force_escape }}"
|
||||||
data-lightbox="{{ item.id }}">
|
data-lightbox="{{ item.id }}">
|
||||||
<img src="{{ item.picture|thumbnail_url:'productlist' }}"
|
<img src="{{ item.picture|thumbnail_url:'productlist' }}"
|
||||||
alt="{{ item.name }}"/>
|
alt="{{ item.name }}"/>
|
||||||
|
|||||||
@@ -29,7 +29,8 @@
|
|||||||
<div class="col-md-8 col-xs-12">
|
<div class="col-md-8 col-xs-12">
|
||||||
{% if item.picture %}
|
{% if item.picture %}
|
||||||
<a href="{{ item.picture.url }}" class="productpicture"
|
<a href="{{ item.picture.url }}" class="productpicture"
|
||||||
data-title="{{ item.name }}"
|
data-title="{{ item.name|force_escape|force_escape }}"
|
||||||
|
{# Yes, double-escape to prevent XSS in lightbox #}
|
||||||
data-lightbox="{{ item.id }}">
|
data-lightbox="{{ item.id }}">
|
||||||
<img src="{{ item.picture|thumbnail_url:'productlist' }}"
|
<img src="{{ item.picture|thumbnail_url:'productlist' }}"
|
||||||
alt="{{ item.name }}"/>
|
alt="{{ item.name }}"/>
|
||||||
@@ -116,7 +117,8 @@
|
|||||||
<div class="col-md-8 col-xs-12">
|
<div class="col-md-8 col-xs-12">
|
||||||
{% if item.picture %}
|
{% if item.picture %}
|
||||||
<a href="{{ item.picture.url }}" class="productpicture"
|
<a href="{{ item.picture.url }}" class="productpicture"
|
||||||
data-title="{{ item.name }}"
|
data-title="{{ item.name|force_escape|force_escape }}"
|
||||||
|
{# Yes, double-escape to prevent XSS in lightbox #}
|
||||||
data-lightbox="{{ item.id }}">
|
data-lightbox="{{ item.id }}">
|
||||||
<img src="{{ item.picture|thumbnail_url:'productlist' }}"
|
<img src="{{ item.picture|thumbnail_url:'productlist' }}"
|
||||||
alt="{{ item.name }}"/>
|
alt="{{ item.name }}"/>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* @license
|
/* @license
|
||||||
morris.js v0.5.0
|
morris.js v0.5.1
|
||||||
Copyright 2014 Olly Smith All rights reserved.
|
Copyright 2014 Olly Smith All rights reserved.
|
||||||
Licensed under the BSD-2-Clause License.
|
Licensed under the BSD-2-Clause License.
|
||||||
*/
|
*/
|
||||||
@@ -74,6 +74,7 @@ Licensed under the BSD-2-Clause License.
|
|||||||
__extends(Grid, _super);
|
__extends(Grid, _super);
|
||||||
|
|
||||||
function Grid(options) {
|
function Grid(options) {
|
||||||
|
this.hasToShow = __bind(this.hasToShow, this);
|
||||||
this.resizeHandler = __bind(this.resizeHandler, this);
|
this.resizeHandler = __bind(this.resizeHandler, this);
|
||||||
var _this = this;
|
var _this = this;
|
||||||
if (typeof options.element === 'string') {
|
if (typeof options.element === 'string') {
|
||||||
@@ -197,7 +198,7 @@ Licensed under the BSD-2-Clause License.
|
|||||||
};
|
};
|
||||||
|
|
||||||
Grid.prototype.setData = function(data, redraw) {
|
Grid.prototype.setData = function(data, redraw) {
|
||||||
var e, idx, index, maxGoal, minGoal, ret, row, step, total, y, ykey, ymax, ymin, yval, _ref;
|
var e, flatEvents, from, idx, index, maxGoal, minGoal, ret, row, step, to, total, y, ykey, ymax, ymin, yval, _i, _len, _ref, _ref1;
|
||||||
if (redraw == null) {
|
if (redraw == null) {
|
||||||
redraw = true;
|
redraw = true;
|
||||||
}
|
}
|
||||||
@@ -254,7 +255,7 @@ Licensed under the BSD-2-Clause License.
|
|||||||
if ((yval != null) && typeof yval !== 'number') {
|
if ((yval != null) && typeof yval !== 'number') {
|
||||||
yval = null;
|
yval = null;
|
||||||
}
|
}
|
||||||
if (yval != null) {
|
if ((yval != null) && this.hasToShow(idx)) {
|
||||||
if (this.cumulative) {
|
if (this.cumulative) {
|
||||||
total += yval;
|
total += yval;
|
||||||
} else {
|
} else {
|
||||||
@@ -288,21 +289,24 @@ Licensed under the BSD-2-Clause License.
|
|||||||
this.events = [];
|
this.events = [];
|
||||||
if (this.options.events.length > 0) {
|
if (this.options.events.length > 0) {
|
||||||
if (this.options.parseTime) {
|
if (this.options.parseTime) {
|
||||||
this.events = (function() {
|
_ref = this.options.events;
|
||||||
var _i, _len, _ref, _results;
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||||
_ref = this.options.events;
|
e = _ref[_i];
|
||||||
_results = [];
|
if (e instanceof Array) {
|
||||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
from = e[0], to = e[1];
|
||||||
e = _ref[_i];
|
this.events.push([Morris.parseDate(from), Morris.parseDate(to)]);
|
||||||
_results.push(Morris.parseDate(e));
|
} else {
|
||||||
|
this.events.push(Morris.parseDate(e));
|
||||||
}
|
}
|
||||||
return _results;
|
}
|
||||||
}).call(this);
|
|
||||||
} else {
|
} else {
|
||||||
this.events = this.options.events;
|
this.events = this.options.events;
|
||||||
}
|
}
|
||||||
this.xmax = Math.max(this.xmax, Math.max.apply(Math, this.events));
|
flatEvents = $.map(this.events, function(e) {
|
||||||
this.xmin = Math.min(this.xmin, Math.min.apply(Math, this.events));
|
return e;
|
||||||
|
});
|
||||||
|
this.xmax = Math.max(this.xmax, Math.max.apply(Math, flatEvents));
|
||||||
|
this.xmin = Math.min(this.xmin, Math.min.apply(Math, flatEvents));
|
||||||
}
|
}
|
||||||
if (this.xmin === this.xmax) {
|
if (this.xmin === this.xmax) {
|
||||||
this.xmin -= 1;
|
this.xmin -= 1;
|
||||||
@@ -316,7 +320,7 @@ Licensed under the BSD-2-Clause License.
|
|||||||
}
|
}
|
||||||
this.ymax += 1;
|
this.ymax += 1;
|
||||||
}
|
}
|
||||||
if (((_ref = this.options.axes) === true || _ref === 'both' || _ref === 'y') || this.options.grid === true) {
|
if (((_ref1 = this.options.axes) === true || _ref1 === 'both' || _ref1 === 'y') || this.options.grid === true) {
|
||||||
if (this.options.ymax === this.gridDefaults.ymax && this.options.ymin === this.gridDefaults.ymin) {
|
if (this.options.ymax === this.gridDefaults.ymax && this.options.ymin === this.gridDefaults.ymin) {
|
||||||
this.grid = this.autoGridLines(this.ymin, this.ymax, this.options.numLines);
|
this.grid = this.autoGridLines(this.ymin, this.ymax, this.options.numLines);
|
||||||
this.ymin = Math.min(this.ymin, this.grid[0]);
|
this.ymin = Math.min(this.ymin, this.grid[0]);
|
||||||
@@ -324,9 +328,9 @@ Licensed under the BSD-2-Clause License.
|
|||||||
} else {
|
} else {
|
||||||
step = (this.ymax - this.ymin) / (this.options.numLines - 1);
|
step = (this.ymax - this.ymin) / (this.options.numLines - 1);
|
||||||
this.grid = (function() {
|
this.grid = (function() {
|
||||||
var _i, _ref1, _ref2, _results;
|
var _j, _ref2, _ref3, _results;
|
||||||
_results = [];
|
_results = [];
|
||||||
for (y = _i = _ref1 = this.ymin, _ref2 = this.ymax; step > 0 ? _i <= _ref2 : _i >= _ref2; y = _i += step) {
|
for (y = _j = _ref2 = this.ymin, _ref3 = this.ymax; step > 0 ? _j <= _ref3 : _j >= _ref3; y = _j += step) {
|
||||||
_results.push(y);
|
_results.push(y);
|
||||||
}
|
}
|
||||||
return _results;
|
return _results;
|
||||||
@@ -405,7 +409,7 @@ Licensed under the BSD-2-Clause License.
|
|||||||
};
|
};
|
||||||
|
|
||||||
Grid.prototype._calc = function() {
|
Grid.prototype._calc = function() {
|
||||||
var bottomOffsets, gridLine, h, i, w, yLabelWidths, _ref, _ref1;
|
var angle, bottomOffsets, gridLine, h, i, w, yLabelWidths, _ref, _ref1;
|
||||||
w = this.el.width();
|
w = this.el.width();
|
||||||
h = this.el.height();
|
h = this.el.height();
|
||||||
if (this.elementWidth !== w || this.elementHeight !== h || this.dirty) {
|
if (this.elementWidth !== w || this.elementHeight !== h || this.dirty) {
|
||||||
@@ -427,23 +431,53 @@ Licensed under the BSD-2-Clause License.
|
|||||||
}
|
}
|
||||||
return _results;
|
return _results;
|
||||||
}).call(this);
|
}).call(this);
|
||||||
this.left += Math.max.apply(Math, yLabelWidths);
|
if (!this.options.horizontal) {
|
||||||
|
this.left += Math.max.apply(Math, yLabelWidths);
|
||||||
|
} else {
|
||||||
|
this.bottom -= Math.max.apply(Math, yLabelWidths);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ((_ref1 = this.options.axes) === true || _ref1 === 'both' || _ref1 === 'x') {
|
if ((_ref1 = this.options.axes) === true || _ref1 === 'both' || _ref1 === 'x') {
|
||||||
|
if (!this.options.horizontal) {
|
||||||
|
angle = -this.options.xLabelAngle;
|
||||||
|
} else {
|
||||||
|
angle = -90;
|
||||||
|
}
|
||||||
bottomOffsets = (function() {
|
bottomOffsets = (function() {
|
||||||
var _i, _ref2, _results;
|
var _i, _ref2, _results;
|
||||||
_results = [];
|
_results = [];
|
||||||
for (i = _i = 0, _ref2 = this.data.length; 0 <= _ref2 ? _i < _ref2 : _i > _ref2; i = 0 <= _ref2 ? ++_i : --_i) {
|
for (i = _i = 0, _ref2 = this.data.length; 0 <= _ref2 ? _i < _ref2 : _i > _ref2; i = 0 <= _ref2 ? ++_i : --_i) {
|
||||||
_results.push(this.measureText(this.data[i].text, -this.options.xLabelAngle).height);
|
_results.push(this.measureText(this.data[i].label, angle).height);
|
||||||
}
|
}
|
||||||
return _results;
|
return _results;
|
||||||
}).call(this);
|
}).call(this);
|
||||||
this.bottom -= Math.max.apply(Math, bottomOffsets);
|
if (!this.options.horizontal) {
|
||||||
|
this.bottom -= Math.max.apply(Math, bottomOffsets);
|
||||||
|
} else {
|
||||||
|
this.left += Math.max.apply(Math, bottomOffsets);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.width = Math.max(1, this.right - this.left);
|
this.width = Math.max(1, this.right - this.left);
|
||||||
this.height = Math.max(1, this.bottom - this.top);
|
this.height = Math.max(1, this.bottom - this.top);
|
||||||
this.dx = this.width / (this.xmax - this.xmin);
|
if (!this.options.horizontal) {
|
||||||
this.dy = this.height / (this.ymax - this.ymin);
|
this.dx = this.width / (this.xmax - this.xmin);
|
||||||
|
this.dy = this.height / (this.ymax - this.ymin);
|
||||||
|
this.yStart = this.bottom;
|
||||||
|
this.yEnd = this.top;
|
||||||
|
this.xStart = this.left;
|
||||||
|
this.xEnd = this.right;
|
||||||
|
this.xSize = this.width;
|
||||||
|
this.ySize = this.height;
|
||||||
|
} else {
|
||||||
|
this.dx = this.height / (this.xmax - this.xmin);
|
||||||
|
this.dy = this.width / (this.ymax - this.ymin);
|
||||||
|
this.yStart = this.left;
|
||||||
|
this.yEnd = this.right;
|
||||||
|
this.xStart = this.top;
|
||||||
|
this.xEnd = this.bottom;
|
||||||
|
this.xSize = this.height;
|
||||||
|
this.ySize = this.width;
|
||||||
|
}
|
||||||
if (this.calc) {
|
if (this.calc) {
|
||||||
return this.calc();
|
return this.calc();
|
||||||
}
|
}
|
||||||
@@ -451,14 +485,18 @@ Licensed under the BSD-2-Clause License.
|
|||||||
};
|
};
|
||||||
|
|
||||||
Grid.prototype.transY = function(y) {
|
Grid.prototype.transY = function(y) {
|
||||||
return this.bottom - (y - this.ymin) * this.dy;
|
if (!this.options.horizontal) {
|
||||||
|
return this.bottom - (y - this.ymin) * this.dy;
|
||||||
|
} else {
|
||||||
|
return this.left + (y - this.ymin) * this.dy;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Grid.prototype.transX = function(x) {
|
Grid.prototype.transX = function(x) {
|
||||||
if (this.data.length === 1) {
|
if (this.data.length === 1) {
|
||||||
return (this.left + this.right) / 2;
|
return (this.xStart + this.xEnd) / 2;
|
||||||
} else {
|
} else {
|
||||||
return this.left + (x - this.xmin) * this.dx;
|
return this.xStart + (x - this.xmin) * this.dx;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -485,32 +523,50 @@ Licensed under the BSD-2-Clause License.
|
|||||||
};
|
};
|
||||||
|
|
||||||
Grid.prototype.yAxisFormat = function(label) {
|
Grid.prototype.yAxisFormat = function(label) {
|
||||||
return this.yLabelFormat(label);
|
return this.yLabelFormat(label, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
Grid.prototype.yLabelFormat = function(label) {
|
Grid.prototype.yLabelFormat = function(label, i) {
|
||||||
if (typeof this.options.yLabelFormat === 'function') {
|
if (typeof this.options.yLabelFormat === 'function') {
|
||||||
return this.options.yLabelFormat(label);
|
return this.options.yLabelFormat(label, i);
|
||||||
} else {
|
} else {
|
||||||
return "" + this.options.preUnits + (Morris.commas(label)) + this.options.postUnits;
|
return "" + this.options.preUnits + (Morris.commas(label)) + this.options.postUnits;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Grid.prototype.getYAxisLabelX = function() {
|
||||||
|
return this.left - this.options.padding / 2;
|
||||||
|
};
|
||||||
|
|
||||||
Grid.prototype.drawGrid = function() {
|
Grid.prototype.drawGrid = function() {
|
||||||
var lineY, y, _i, _len, _ref, _ref1, _ref2, _results;
|
var basePos, lineY, pos, _i, _len, _ref, _ref1, _ref2, _results;
|
||||||
if (this.options.grid === false && ((_ref = this.options.axes) !== true && _ref !== 'both' && _ref !== 'y')) {
|
if (this.options.grid === false && ((_ref = this.options.axes) !== true && _ref !== 'both' && _ref !== 'y')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!this.options.horizontal) {
|
||||||
|
basePos = this.getYAxisLabelX();
|
||||||
|
} else {
|
||||||
|
basePos = this.getXAxisLabelY();
|
||||||
|
}
|
||||||
_ref1 = this.grid;
|
_ref1 = this.grid;
|
||||||
_results = [];
|
_results = [];
|
||||||
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
|
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
|
||||||
lineY = _ref1[_i];
|
lineY = _ref1[_i];
|
||||||
y = this.transY(lineY);
|
pos = this.transY(lineY);
|
||||||
if ((_ref2 = this.options.axes) === true || _ref2 === 'both' || _ref2 === 'y') {
|
if ((_ref2 = this.options.axes) === true || _ref2 === 'both' || _ref2 === 'y') {
|
||||||
this.drawYAxisLabel(this.left - this.options.padding / 2, y, this.yAxisFormat(lineY));
|
if (!this.options.horizontal) {
|
||||||
|
this.drawYAxisLabel(basePos, pos, this.yAxisFormat(lineY));
|
||||||
|
} else {
|
||||||
|
this.drawXAxisLabel(pos, basePos, this.yAxisFormat(lineY));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this.options.grid) {
|
if (this.options.grid) {
|
||||||
_results.push(this.drawGridLine("M" + this.left + "," + y + "H" + (this.left + this.width)));
|
pos = Math.floor(pos) + 0.5;
|
||||||
|
if (!this.options.horizontal) {
|
||||||
|
_results.push(this.drawGridLine("M" + this.xStart + "," + pos + "H" + this.xEnd));
|
||||||
|
} else {
|
||||||
|
_results.push(this.drawGridLine("M" + pos + "," + this.xStart + "V" + this.xEnd));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
_results.push(void 0);
|
_results.push(void 0);
|
||||||
}
|
}
|
||||||
@@ -543,11 +599,42 @@ Licensed under the BSD-2-Clause License.
|
|||||||
};
|
};
|
||||||
|
|
||||||
Grid.prototype.drawGoal = function(goal, color) {
|
Grid.prototype.drawGoal = function(goal, color) {
|
||||||
return this.raphael.path("M" + this.left + "," + (this.transY(goal)) + "H" + this.right).attr('stroke', color).attr('stroke-width', this.options.goalStrokeWidth);
|
var path, y;
|
||||||
|
y = Math.floor(this.transY(goal)) + 0.5;
|
||||||
|
if (!this.options.horizontal) {
|
||||||
|
path = "M" + this.xStart + "," + y + "H" + this.xEnd;
|
||||||
|
} else {
|
||||||
|
path = "M" + y + "," + this.xStart + "V" + this.xEnd;
|
||||||
|
}
|
||||||
|
return this.raphael.path(path).attr('stroke', color).attr('stroke-width', this.options.goalStrokeWidth);
|
||||||
};
|
};
|
||||||
|
|
||||||
Grid.prototype.drawEvent = function(event, color) {
|
Grid.prototype.drawEvent = function(event, color) {
|
||||||
return this.raphael.path("M" + (this.transX(event)) + "," + this.bottom + "V" + this.top).attr('stroke', color).attr('stroke-width', this.options.eventStrokeWidth);
|
var from, path, to, x;
|
||||||
|
if (event instanceof Array) {
|
||||||
|
from = event[0], to = event[1];
|
||||||
|
from = Math.floor(this.transX(from)) + 0.5;
|
||||||
|
to = Math.floor(this.transX(to)) + 0.5;
|
||||||
|
if (!this.options.horizontal) {
|
||||||
|
return this.raphael.rect(from, this.yEnd, to - from, this.yStart - this.yEnd).attr({
|
||||||
|
fill: color,
|
||||||
|
stroke: false
|
||||||
|
}).toBack();
|
||||||
|
} else {
|
||||||
|
return this.raphael.rect(this.yStart, from, this.yEnd - this.yStart, to - from).attr({
|
||||||
|
fill: color,
|
||||||
|
stroke: false
|
||||||
|
}).toBack();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
x = Math.floor(this.transX(event)) + 0.5;
|
||||||
|
if (!this.options.horizontal) {
|
||||||
|
path = "M" + x + "," + this.yStart + "V" + this.yEnd;
|
||||||
|
} else {
|
||||||
|
path = "M" + this.yStart + "," + x + "H" + this.yEnd;
|
||||||
|
}
|
||||||
|
return this.raphael.path(path).attr('stroke', color).attr('stroke-width', this.options.eventStrokeWidth);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Grid.prototype.drawYAxisLabel = function(xPos, yPos, text) {
|
Grid.prototype.drawYAxisLabel = function(xPos, yPos, text) {
|
||||||
@@ -586,6 +673,10 @@ Licensed under the BSD-2-Clause License.
|
|||||||
return this.redraw();
|
return this.redraw();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Grid.prototype.hasToShow = function(i) {
|
||||||
|
return this.options.shown === true || this.options.shown[i] === true;
|
||||||
|
};
|
||||||
|
|
||||||
return Grid;
|
return Grid;
|
||||||
|
|
||||||
})(Morris.EventEmitter);
|
})(Morris.EventEmitter);
|
||||||
@@ -662,13 +753,13 @@ Licensed under the BSD-2-Clause License.
|
|||||||
this.options.parent.append(this.el);
|
this.options.parent.append(this.el);
|
||||||
}
|
}
|
||||||
|
|
||||||
Hover.prototype.update = function(html, x, y) {
|
Hover.prototype.update = function(html, x, y, centre_y) {
|
||||||
if (!html) {
|
if (!html) {
|
||||||
return this.hide();
|
return this.hide();
|
||||||
} else {
|
} else {
|
||||||
this.html(html);
|
this.html(html);
|
||||||
this.show();
|
this.show();
|
||||||
return this.moveTo(x, y);
|
return this.moveTo(x, y, centre_y);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -676,7 +767,7 @@ Licensed under the BSD-2-Clause License.
|
|||||||
return this.el.html(content);
|
return this.el.html(content);
|
||||||
};
|
};
|
||||||
|
|
||||||
Hover.prototype.moveTo = function(x, y) {
|
Hover.prototype.moveTo = function(x, y, centre_y) {
|
||||||
var hoverHeight, hoverWidth, left, parentHeight, parentWidth, top;
|
var hoverHeight, hoverWidth, left, parentHeight, parentWidth, top;
|
||||||
parentWidth = this.options.parent.innerWidth();
|
parentWidth = this.options.parent.innerWidth();
|
||||||
parentHeight = this.options.parent.innerHeight();
|
parentHeight = this.options.parent.innerHeight();
|
||||||
@@ -684,11 +775,18 @@ Licensed under the BSD-2-Clause License.
|
|||||||
hoverHeight = this.el.outerHeight();
|
hoverHeight = this.el.outerHeight();
|
||||||
left = Math.min(Math.max(0, x - hoverWidth / 2), parentWidth - hoverWidth);
|
left = Math.min(Math.max(0, x - hoverWidth / 2), parentWidth - hoverWidth);
|
||||||
if (y != null) {
|
if (y != null) {
|
||||||
top = y - hoverHeight - 10;
|
if (centre_y === true) {
|
||||||
if (top < 0) {
|
top = y - hoverHeight / 2;
|
||||||
top = y + 10;
|
if (top < 0) {
|
||||||
if (top + hoverHeight > parentHeight) {
|
top = 0;
|
||||||
top = parentHeight / 2 - hoverHeight / 2;
|
}
|
||||||
|
} else {
|
||||||
|
top = y - hoverHeight - 10;
|
||||||
|
if (top < 0) {
|
||||||
|
top = y + 10;
|
||||||
|
if (top + hoverHeight > parentHeight) {
|
||||||
|
top = parentHeight / 2 - hoverHeight / 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -745,10 +843,14 @@ Licensed under the BSD-2-Clause License.
|
|||||||
pointStrokeColors: ['#ffffff'],
|
pointStrokeColors: ['#ffffff'],
|
||||||
pointFillColors: [],
|
pointFillColors: [],
|
||||||
smooth: true,
|
smooth: true,
|
||||||
|
shown: true,
|
||||||
xLabels: 'auto',
|
xLabels: 'auto',
|
||||||
xLabelFormat: null,
|
xLabelFormat: null,
|
||||||
xLabelMargin: 24,
|
xLabelMargin: 24,
|
||||||
hideHover: false
|
hideHover: false,
|
||||||
|
trendLine: false,
|
||||||
|
trendLineWidth: 2,
|
||||||
|
trendLineColors: ['#689bc3', '#a2b3bf', '#64b764']
|
||||||
};
|
};
|
||||||
|
|
||||||
Line.prototype.calc = function() {
|
Line.prototype.calc = function() {
|
||||||
@@ -840,11 +942,15 @@ Licensed under the BSD-2-Clause License.
|
|||||||
Line.prototype.hoverContentForRow = function(index) {
|
Line.prototype.hoverContentForRow = function(index) {
|
||||||
var content, j, row, y, _i, _len, _ref;
|
var content, j, row, y, _i, _len, _ref;
|
||||||
row = this.data[index];
|
row = this.data[index];
|
||||||
content = "<div class='morris-hover-row-label'>" + row.label + "</div>";
|
content = $("<div class='morris-hover-row-label'>").text(row.label);
|
||||||
|
content = content.prop('outerHTML');
|
||||||
_ref = row.y;
|
_ref = row.y;
|
||||||
for (j = _i = 0, _len = _ref.length; _i < _len; j = ++_i) {
|
for (j = _i = 0, _len = _ref.length; _i < _len; j = ++_i) {
|
||||||
y = _ref[j];
|
y = _ref[j];
|
||||||
content += "<div class='morris-hover-point' style='color: " + (this.colorFor(row, j, 'label')) + "'>\n " + this.options.labels[j] + ":\n " + (this.yLabelFormat(y)) + "\n</div>";
|
if (this.options.labels[j] === false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
content += "<div class='morris-hover-point' style='color: " + (this.colorFor(row, j, 'label')) + "'>\n " + this.options.labels[j] + ":\n " + (this.yLabelFormat(y, j)) + "\n</div>";
|
||||||
}
|
}
|
||||||
if (typeof this.options.hoverCallback === 'function') {
|
if (typeof this.options.hoverCallback === 'function') {
|
||||||
content = this.options.hoverCallback(index, this.options, content, row.src);
|
content = this.options.hoverCallback(index, this.options, content, row.src);
|
||||||
@@ -954,11 +1060,20 @@ Licensed under the BSD-2-Clause License.
|
|||||||
var i, _i, _j, _ref, _ref1, _results;
|
var i, _i, _j, _ref, _ref1, _results;
|
||||||
this.seriesPoints = [];
|
this.seriesPoints = [];
|
||||||
for (i = _i = _ref = this.options.ykeys.length - 1; _ref <= 0 ? _i <= 0 : _i >= 0; i = _ref <= 0 ? ++_i : --_i) {
|
for (i = _i = _ref = this.options.ykeys.length - 1; _ref <= 0 ? _i <= 0 : _i >= 0; i = _ref <= 0 ? ++_i : --_i) {
|
||||||
this._drawLineFor(i);
|
if (this.hasToShow(i)) {
|
||||||
|
if (this.options.trendLine !== false && this.options.trendLine === true || this.options.trendLine[i] === true) {
|
||||||
|
this._drawTrendLine(i);
|
||||||
|
}
|
||||||
|
this._drawLineFor(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_results = [];
|
_results = [];
|
||||||
for (i = _j = _ref1 = this.options.ykeys.length - 1; _ref1 <= 0 ? _j <= 0 : _j >= 0; i = _ref1 <= 0 ? ++_j : --_j) {
|
for (i = _j = _ref1 = this.options.ykeys.length - 1; _ref1 <= 0 ? _j <= 0 : _j >= 0; i = _ref1 <= 0 ? ++_j : --_j) {
|
||||||
_results.push(this._drawPointFor(i));
|
if (this.hasToShow(i)) {
|
||||||
|
_results.push(this._drawPointFor(i));
|
||||||
|
} else {
|
||||||
|
_results.push(void 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return _results;
|
return _results;
|
||||||
};
|
};
|
||||||
@@ -987,6 +1102,38 @@ Licensed under the BSD-2-Clause License.
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Line.prototype._drawTrendLine = function(index) {
|
||||||
|
var a, b, data, datapoints, path, sum_x, sum_xx, sum_xy, sum_y, val, x, y, _i, _len, _ref;
|
||||||
|
sum_x = 0;
|
||||||
|
sum_y = 0;
|
||||||
|
sum_xx = 0;
|
||||||
|
sum_xy = 0;
|
||||||
|
datapoints = 0;
|
||||||
|
_ref = this.data;
|
||||||
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||||
|
val = _ref[_i];
|
||||||
|
x = val.x;
|
||||||
|
y = val.y[index];
|
||||||
|
if (y === void 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
datapoints += 1;
|
||||||
|
sum_x += x;
|
||||||
|
sum_y += y;
|
||||||
|
sum_xx += x * x;
|
||||||
|
sum_xy += x * y;
|
||||||
|
}
|
||||||
|
a = (datapoints * sum_xy - sum_x * sum_y) / (datapoints * sum_xx - sum_x * sum_x);
|
||||||
|
b = (sum_y / datapoints) - ((a * sum_x) / datapoints);
|
||||||
|
data = [{}, {}];
|
||||||
|
data[0].x = this.transX(this.data[0].x);
|
||||||
|
data[0].y = this.transY(this.data[0].x * a + b);
|
||||||
|
data[1].x = this.transX(this.data[this.data.length - 1].x);
|
||||||
|
data[1].y = this.transY(this.data[this.data.length - 1].x * a + b);
|
||||||
|
path = Morris.Line.createPath(data, false, this.bottom);
|
||||||
|
return path = this.raphael.path(path).attr('stroke', this.colorFor(null, index, 'trendLine')).attr('stroke-width', this.options.trendLineWidth);
|
||||||
|
};
|
||||||
|
|
||||||
Line.createPath = function(coords, smooth, bottom) {
|
Line.createPath = function(coords, smooth, bottom) {
|
||||||
var coord, g, grads, i, ix, lg, path, prevCoord, x1, x2, y1, y2, _i, _len;
|
var coord, g, grads, i, ix, lg, path, prevCoord, x1, x2, y1, y2, _i, _len;
|
||||||
path = "";
|
path = "";
|
||||||
@@ -1078,8 +1225,10 @@ Licensed under the BSD-2-Clause License.
|
|||||||
return this.options.lineColors.call(this, row, sidx, type);
|
return this.options.lineColors.call(this, row, sidx, type);
|
||||||
} else if (type === 'point') {
|
} else if (type === 'point') {
|
||||||
return this.options.pointFillColors[sidx % this.options.pointFillColors.length] || this.options.lineColors[sidx % this.options.lineColors.length];
|
return this.options.pointFillColors[sidx % this.options.pointFillColors.length] || this.options.lineColors[sidx % this.options.lineColors.length];
|
||||||
} else {
|
} else if (type === 'line') {
|
||||||
return this.options.lineColors[sidx % this.options.lineColors.length];
|
return this.options.lineColors[sidx % this.options.lineColors.length];
|
||||||
|
} else {
|
||||||
|
return this.options.trendLineColors[sidx % this.options.trendLineColors.length];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1120,6 +1269,9 @@ Licensed under the BSD-2-Clause License.
|
|||||||
};
|
};
|
||||||
|
|
||||||
Line.prototype.pointGrowSeries = function(index) {
|
Line.prototype.pointGrowSeries = function(index) {
|
||||||
|
if (this.pointSizeForSeries(index) === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
return Raphael.animation({
|
return Raphael.animation({
|
||||||
r: this.pointSizeForSeries(index) + 3
|
r: this.pointSizeForSeries(index) + 3
|
||||||
}, 25, 'linear');
|
}, 25, 'linear');
|
||||||
@@ -1409,7 +1561,9 @@ Licensed under the BSD-2-Clause License.
|
|||||||
barColors: ['#0b62a4', '#7a92a3', '#4da74d', '#afd8f8', '#edc240', '#cb4b4b', '#9440ed'],
|
barColors: ['#0b62a4', '#7a92a3', '#4da74d', '#afd8f8', '#edc240', '#cb4b4b', '#9440ed'],
|
||||||
barOpacity: 1.0,
|
barOpacity: 1.0,
|
||||||
barRadius: [0, 0, 0, 0],
|
barRadius: [0, 0, 0, 0],
|
||||||
xLabelMargin: 50
|
xLabelMargin: 50,
|
||||||
|
horizontal: false,
|
||||||
|
shown: true
|
||||||
};
|
};
|
||||||
|
|
||||||
Bar.prototype.calc = function() {
|
Bar.prototype.calc = function() {
|
||||||
@@ -1426,7 +1580,7 @@ Licensed under the BSD-2-Clause License.
|
|||||||
_results = [];
|
_results = [];
|
||||||
for (idx = _i = 0, _len = _ref.length; _i < _len; idx = ++_i) {
|
for (idx = _i = 0, _len = _ref.length; _i < _len; idx = ++_i) {
|
||||||
row = _ref[idx];
|
row = _ref[idx];
|
||||||
row._x = this.left + this.width * (idx + 0.5) / this.data.length;
|
row._x = this.xStart + this.xSize * (idx + 0.5) / this.data.length;
|
||||||
_results.push(row._y = (function() {
|
_results.push(row._y = (function() {
|
||||||
var _j, _len1, _ref1, _results1;
|
var _j, _len1, _ref1, _results1;
|
||||||
_ref1 = row.y;
|
_ref1 = row.y;
|
||||||
@@ -1454,28 +1608,54 @@ Licensed under the BSD-2-Clause License.
|
|||||||
};
|
};
|
||||||
|
|
||||||
Bar.prototype.drawXAxis = function() {
|
Bar.prototype.drawXAxis = function() {
|
||||||
var i, label, labelBox, margin, offset, prevAngleMargin, prevLabelMargin, row, textBox, ypos, _i, _ref, _results;
|
var angle, basePos, i, label, labelBox, margin, maxSize, offset, prevAngleMargin, prevLabelMargin, row, size, startPos, textBox, _i, _ref, _results;
|
||||||
ypos = this.bottom + (this.options.xAxisLabelTopPadding || this.options.padding / 2);
|
if (!this.options.horizontal) {
|
||||||
|
basePos = this.getXAxisLabelY();
|
||||||
|
} else {
|
||||||
|
basePos = this.getYAxisLabelX();
|
||||||
|
}
|
||||||
prevLabelMargin = null;
|
prevLabelMargin = null;
|
||||||
prevAngleMargin = null;
|
prevAngleMargin = null;
|
||||||
_results = [];
|
_results = [];
|
||||||
for (i = _i = 0, _ref = this.data.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
|
for (i = _i = 0, _ref = this.data.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
|
||||||
row = this.data[this.data.length - 1 - i];
|
row = this.data[this.data.length - 1 - i];
|
||||||
label = this.drawXAxisLabel(row._x, ypos, row.label);
|
if (!this.options.horizontal) {
|
||||||
|
label = this.drawXAxisLabel(row._x, basePos, row.label);
|
||||||
|
} else {
|
||||||
|
label = this.drawYAxisLabel(basePos, row._x - 0.5 * this.options.gridTextSize, row.label);
|
||||||
|
}
|
||||||
|
if (!this.options.horizontal) {
|
||||||
|
angle = this.options.xLabelAngle;
|
||||||
|
} else {
|
||||||
|
angle = 0;
|
||||||
|
}
|
||||||
textBox = label.getBBox();
|
textBox = label.getBBox();
|
||||||
label.transform("r" + (-this.options.xLabelAngle));
|
label.transform("r" + (-angle));
|
||||||
labelBox = label.getBBox();
|
labelBox = label.getBBox();
|
||||||
label.transform("t0," + (labelBox.height / 2) + "...");
|
label.transform("t0," + (labelBox.height / 2) + "...");
|
||||||
if (this.options.xLabelAngle !== 0) {
|
if (angle !== 0) {
|
||||||
offset = -0.5 * textBox.width * Math.cos(this.options.xLabelAngle * Math.PI / 180.0);
|
offset = -0.5 * textBox.width * Math.cos(angle * Math.PI / 180.0);
|
||||||
label.transform("t" + offset + ",0...");
|
label.transform("t" + offset + ",0...");
|
||||||
}
|
}
|
||||||
if (((prevLabelMargin == null) || prevLabelMargin >= labelBox.x + labelBox.width || (prevAngleMargin != null) && prevAngleMargin >= labelBox.x) && labelBox.x >= 0 && (labelBox.x + labelBox.width) < this.el.width()) {
|
if (!this.options.horizontal) {
|
||||||
if (this.options.xLabelAngle !== 0) {
|
startPos = labelBox.x;
|
||||||
margin = 1.25 * this.options.gridTextSize / Math.sin(this.options.xLabelAngle * Math.PI / 180.0);
|
size = labelBox.width;
|
||||||
prevAngleMargin = labelBox.x - margin;
|
maxSize = this.el.width();
|
||||||
|
} else {
|
||||||
|
startPos = labelBox.y;
|
||||||
|
size = labelBox.height;
|
||||||
|
maxSize = this.el.height();
|
||||||
|
}
|
||||||
|
if (((prevLabelMargin == null) || prevLabelMargin >= startPos + size || (prevAngleMargin != null) && prevAngleMargin >= startPos) && startPos >= 0 && (startPos + size) < maxSize) {
|
||||||
|
if (angle !== 0) {
|
||||||
|
margin = 1.25 * this.options.gridTextSize / Math.sin(angle * Math.PI / 180.0);
|
||||||
|
prevAngleMargin = startPos - margin;
|
||||||
|
}
|
||||||
|
if (!this.options.horizontal) {
|
||||||
|
_results.push(prevLabelMargin = startPos - this.options.xLabelMargin);
|
||||||
|
} else {
|
||||||
|
_results.push(prevLabelMargin = startPos);
|
||||||
}
|
}
|
||||||
_results.push(prevLabelMargin = labelBox.x - this.options.xLabelMargin);
|
|
||||||
} else {
|
} else {
|
||||||
_results.push(label.remove());
|
_results.push(label.remove());
|
||||||
}
|
}
|
||||||
@@ -1483,10 +1663,23 @@ Licensed under the BSD-2-Clause License.
|
|||||||
return _results;
|
return _results;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Bar.prototype.getXAxisLabelY = function() {
|
||||||
|
return this.bottom + (this.options.xAxisLabelTopPadding || this.options.padding / 2);
|
||||||
|
};
|
||||||
|
|
||||||
Bar.prototype.drawSeries = function() {
|
Bar.prototype.drawSeries = function() {
|
||||||
var barWidth, bottom, groupWidth, idx, lastTop, left, leftPadding, numBars, row, sidx, size, spaceLeft, top, ypos, zeroPos;
|
var barWidth, bottom, groupWidth, i, idx, lastTop, left, leftPadding, numBars, row, sidx, size, spaceLeft, top, ypos, zeroPos, _i, _ref;
|
||||||
groupWidth = this.width / this.options.data.length;
|
groupWidth = this.xSize / this.options.data.length;
|
||||||
numBars = this.options.stacked ? 1 : this.options.ykeys.length;
|
if (this.options.stacked) {
|
||||||
|
numBars = 1;
|
||||||
|
} else {
|
||||||
|
numBars = 0;
|
||||||
|
for (i = _i = 0, _ref = this.options.ykeys.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
|
||||||
|
if (this.hasToShow(i)) {
|
||||||
|
numBars += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
barWidth = (groupWidth * this.options.barSizeRatio - this.options.barGap * (numBars - 1)) / numBars;
|
barWidth = (groupWidth * this.options.barSizeRatio - this.options.barGap * (numBars - 1)) / numBars;
|
||||||
if (this.options.barSize) {
|
if (this.options.barSize) {
|
||||||
barWidth = Math.min(barWidth, this.options.barSize);
|
barWidth = Math.min(barWidth, this.options.barSize);
|
||||||
@@ -1495,18 +1688,21 @@ Licensed under the BSD-2-Clause License.
|
|||||||
leftPadding = spaceLeft / 2;
|
leftPadding = spaceLeft / 2;
|
||||||
zeroPos = this.ymin <= 0 && this.ymax >= 0 ? this.transY(0) : null;
|
zeroPos = this.ymin <= 0 && this.ymax >= 0 ? this.transY(0) : null;
|
||||||
return this.bars = (function() {
|
return this.bars = (function() {
|
||||||
var _i, _len, _ref, _results;
|
var _j, _len, _ref1, _results;
|
||||||
_ref = this.data;
|
_ref1 = this.data;
|
||||||
_results = [];
|
_results = [];
|
||||||
for (idx = _i = 0, _len = _ref.length; _i < _len; idx = ++_i) {
|
for (idx = _j = 0, _len = _ref1.length; _j < _len; idx = ++_j) {
|
||||||
row = _ref[idx];
|
row = _ref1[idx];
|
||||||
lastTop = 0;
|
lastTop = 0;
|
||||||
_results.push((function() {
|
_results.push((function() {
|
||||||
var _j, _len1, _ref1, _results1;
|
var _k, _len1, _ref2, _results1;
|
||||||
_ref1 = row._y;
|
_ref2 = row._y;
|
||||||
_results1 = [];
|
_results1 = [];
|
||||||
for (sidx = _j = 0, _len1 = _ref1.length; _j < _len1; sidx = ++_j) {
|
for (sidx = _k = 0, _len1 = _ref2.length; _k < _len1; sidx = ++_k) {
|
||||||
ypos = _ref1[sidx];
|
ypos = _ref2[sidx];
|
||||||
|
if (!this.hasToShow(sidx)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (ypos !== null) {
|
if (ypos !== null) {
|
||||||
if (zeroPos) {
|
if (zeroPos) {
|
||||||
top = Math.min(ypos, zeroPos);
|
top = Math.min(ypos, zeroPos);
|
||||||
@@ -1515,19 +1711,28 @@ Licensed under the BSD-2-Clause License.
|
|||||||
top = ypos;
|
top = ypos;
|
||||||
bottom = this.bottom;
|
bottom = this.bottom;
|
||||||
}
|
}
|
||||||
left = this.left + idx * groupWidth + leftPadding;
|
left = this.xStart + idx * groupWidth + leftPadding;
|
||||||
if (!this.options.stacked) {
|
if (!this.options.stacked) {
|
||||||
left += sidx * (barWidth + this.options.barGap);
|
left += sidx * (barWidth + this.options.barGap);
|
||||||
}
|
}
|
||||||
size = bottom - top;
|
size = bottom - top;
|
||||||
if (this.options.verticalGridCondition && this.options.verticalGridCondition(row.x)) {
|
if (this.options.verticalGridCondition && this.options.verticalGridCondition(row.x)) {
|
||||||
this.drawBar(this.left + idx * groupWidth, this.top, groupWidth, Math.abs(this.top - this.bottom), this.options.verticalGridColor, this.options.verticalGridOpacity, this.options.barRadius);
|
if (!this.options.horizontal) {
|
||||||
|
this.drawBar(this.xStart + idx * groupWidth, this.yEnd, groupWidth, this.ySize, this.options.verticalGridColor, this.options.verticalGridOpacity, this.options.barRadius);
|
||||||
|
} else {
|
||||||
|
this.drawBar(this.yStart, this.xStart + idx * groupWidth, this.ySize, groupWidth, this.options.verticalGridColor, this.options.verticalGridOpacity, this.options.barRadius);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this.options.stacked) {
|
if (this.options.stacked) {
|
||||||
top -= lastTop;
|
top -= lastTop;
|
||||||
}
|
}
|
||||||
this.drawBar(left, top, barWidth, size, this.colorFor(row, sidx, 'bar'), this.options.barOpacity, this.options.barRadius);
|
if (!this.options.horizontal) {
|
||||||
_results1.push(lastTop += size);
|
this.drawBar(left, top, barWidth, size, this.colorFor(row, sidx, 'bar'), this.options.barOpacity, this.options.barRadius);
|
||||||
|
_results1.push(lastTop += size);
|
||||||
|
} else {
|
||||||
|
this.drawBar(top, left, size, barWidth, this.colorFor(row, sidx, 'bar'), this.options.barOpacity, this.options.barRadius);
|
||||||
|
_results1.push(lastTop -= size);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
_results1.push(null);
|
_results1.push(null);
|
||||||
}
|
}
|
||||||
@@ -1558,23 +1763,29 @@ Licensed under the BSD-2-Clause License.
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Bar.prototype.hitTest = function(x) {
|
Bar.prototype.hitTest = function(x, y) {
|
||||||
|
var pos;
|
||||||
if (this.data.length === 0) {
|
if (this.data.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
x = Math.max(Math.min(x, this.right), this.left);
|
if (!this.options.horizontal) {
|
||||||
return Math.min(this.data.length - 1, Math.floor((x - this.left) / (this.width / this.data.length)));
|
pos = x;
|
||||||
|
} else {
|
||||||
|
pos = y;
|
||||||
|
}
|
||||||
|
pos = Math.max(Math.min(pos, this.xEnd), this.xStart);
|
||||||
|
return Math.min(this.data.length - 1, Math.floor((pos - this.xStart) / (this.xSize / this.data.length)));
|
||||||
};
|
};
|
||||||
|
|
||||||
Bar.prototype.onGridClick = function(x, y) {
|
Bar.prototype.onGridClick = function(x, y) {
|
||||||
var index;
|
var index;
|
||||||
index = this.hitTest(x);
|
index = this.hitTest(x, y);
|
||||||
return this.fire('click', index, this.data[index].src, x, y);
|
return this.fire('click', index, this.data[index].src, x, y);
|
||||||
};
|
};
|
||||||
|
|
||||||
Bar.prototype.onHoverMove = function(x, y) {
|
Bar.prototype.onHoverMove = function(x, y) {
|
||||||
var index, _ref;
|
var index, _ref;
|
||||||
index = this.hitTest(x);
|
index = this.hitTest(x, y);
|
||||||
return (_ref = this.hover).update.apply(_ref, this.hoverContentForRow(index));
|
return (_ref = this.hover).update.apply(_ref, this.hoverContentForRow(index));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1587,17 +1798,27 @@ Licensed under the BSD-2-Clause License.
|
|||||||
Bar.prototype.hoverContentForRow = function(index) {
|
Bar.prototype.hoverContentForRow = function(index) {
|
||||||
var content, j, row, x, y, _i, _len, _ref;
|
var content, j, row, x, y, _i, _len, _ref;
|
||||||
row = this.data[index];
|
row = this.data[index];
|
||||||
content = "<div class='morris-hover-row-label'>" + row.label + "</div>";
|
content = $("<div class='morris-hover-row-label'>").text(row.label);
|
||||||
|
content = content.prop('outerHTML');
|
||||||
_ref = row.y;
|
_ref = row.y;
|
||||||
for (j = _i = 0, _len = _ref.length; _i < _len; j = ++_i) {
|
for (j = _i = 0, _len = _ref.length; _i < _len; j = ++_i) {
|
||||||
y = _ref[j];
|
y = _ref[j];
|
||||||
content += "<div class='morris-hover-point' style='color: " + (this.colorFor(row, j, 'label')) + "'>\n " + this.options.labels[j] + ":\n " + (this.yLabelFormat(y)) + "\n</div>";
|
if (this.options.labels[j] === false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
content += "<div class='morris-hover-point' style='color: " + (this.colorFor(row, j, 'label')) + "'>\n " + this.options.labels[j] + ":\n " + (this.yLabelFormat(y, j)) + "\n</div>";
|
||||||
}
|
}
|
||||||
if (typeof this.options.hoverCallback === 'function') {
|
if (typeof this.options.hoverCallback === 'function') {
|
||||||
content = this.options.hoverCallback(index, this.options, content, row.src);
|
content = this.options.hoverCallback(index, this.options, content, row.src);
|
||||||
}
|
}
|
||||||
x = this.left + (index + 0.5) * this.width / this.data.length;
|
if (!this.options.horizontal) {
|
||||||
return [content, x];
|
x = this.left + (index + 0.5) * this.width / this.data.length;
|
||||||
|
return [content, x];
|
||||||
|
} else {
|
||||||
|
x = this.left + 0.5 * this.width;
|
||||||
|
y = this.top + (index + 0.5) * this.height / this.data.length;
|
||||||
|
return [content, x, y, true];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Bar.prototype.drawXAxisLabel = function(xPos, yPos, text) {
|
Bar.prototype.drawXAxisLabel = function(xPos, yPos, text) {
|
||||||
|
|||||||
@@ -39,3 +39,4 @@ chardet<3.1.0,>=3.0.2
|
|||||||
mt-940==3.2
|
mt-940==3.2
|
||||||
vobject==0.9.*
|
vobject==0.9.*
|
||||||
pycountry
|
pycountry
|
||||||
|
defusedcsv>=1.0.1
|
||||||
|
|||||||
@@ -100,7 +100,8 @@ setup(
|
|||||||
'mt-940==4.7',
|
'mt-940==4.7',
|
||||||
'django-i18nfield>=1.0.1',
|
'django-i18nfield>=1.0.1',
|
||||||
'vobject==0.9.*',
|
'vobject==0.9.*',
|
||||||
'pycountry'
|
'pycountry',
|
||||||
|
'defusedcsv'
|
||||||
],
|
],
|
||||||
extras_require={
|
extras_require={
|
||||||
'dev': [
|
'dev': [
|
||||||
|
|||||||
@@ -2,10 +2,9 @@ from django.db import DEFAULT_DB_ALIAS, connections
|
|||||||
from django.test.utils import CaptureQueriesContext
|
from django.test.utils import CaptureQueriesContext
|
||||||
|
|
||||||
|
|
||||||
# Inspired by /django/test/testcases.py
|
|
||||||
# but copied over to work without the unit test module
|
|
||||||
|
|
||||||
class _AssertNumQueriesContext(CaptureQueriesContext):
|
class _AssertNumQueriesContext(CaptureQueriesContext):
|
||||||
|
# Inspired by /django/test/testcases.py
|
||||||
|
# but copied over to work without the unit test module
|
||||||
def __init__(self, num, connection):
|
def __init__(self, num, connection):
|
||||||
self.num = num
|
self.num = num
|
||||||
super(_AssertNumQueriesContext, self).__init__(connection)
|
super(_AssertNumQueriesContext, self).__init__(connection)
|
||||||
|
|||||||
@@ -66,6 +66,18 @@ class EventMiddlewareTest(EventTestMixin, SoupTest):
|
|||||||
|
|
||||||
|
|
||||||
class ItemDisplayTest(EventTestMixin, SoupTest):
|
class ItemDisplayTest(EventTestMixin, SoupTest):
|
||||||
|
def test_link_rewrite(self):
|
||||||
|
q = Quota.objects.create(event=self.event, name='Quota', size=2)
|
||||||
|
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=True,
|
||||||
|
description="http://example.org [Sample](http://example.net)")
|
||||||
|
q.items.add(item)
|
||||||
|
html = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content
|
||||||
|
|
||||||
|
self.assertNotIn('href="http://example.org', html)
|
||||||
|
self.assertNotIn('href="http://example.net', html)
|
||||||
|
self.assertIn('href="/redirect/?url=http%3A//example.org%3A', html)
|
||||||
|
self.assertIn('href="/redirect/?url=http%3A//example.net%3A', html)
|
||||||
|
|
||||||
def test_not_active(self):
|
def test_not_active(self):
|
||||||
q = Quota.objects.create(event=self.event, name='Quota', size=2)
|
q = Quota.objects.create(event=self.event, name='Quota', size=2)
|
||||||
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=False)
|
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=False)
|
||||||
|
|||||||
Reference in New Issue
Block a user