Working on calendar layout

This commit is contained in:
Justin Lewis Salmon 2013-06-01 15:24:46 +01:00
parent 8200d40cf1
commit 19210b734c
8 changed files with 325 additions and 141 deletions

BIN
app.db

Binary file not shown.

View file

@ -0,0 +1,32 @@
from sqlalchemy import *
from migrate import *
from migrate.changeset import schema
pre_meta = MetaData()
post_meta = MetaData()
task = Table('task', post_meta,
Column('id', Integer, primary_key=True, nullable=False),
Column('name', String(length=256)),
Column('start_date', Date),
Column('end_date', Date),
Column('info', String(length=256)),
Column('project_id', Integer),
Column('owner_id', Integer),
Column('parent_task', Integer),
)
def upgrade(migrate_engine):
# Upgrade operations go here. Don't create your own engine; bind
# migrate_engine to your metadata
pre_meta.bind = migrate_engine
post_meta.bind = migrate_engine
post_meta.tables['task'].columns['info'].create()
def downgrade(migrate_engine):
# Operations to reverse the above upgrade go here.
pre_meta.bind = migrate_engine
post_meta.bind = migrate_engine
post_meta.tables['task'].columns['info'].drop()

View file

@ -0,0 +1,17 @@
{% from "macros.html" import alert, field, input, date %}
<form class="form-vertical" action="/create-task" method="post" id="create-task">
<fieldset>
<h3>Create Task</h3>
{{ field(form.name, hide_label=True, placeholder=True) }}
{{ field(form.info, hide_label=True, placeholder=True) }}
{{ date(form.start_date, hide_label=True, placeholder=True) }}
{{ date(form.end_date, hide_label=True, placeholder=True) }}
{{ field(form.team, input_classes='typeahead', hide_label=True, placeholder=True, autocomplete='off') }}
{{ form.hidden_tag() }}
<button type="submit" class="btn btn-primary">Submit</button>
<a href="#" class="btn">Cancel</a>
</fieldset>
</form>

View file

@ -1,5 +1,4 @@
{% extends "base/base_with_nav_responsive.html" %}
{% from "macros.html" import alert, field, input, date %}
{% block css %}
<style type="text/css">
@ -58,21 +57,21 @@
<div class="navbar tabbable">
<div class="navbar-inner navbar-justified">
<!-- .btn-navbar is used as the toggle for collapsed navbar content -->
<a class="btn btn-navbar" data-toggle="collapse" data-target="#justified-nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<!-- .btn-navbar is used as the toggle for collapsed navbar content -->
<a class="btn btn-navbar" data-toggle="collapse" data-target="#justified-nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<div id="justified-nav-collapse" class="nav-collapse collapse">
<ul id="justified-nav" class="nav">
<li class="active"><a href="#overview" data-toggle="tab">Overview</a></li>
<li><a href="#todo" data-toggle="tab">To-Do</a></li>
<li><a href="#team" data-toggle="tab">Team Members</a></li>
<li><a href="#settings" data-toggle="tab">Settings</a></li>
</ul>
</div>
<div id="justified-nav-collapse" class="nav-collapse collapse">
<ul id="justified-nav" class="nav">
<li class="active"><a href="#overview" data-toggle="tab">Overview</a></li>
<li><a href="#todo" data-toggle="tab">To-Do</a></li>
<li><a href="#team" data-toggle="tab">Team Members</a></li>
<li><a href="#settings" data-toggle="tab">Settings</a></li>
</ul>
</div>
</div>
</div>
<!-- /.navbar -->
@ -88,57 +87,102 @@
</div>
</div>
{# <div class="span8">#}
{# <form class="form-horizontal" action="" method="post" name="create-task">#}
{# <fieldset>#}
{# <legend>Create Task</legend>#}
{##}
{# {{ field(form.name) }}#}
{# {{ field(form.info) }}#}
{# {{ date(form.start_date) }}#}
{# {{ date(form.end_date) }}#}
{# {{ field(form.team) }}#}
{##}
{# <div class="form-actions">#}
{# {{ form.hidden_tag() }}#}
{# <button type="submit" class="btn btn-primary">Submit</button>#}
{# <a href="#" class="btn">Cancel</a>#}
{# </div>#}
{# </fieldset>#}
{# </form>#}
{# </div>#}
{% endblock %}
{% block content_side %}
<div class="thumbnail">
<div class="caption">
{% include "forms/create_task.html" %}
</div>
</div>
<div class="clearfix"></div>
<div class="thumbnail">
<div class="caption" id="task-overview">
<h3>Thumbnail label</h3>
<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus.
Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
<p><a href="#" class="btn btn-primary">Action</a> <a href="#" class="btn">Action</a></p>
<p><a href="#" rel="popover" data-original-title="A Title" class="btn btn-primary">Action</a> <a href="#"
class="btn">Action</a>
</p>
<div id="popover_content_wrapper" style="display: none">This is your div content</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script type="text/javascript">
// Tabs
$(function () {
var baseURL = '/';
//load content for first tab and initialize
$('#overview').load(baseURL + 'overview', function () {
$('#justified-nav').tab(); //initialize tabs
//initialize tabs
$('#justified-nav').tab();
});
$('#justified-nav').bind('show', function (e) {
var pattern = /#.+/gi //use regex to get anchor(==selector)
var contentID = e.target.toString().match(pattern)[0]; //get anchor
//use regex to get anchor(==selector)
var pattern = /#.+/gi
//get anchor
var contentID = e.target.toString().match(pattern)[0];
//load content for selected tab
$(contentID).load(baseURL + contentID.replace('#', ''), function () {
$('#justified-nav').tab(); //reinitialize tabs
//reinitialize tabs
$('#justified-nav').tab();
});
});
});
// Datepickers
$('.datepicker').datepicker();
$('.popover').popover({
html: true,
trigger: 'hover',
content: function () {
return $('#popover_content_wrapper').html();
}
});
// Task creation form
{# $('#create-task').bind('submit', function (e) {#}
{# e.preventDefault();#}
{##}
{# $.post('/create-task', {#}
{# $('#create-task').serialize()#}
{# }).success(function (data) {#}
{# alert('yay');#}
{# console.log($(".datepicker"));#}
{# console.log(data);#}
{# $('#create-task').html(data).find(".datepicker").datepicker();#}
{##}
{# }).error(function (data) {#}
{# alert('aww');#}
{# $('#create-task').html(data).find(".datepicker").datepicker();#}
{##}
{# });#}
{##}
{# $.ajax({#}
{# type: "POST",#}
{# url: "{{ url_for('create_task') }}",#}
{# data: $('#create-task').serialize(),#}
{# success: function (result) {#}
{# console.log(result);#}
{# $('#create-task').html(result).find(".datepicker").datepicker();#}
{# #}
{# }#}
{# });#}
{##}
{# });#}
</script>
{% endblock %}

View file

@ -1,98 +1,108 @@
{% macro alert(content, type=None, alert_header=None, close_button=True) -%}
{# type can be success, error (or danger), info. Defaults to a warning style. #}
<div class="alert
{# type can be success, error (or danger), info. Defaults to a warning style. #}
<div class="alert
{%- if alert_header %} alert-block{% endif -%}
{%- if type %} alert-{{ type }}{% endif -%}
{%- if close_button %} fade in{% endif %}">
{% if close_button -%}
<a class="close" data-dismiss="alert">&times;</a>
{%- endif %}
{% if alert_header -%}
<h4 class="alert-heading">{{ alert_header|safe }}</h4>
{%- endif %}
{% if close_button -%}
<a class="close" data-dismiss="alert">&times;</a>
{%- endif %}
{% if alert_header -%}
<h4 class="alert-heading">{{ alert_header|safe }}</h4>
{%- endif %}
{{ content|safe }}
{{ content|safe }}
</div>
</div>
{%- endmacro %}
{% macro label(content, type='warning') -%}
<span class="label label-{{ type }}">{{ content|safe }}</span>
<span class="label label-{{ type }}">{{ content|safe }}</span>
{%- endmacro %}
{% macro non_field_errors(form) %}
{% if form.non_field_errors %}
{% for error in form.non_field_errors() %}
{{ alert(content=error, type='error', close_button=False) }}
{% endfor %}
{% endif %}
{% if form.non_field_errors %}
{% for error in form.non_field_errors() %}
{{ alert(content=error, type='error', close_button=False) }}
{% endfor %}
{% endif %}
{% endmacro %}
{% macro label(field) -%}
<label class="control-label"{% if field.auto_id %} for="{{ field.auto_id|safe }}"{% endif %}>{{ field.label|safe }}</label>
<label class="control-label"{% if field.auto_id %}
for="{{ field.auto_id|safe }}"{% endif %}>{{ field.label|safe }}</label>
{%- endmacro %}
{% macro input(field, prepend_content=None, append_content=None) -%}
{# Helper macro for rendering the input itself #}
{% macro input(field, input_classes=None, prepend_content=None, append_content=None, placeholder=None, autocomplete='on') -%}
{# Helper macro for rendering the input itself #}
{% if prepend_content %}
{% if prepend_content %}
<div class="input-prepend">
{% elif append_content %}
{% elif append_content %}
<div class="input-append">
{% endif %}
{%- if prepend_content -%}
<span class="add-on">{{ prepend_content }}</span>
{%- endif -%}
{% endif %}
{%- if prepend_content -%}
<span class="add-on">{{ prepend_content }}</span>
{%- endif -%}
{% if placeholder %}
{{ field(placeholder=placeholder, class=input_classes, autocomplete=autocomplete) }}
{% else %}
{{ field|safe }}
{% endif %}
{%- if append_content -%}
<span class="add-on">{{ append_content }}</span>
{%- endif -%}
{% if field.errors %}
<span class="help-inline">{{ field.errors|join(' ')|safe }}</span>
{% endif %}
{% if append_content or prepend_content %}
</div>
{% endif %}
{%- endmacro %}
{% macro field(field, classes=None, input_classes=None, prepend_content=None, append_content=None, hide_label=False, inline=False, placeholder=False, autocomplete='on') -%}
{% if field.is_hidden %}
{{ field|safe }}
{% else %}
<div class="control-group{% if field.errors %} error{% endif -%}{%- if classes %} {{ classes }}{% endif %}">
{% if not hide_label %}
{{ label(field) }}
{% endif %}
<div class="controls">
{%- if append_content -%}
<span class="add-on">{{ append_content }}</span>
{%- endif -%}
{{ input(field, input_classes, prepend_content, append_content, placeholder, autocomplete) }}
{% if field.errors %}
<span class="help-inline">{{ field.errors|join(' ')|safe }}</span>
{% endif %}
{% if append_content or prepend_content %}
{% if field.description %}
<p class="help-block">{{ field.description|safe }}</p>
{% endif %}
</div>
</div>
{% endif %}
{% endif %}
{%- endmacro %}
{% macro field(field, classes=None, prepend_content=None, append_content=None, hide_label=False, inline=False) -%}
{% if field.is_hidden %}
{{ field|safe }}
{% else %}
<div class="control-group{% if field.errors %} error{% endif -%}{%- if classes %} {{ classes }}{% endif %}">
{% if not hide_label %}
{{ label(field) }}
{% endif %}
<div class="controls">
{{ input(field, prepend_content, append_content) }}
{% if field.description %}
<p class="help-block">{{ field.description|safe }}</p>
{% endif %}
</div>
</div>
{% endif %}
{%- endmacro %}
{% macro date(field) %}
{% macro date(field, hide_label=False, placeholder=False) %}
<div class="control-group{% if field.errors %} error{% endif -%}{%- if classes %} {{ classes }}{% endif %}">
{{ label(field) }}
{% if not hide_label %}
{{ label(field) }}
{% endif %}
<div class="controls">
<div class="input-append date datepicker"
data-date="12-02-2012"
data-date-format="dd-mm-yyyy">
<input class="span" size="16" type="date" value="12-02-2012" id="{{ field.id }}"
name="{{ field.id }}">
<div class="input-append date datepicker" data-date-format="dd-mm-yyyy">
{% if placeholder %}
{{ field(placeholder=field.name) }}
{% else %}
{{ field }}
{% endif %}
<span class="add-on"><i class="icon-th"></i></span>
</div>
{% if field.errors %}
<span class="help-inline">{{ field.errors|join(' ')|safe }}</span>
{% endif %}
</div>
</div>
{% endmacro %}

View file

@ -14,8 +14,60 @@
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
eventSources: [
{
url: '/events',
type: 'POST',
data: {
custom_param1: 'something',
custom_param2: 'somethingelse'
},
error: function (e) {
alert('there was an error while fetching events!');
console.log(e)
},
success: function (data) {
console.log(data)
}
//className: 'popover'
//color: '#eee', // a non-ajax option
//textColor: 'black' // a non-ajax option
},
// any other sources...
'https://www.google.com/calendar/feeds/mccrustin%40gmail.com/public/basic'
],
eventClick: function (task) {
// opens events in a popup window
{# window.open(event.url, 'gcalevent', 'width=700,height=600');#}
$.ajax({
type: "POST",
url: '/task-overview',
data: task,
success: function (data) {
alert('lol')
$('#task-overview').html(data);
$('.popover').popover({
html: true,
trigger: 'hover',
content: function () {
return $('#popover_content_wrapper').html();
}
});
}
});
return false;
},
editable: true,
selectable: true,
selectHelper: true,
select: function (start, end, allDay) {
var title = prompt('Event Title:');
if (title) {
@ -31,13 +83,6 @@
}
calendar.fullCalendar('unselect');
},
editable: true,
eventClick: function (event) {
// opens events in a popup window
window.open(event.url, 'gcalevent', 'width=700,height=600');
return false;
},
loading: function (bool) {
if (bool) {
@ -45,34 +90,7 @@
} else {
$('#loading').hide();
}
},
eventSources: [
// your event source
{
url: '/events',
type: 'POST',
data: {
custom_param1: 'something',
custom_param2: 'somethingelse'
},
error: function () {
alert('there was an error while fetching events!');
},
success: function (data) {
console.log(data)
}
//color: '#eee', // a non-ajax option
//textColor: 'black' // a non-ajax option
},
// any other sources...
// 'http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic'
]
}
});
});

View file

@ -0,0 +1,9 @@
<h3>{{ task.title }}</h3>
<p>{{ task.info }}</p>
<p><a href="#" rel="popover" data-original-title="A Title" class="btn btn-primary">Action</a> <a href="#"
class="btn">Action</a>
</p>
<div id="popover_content_wrapper" style="display: none">This is your div content</div>

View file

@ -1,9 +1,10 @@
from flask import render_template, flash, redirect, session, url_for, g, request, jsonify
from datetime import datetime
from flask import render_template, flash, redirect, session, url_for, g, request, jsonify, json
from flask.ext.login import login_user, current_user, login_required, logout_user
from megaproject import app, lm, oid, db
from forms import LoginForm, CreateProjectForm, CreateTaskForm
from models import User, ROLE_USER, Project
from models import User, ROLE_USER, Project, Task
@app.route('/')
@ -98,16 +99,57 @@ def create_project():
return render_template('create_project.html', title='Create Project', user=user, form=form)
@app.route('/create-task', methods=['GET', 'POST'])
@app.route('/create-task', methods=['POST'])
@login_required
def create_task():
user = g.user
form = CreateTaskForm()
print 'form:', request.form
if form.validate_on_submit():
print 'ok'
# Check the task doesn't already exist
task = Task(name=form.name.data,
start_date=form.start_date.data,
end_date=form.end_date.data,
info=form.info.data)
db.session.add(task)
db.session.commit()
flash('created task %s' % form.name.data)
return redirect(url_for('index'))
return render_template('index.html', title='Index', user=user, form=form)
@app.route('/overview', methods=['GET', 'POST'])
@login_required
def overview():
return render_template('views/selectable.html')
return render_template('views/calendar.html')
@app.route('/events', methods=['GET', 'POST'])
@login_required
def events():
event1 = {'title': 'Task 1', 'start': '2013-05-05 12:30:00',
'end': '%s' % datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'color': '#ddd'}
event2 = {'title': 'Task 2', 'start': '2013-05-06 12:30:00',
'end': '%s' % datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'color': '#eee'}
events = [event1, event2]
for event in Task.query.all():
ev = event.__dict__
del ev['_sa_instance_state']
ev['title'] = ev['name']
ev['start'] = ev['start_date'].strftime('%Y-%m-%d')
del ev['start_date']
ev['end'] = ev['end_date'].strftime('%Y-%m-%d')
del ev['end_date']
events.append(ev)
print 'events: ', events
return json.dumps(events)
@app.route('/todo', methods=['GET', 'POST'])
@ -131,6 +173,18 @@ def settings():
@app.route('/typeahead', methods=['GET', 'POST'])
@login_required
def typeahead():
response = jsonify(options=['red', 'blue', 'green', 'yellow'])
# users = User.query.all()
# usernames = list()
#
# for user in users:
# usernames.append()
response = jsonify(options=[user.nickname for user in User.query.all()])
return response
@app.route('/task-overview', methods=['GET', 'POST'])
@login_required
def task_overview():
print 'lol ', request.form
return render_template('views/task_overview.html', task=request.form)