Commit 0eff495f authored by David Haynes's avatar David Haynes 🙆
Browse files

Merge branch 'crispy' into 'master'

Additional Explanatory Info & Interface Updates ( Closes #17 )

Basically:

    - Crispy-forms now in play for better formatted forms

    - Now a three step process with some space and some info

    - Magnificently formatted by yours truely

One day:

    - Possibly squish short + expiration fields together

    - Example text within with like an example

See merge request !17
parents 7055408f 972dfbd2
......@@ -2,7 +2,9 @@ from django import forms
from go.models import URL, RegisteredUser
from django.core.exceptions import ValidationError
from captcha.fields import CaptchaField
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Fieldset, Submit, HTML, Div, Field
from crispy_forms.bootstrap import StrictButton, PrependedText, Accordion, AccordionGroup
class URLForm(forms.ModelForm):
......@@ -12,7 +14,6 @@ class URLForm(forms.ModelForm):
label='Long URL',
max_length=1000,
widget=forms.URLInput(attrs={
'placeholder': 'https://'
})
)
......@@ -55,11 +56,86 @@ class URLForm(forms.ModelForm):
widget=forms.RadioSelect(),
)
def __init__(self, *args, **kwargs):
super(URLForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_method = 'POST'
self.helper.form_class = 'form-horizontal'
self.helper.label_class = 'col-md-1'
self.helper.field_class = 'col-md-6'
self.helper.layout = Layout(
Fieldset(
'',
Accordion(
AccordionGroup('Step 1: Long URL',
Div(
HTML("""
<h4>Paste the URL you would like to shorten:</h4>
<br />
"""),
PrependedText('target',
'https:// required',
),
style="background: rgb(#F6F6F6);",
title="target_url",
css_class="first_group",
),
css_id='firstCollapse',
active=True,
template='crispy/accordian-group.html',
),
AccordionGroup('Step 2: Short URL',
Div(
HTML("""
<h4>Create a custom Go address:</h4>
<br />
"""),
PrependedText('short',
'go.gmu.edu/',
),
style="background: rgb(#F6F6F6);",
title="short_url",
css_class="second_group",
),
css_id='secondCollapse',
active=True,
template='crispy/accordian-group.html',
),
AccordionGroup('Step 3: URL Expiration',
Div(
HTML("""
<h4>Set when you would like your Go address to expire:</h4>
<br />
"""),
'expires',
style="background: rgb(#F6F6F6);",
title="expires_url",
css_class="third_group",
),
css_id='thirdCollapse',
active=True,
template='crispy/accordian-group.html',
),
css_id='accordian',
template='crispy/accordian.html'
),
HTML("""
<br />
"""),
StrictButton('Shorten', css_class="btn-success", type='submit'),
)
)
class Meta:
model = URL
fields = ('target',)
exclude = ('owner', 'short', 'date_created', 'clicks', 'expires')
class SignupForm(forms.ModelForm):
def validate_username(username):
......
{% extends 'layouts/base.html' %}
{% load crispy_forms_tags %}
{% block title %}
Go - A University Branded URL Shortener
......@@ -8,108 +8,20 @@ Go - A University Branded URL Shortener
{% block content %}
<style>
.asteriskField {
display: none;
}
</style>
<div class="page-header" id="banner">
<div class="row">
<div class="col-md-12">
<h1><strong>Shorten URL</strong></h1>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="well">
<form class="form-horizontal" method="post" action="{%url 'index'%}">
{% csrf_token %}
<fieldset>
{% if form.non_field_errors %}
<div class="form-group has-error">
<div class="col-md-12">
{% for error in form.non_field_errors %}
<span class="help-block">{{ error }}</p>
{% endfor %}
</div>
</div>
{% endif %}
{% if form.target.errors %}
<div class="form-group has-error">
{% else %}
<div class="form-group">
{% endif %}
<div class="col-md-4">
<label class="control-label" for="{{ form.target.id_for_label }}">
{{ form.target.label }}</label>
</div>
<div class="col-md-8">
{{ form.target }}
{% for error in form.target.errors %}
<span class="help-block">{{error}}</span>
{% endfor %}
</div>
</div>
{% if form.short.errors %}
<div class="form-group has-error">
{% else %}
<div class="form-group">
{% endif %}
<div class="col-md-4">
<label class="control-label" for="{{ form.short.id_for_label }}">
{{ form.short.label }}</label>
</div>
<div class="col-md-8">
{{ form.short }}
{% for error in form.short.errors %}
<span class="help-block">{{error}}</span>
{% endfor %}
</div>
</div>
{% if form.expires.errors %}
<div class="form-group has-error">
{% else %}
<div class="form-group">
{% endif %}
<div class="col-md-4">
<label class="control-label" for="{{ form.expires.id_for_label }}">
{{ form.expires.label }}</label>
</div>
<div class="col-md-8">
{% for option in form.expires %}
<p>
{{ option }}
</p>
{% endfor %}
{% for error in form.expires.errors %}
<span class="help-block">{{error}}</span>
{% endfor %}
</div>
</div>
<div class="form-group">
<div class="col-md-12">
<input type="submit" value="Shorten"
class="btn btn-primary btn-lg btn-block" />
</div>
</div>
</fieldset>
</form>
</div>
</div>
</div>
{% crispy form %}
{% endblock %}
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
{{ div.name }}
</h4>
</div>
<div id="{{ div.css_id }}" class="panel-collapse collapse{% if div.active %} in{% endif %}" >
<div class="panel-body">
{{ fields|safe }}
</div>
</div>
</div>
<br />
<div class="panel-group" id="{{ accordion.css_id }}">
{{ content|safe }}
</div>
......@@ -170,6 +170,7 @@ elif AUTH_MODE.lower() == 'cas':
PIWIK_SITE_ID = secret.PIWIK_SITE_ID
PIWIK_URL = secret.PIWIK_URL
CRISPY_TEMPLATE_PACK = 'bootstrap3'
# Mail settings
EMAIL_HOST = secret.EMAIL_HOST
......
/* ========================================================================
* Bootstrap: tab.js v3.3.6
* http://getbootstrap.com/javascript/#tabs
* ========================================================================
* Copyright 2011-2016 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// TAB CLASS DEFINITION
// ====================
var Tab = function (element) {
// jscs:disable requireDollarBeforejQueryAssignment
this.element = $(element)
// jscs:enable requireDollarBeforejQueryAssignment
}
Tab.VERSION = '3.3.6'
Tab.TRANSITION_DURATION = 150
Tab.prototype.show = function () {
var $this = this.element
var $ul = $this.closest('ul:not(.dropdown-menu)')
var selector = $this.data('target')
if (!selector) {
selector = $this.attr('href')
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
}
if ($this.parent('li').hasClass('active')) return
var $previous = $ul.find('.active:last a')
var hideEvent = $.Event('hide.bs.tab', {
relatedTarget: $this[0]
})
var showEvent = $.Event('show.bs.tab', {
relatedTarget: $previous[0]
})
$previous.trigger(hideEvent)
$this.trigger(showEvent)
if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
var $target = $(selector)
this.activate($this.closest('li'), $ul)
this.activate($target, $target.parent(), function () {
$previous.trigger({
type: 'hidden.bs.tab',
relatedTarget: $this[0]
})
$this.trigger({
type: 'shown.bs.tab',
relatedTarget: $previous[0]
})
})
}
Tab.prototype.activate = function (element, container, callback) {
var $active = container.find('> .active')
var transition = callback
&& $.support.transition
&& ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)
function next() {
$active
.removeClass('active')
.find('> .dropdown-menu > .active')
.removeClass('active')
.end()
.find('[data-toggle="tab"]')
.attr('aria-expanded', false)
element
.addClass('active')
.find('[data-toggle="tab"]')
.attr('aria-expanded', true)
if (transition) {
element[0].offsetWidth // reflow for transition
element.addClass('in')
} else {
element.removeClass('fade')
}
if (element.parent('.dropdown-menu').length) {
element
.closest('li.dropdown')
.addClass('active')
.end()
.find('[data-toggle="tab"]')
.attr('aria-expanded', true)
}
callback && callback()
}
$active.length && transition ?
$active
.one('bsTransitionEnd', next)
.emulateTransitionEnd(Tab.TRANSITION_DURATION) :
next()
$active.removeClass('in')
}
// TAB PLUGIN DEFINITION
// =====================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.tab')
if (!data) $this.data('bs.tab', (data = new Tab(this)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.tab
$.fn.tab = Plugin
$.fn.tab.Constructor = Tab
// TAB NO CONFLICT
// ===============
$.fn.tab.noConflict = function () {
$.fn.tab = old
return this
}
// TAB DATA-API
// ============
var clickHandler = function (e) {
e.preventDefault()
Plugin.call($(this), 'show')
}
$(document)
.on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
.on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
}(jQuery);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment