Commit c943495e42fd09477a5a9c14038f7c233fc6e384

Authored by Zambom
1 parent 152fb646

Adding webpage form (Not working yet/Adjusts to make)

amadeus/settings.py
... ... @@ -60,6 +60,8 @@ INSTALLED_APPS = [
60 60 'subjects',
61 61 'students_group',
62 62 'topics',
  63 + 'pendencies',
  64 + 'webpage',
63 65 'mailsender',
64 66 'security',
65 67 'themes'
... ...
amadeus/static/js/jquery.formset.js 0 → 100644
... ... @@ -0,0 +1,170 @@
  1 +/**
  2 + * jQuery Formset 1.2
  3 + * @author Stanislaus Madueke (stan DOT madueke AT gmail DOT com)
  4 + * @requires jQuery 1.2.6 or later
  5 + *
  6 + * Copyright (c) 2009, Stanislaus Madueke
  7 + * All rights reserved.
  8 + *
  9 + * Licensed under the New BSD License
  10 + * See: http://www.opensource.org/licenses/bsd-license.php
  11 + */
  12 +;(function($) {
  13 + $.fn.formset = function(opts)
  14 + {
  15 + var options = $.extend({}, $.fn.formset.defaults, opts),
  16 + flatExtraClasses = options.extraClasses.join(' '),
  17 + $$ = $(this),
  18 +
  19 + applyExtraClasses = function(row, ndx) {
  20 + if (options.extraClasses) {
  21 + row.removeClass(flatExtraClasses);
  22 + row.addClass(options.extraClasses[ndx % options.extraClasses.length]);
  23 + }
  24 + },
  25 +
  26 + updateElementIndex = function(elem, prefix, ndx) {
  27 + var idRegex = new RegExp('(' + prefix + '-\\d+-)|(^)'),
  28 + replacement = prefix + '-' + ndx + '-';
  29 + if (elem.attr("for")) elem.attr("for", elem.attr("for").replace(idRegex, replacement));
  30 + if (elem.attr('id')) elem.attr('id', elem.attr('id').replace(idRegex, replacement));
  31 + if (elem.attr('name')) elem.attr('name', elem.attr('name').replace(idRegex, replacement));
  32 + },
  33 +
  34 + hasChildElements = function(row) {
  35 + return row.find('input,select,textarea,label').length > 0;
  36 + },
  37 +
  38 + insertDeleteLink = function(row) {
  39 + if (row.is('TR')) {
  40 + // If the forms are laid out in table rows, insert
  41 + // the remove button into the last table cell:
  42 + row.children(':last').append('<a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + '</a>');
  43 + } else if (row.is('UL') || row.is('OL')) {
  44 + // If they're laid out as an ordered/unordered list,
  45 + // insert an <li> after the last list item:
  46 + row.append('<li><a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText +'</a></li>');
  47 + } else {
  48 + // Otherwise, just insert the remove button as the
  49 + // last child element of the form's container:
  50 + row.append('<a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText +'</a>');
  51 + }
  52 + row.find('a.' + options.deleteCssClass).click(function() {
  53 + var row = $(this).parents('.' + options.formCssClass),
  54 + del = row.find('input:hidden[id $= "-DELETE"]');
  55 + if (del.length) {
  56 + // We're dealing with an inline formset; rather than remove
  57 + // this form from the DOM, we'll mark it as deleted and hide
  58 + // it, then let Django handle the deleting:
  59 + del.val('on');
  60 + row.hide();
  61 + } else {
  62 + row.remove();
  63 + // Update the TOTAL_FORMS form count.
  64 + // Also update names and IDs for all remaining form controls so they remain in sequence:
  65 + var forms = $('.' + options.formCssClass).not('.formset-custom-template');
  66 + $('#id_' + options.prefix + '-TOTAL_FORMS').val(forms.length);
  67 + for (var i=0, formCount=forms.length; i<formCount; i++) {
  68 + applyExtraClasses(forms.eq(i), i);
  69 + forms.eq(i).find('input,select,textarea,label').each(function() {
  70 + updateElementIndex($(this), options.prefix, i);
  71 + });
  72 + }
  73 + }
  74 + // If a post-delete callback was provided, call it with the deleted form:
  75 + if (options.removed) options.removed(row);
  76 + return false;
  77 + });
  78 + };
  79 +
  80 + $$.each(function(i) {
  81 + var row = $(this),
  82 + del = row.find('input:checkbox[id $= "-DELETE"]');
  83 + if (del.length) {
  84 + // If you specify "can_delete = True" when creating an inline formset,
  85 + // Django adds a checkbox to each form in the formset.
  86 + // Replace the default checkbox with a hidden field:
  87 + del.before('<input type="hidden" name="' + del.attr('name') +'" id="' + del.attr('id') +'" />');
  88 + del.remove();
  89 + }
  90 + if (hasChildElements(row)) {
  91 + insertDeleteLink(row);
  92 + row.addClass(options.formCssClass);
  93 + applyExtraClasses(row, i);
  94 + }
  95 + });
  96 +
  97 + if ($$.length) {
  98 + var addButton, template;
  99 + if (options.formTemplate) {
  100 + // If a form template was specified, we'll clone it to generate new form instances:
  101 + template = (options.formTemplate instanceof $) ? options.formTemplate : $(options.formTemplate);
  102 + template.removeAttr('id').addClass(options.formCssClass).addClass('formset-custom-template');
  103 + template.find('input,select,textarea,label').each(function() {
  104 + updateElementIndex($(this), options.prefix, 2012);
  105 + });
  106 + insertDeleteLink(template);
  107 + } else {
  108 + // Otherwise, use the last form in the formset; this works much better if you've got
  109 + // extra (>= 1) forms (thnaks to justhamade for pointing this out):
  110 + template = $('.' + options.formCssClass + ':last').clone(true).removeAttr('id');
  111 + template.find('input:hidden[id $= "-DELETE"]').remove();
  112 + template.find('input,select,textarea,label').each(function() {
  113 + var elem = $(this);
  114 + // If this is a checkbox or radiobutton, uncheck it.
  115 + // This fixes Issue 1, reported by Wilson.Andrew.J:
  116 + if (elem.is('input:checkbox') || elem.is('input:radio')) {
  117 + elem.attr('checked', false);
  118 + } else {
  119 + elem.val('');
  120 + }
  121 + });
  122 + }
  123 + // FIXME: Perhaps using $.data would be a better idea?
  124 + options.formTemplate = template;
  125 +
  126 + if ($$.attr('tagName') == 'TR') {
  127 + // If forms are laid out as table rows, insert the
  128 + // "add" button in a new table row:
  129 + var numCols = $$.eq(0).children().length;
  130 + $$.parent().append('<tr><td colspan="' + numCols + '"><a class="' + options.addCssClass + '" href="javascript:void(0)">' + options.addText + '</a></tr>');
  131 + addButton = $$.parent().find('tr:last a');
  132 + addButton.parents('tr').addClass(options.formCssClass + '-add');
  133 + } else {
  134 + // Otherwise, insert it immediately after the last form:
  135 + $$.filter(':last').after('<a class="' + options.addCssClass + '" href="javascript:void(0)">' + options.addText + '</a>');
  136 + addButton = $$.filter(':last').next();
  137 + }
  138 + addButton.click(function() {
  139 + var formCount = parseInt($('#id_' + options.prefix + '-TOTAL_FORMS').val()),
  140 + row = options.formTemplate.clone(true).removeClass('formset-custom-template'),
  141 + buttonRow = $(this).parents('tr.' + options.formCssClass + '-add').get(0) || this;
  142 + applyExtraClasses(row, formCount);
  143 + row.insertBefore($(buttonRow)).show();
  144 + row.find('input,select,textarea,label').each(function() {
  145 + updateElementIndex($(this), options.prefix, formCount);
  146 + });
  147 + $('#id_' + options.prefix + '-TOTAL_FORMS').val(formCount + 1);
  148 + // If a post-add callback was supplied, call it with the added form:
  149 + if (options.added) options.added(row);
  150 + return false;
  151 + });
  152 + }
  153 +
  154 + return $$;
  155 + }
  156 +
  157 + /* Setup plugin defaults */
  158 + $.fn.formset.defaults = {
  159 + prefix: 'form', // The form prefix for your django formset
  160 + formTemplate: null, // The jQuery selection cloned to generate new form instances
  161 + addText: 'add another', // Text for the add link
  162 + deleteText: 'remove', // Text for the delete link
  163 + addCssClass: 'add-row', // CSS class applied to the add link
  164 + deleteCssClass: 'delete-row', // CSS class applied to the delete link
  165 + formCssClass: 'dynamic-form', // CSS class applied to each form in a formset
  166 + extraClasses: [], // Additional CSS classes, which will be applied to each form in turn
  167 + added: null, // Function called each time a new form is added
  168 + removed: null // Function called each time a form is deleted
  169 + };
  170 +})(jQuery)
... ...
amadeus/static/js/topics.js
... ... @@ -73,4 +73,12 @@ function delete_topic(url) {
73 73  
74 74 $('.modal').modal('show');
75 75 });
76   -}
77 76 \ No newline at end of file
  77 +}
  78 +
  79 +$(".add_resource").on('show.bs.dropdown', function () {
  80 + $(this).find('i').switchClass("fa-angle-right", "fa-angle-down", 250, "easeInOutQuad");
  81 +});
  82 +
  83 +$(".add_resource").on('hide.bs.dropdown', function () {
  84 + $(this).find('i').switchClass("fa-angle-down", "fa-angle-right", 250, "easeInOutQuad");
  85 +});
78 86 \ No newline at end of file
... ...
amadeus/urls.py
... ... @@ -29,6 +29,7 @@ urlpatterns = [
29 29 url(r'^subjects/', include('subjects.urls', namespace = 'subjects')),
30 30 url(r'^groups/', include('students_group.urls', namespace = 'groups')),
31 31 url(r'^topics/', include('topics.urls', namespace = 'topics')),
  32 + url(r'^webpages/', include('webpage.urls', namespace = 'webpages')),
32 33 url(r'^mailsender/', include('mailsender.urls', namespace = 'mailsender')),
33 34 url(r'^security/', include('security.urls', namespace = 'security')),
34 35 url(r'^themes/', include('themes.urls', namespace = 'themes')),
... ...
pendencies/__init__.py 0 → 100644
pendencies/admin.py 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +from django.contrib import admin
  2 +
  3 +# Register your models here.
... ...
pendencies/apps.py 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +from django.apps import AppConfig
  2 +
  3 +
  4 +class PendenciesConfig(AppConfig):
  5 + name = 'pendencies'
... ...
pendencies/forms.py 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +# coding=utf-8
  2 +from django import forms
  3 +from django.utils.translation import ugettext_lazy as _
  4 +
  5 +from .models import Pendencies
  6 +
  7 +class PendenciesForm(forms.ModelForm):
  8 + class Meta:
  9 + model = Pendencies
  10 + fields = ['action', 'begin_date', 'end_date']
0 11 \ No newline at end of file
... ...
pendencies/migrations/0001_initial.py 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2017-01-19 21:09
  3 +from __future__ import unicode_literals
  4 +
  5 +from django.db import migrations, models
  6 +
  7 +
  8 +class Migration(migrations.Migration):
  9 +
  10 + initial = True
  11 +
  12 + dependencies = [
  13 + ]
  14 +
  15 + operations = [
  16 + migrations.CreateModel(
  17 + name='Pendencies',
  18 + fields=[
  19 + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
  20 + ('action', models.CharField(choices=[('view', 'Visualize'), ('create', 'Create'), ('answer', 'Answer'), ('access', 'Access')], max_length=100, verbose_name='Action')),
  21 + ('begin_date', models.DateTimeField(blank=True, null=True, verbose_name='Begin Date')),
  22 + ('end_date', models.DateTimeField(blank=True, null=True, verbose_name='End Date')),
  23 + ],
  24 + ),
  25 + ]
... ...
pendencies/migrations/0002_pendencies_resource.py 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2017-01-19 21:09
  3 +from __future__ import unicode_literals
  4 +
  5 +from django.db import migrations, models
  6 +import django.db.models.deletion
  7 +
  8 +
  9 +class Migration(migrations.Migration):
  10 +
  11 + initial = True
  12 +
  13 + dependencies = [
  14 + ('topics', '0005_resource'),
  15 + ('pendencies', '0001_initial'),
  16 + ]
  17 +
  18 + operations = [
  19 + migrations.AddField(
  20 + model_name='pendencies',
  21 + name='resource',
  22 + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='pendencies_resource', to='topics.Resource', verbose_name='Resource'),
  23 + ),
  24 + ]
... ...
pendencies/migrations/__init__.py 0 → 100644
pendencies/models.py 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +from django.db import models
  2 +from autoslug.fields import AutoSlugField
  3 +from django.utils.translation import ugettext_lazy as _
  4 +
  5 +from topics.models import Resource
  6 +
  7 +class Pendencies(models.Model):
  8 + action = models.CharField(_('Action'), max_length = 100, choices = (("view", _("Visualize")), ("create", _("Create")), ("answer", _("Answer")), ("access", _("Access"))))
  9 + begin_date = models.DateTimeField(_('Begin Date'), null = True, blank = True)
  10 + end_date = models.DateTimeField(_('End Date'), null = True, blank = True)
  11 + resource = models.ForeignKey(Resource, verbose_name = _('Resource'), related_name = 'pendencies_resource', null = True)
0 12 \ No newline at end of file
... ...
pendencies/tests.py 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +from django.test import TestCase
  2 +
  3 +# Create your tests here.
... ...
pendencies/views.py 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +from django.shortcuts import render
  2 +
  3 +# Create your views here.
... ...
students_group/migrations/0003_auto_20170119_1543.py 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2017-01-19 18:43
  3 +from __future__ import unicode_literals
  4 +
  5 +from django.db import migrations
  6 +
  7 +
  8 +class Migration(migrations.Migration):
  9 +
  10 + dependencies = [
  11 + ('students_group', '0002_auto_20170118_1800'),
  12 + ]
  13 +
  14 + operations = [
  15 + migrations.AlterModelOptions(
  16 + name='studentsgroup',
  17 + options={'ordering': ['name'], 'verbose_name': 'Students Group', 'verbose_name_plural': 'Students Groups'},
  18 + ),
  19 + ]
... ...
topics/migrations/0005_resource.py 0 → 100644
... ... @@ -0,0 +1,44 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2017-01-19 21:09
  3 +from __future__ import unicode_literals
  4 +
  5 +import autoslug.fields
  6 +from django.conf import settings
  7 +from django.db import migrations, models
  8 +import django.db.models.deletion
  9 +
  10 +
  11 +class Migration(migrations.Migration):
  12 +
  13 + dependencies = [
  14 + ('subjects', '0012_auto_20170112_1408'),
  15 + migrations.swappable_dependency(settings.AUTH_USER_MODEL),
  16 + ('students_group', '0003_auto_20170119_1543'),
  17 + ('topics', '0004_auto_20170118_1711'),
  18 + ]
  19 +
  20 + operations = [
  21 + migrations.CreateModel(
  22 + name='Resource',
  23 + fields=[
  24 + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
  25 + ('name', models.CharField(max_length=200, verbose_name='Name')),
  26 + ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True, verbose_name='Slug')),
  27 + ('brief_description', models.TextField(blank=True, verbose_name='Brief Description')),
  28 + ('show_window', models.BooleanField(default=False, verbose_name='Show in new window')),
  29 + ('all_students', models.BooleanField(default=False, verbose_name='All Students')),
  30 + ('visible', models.BooleanField(default=True, verbose_name='Visible')),
  31 + ('order', models.PositiveSmallIntegerField(null=True, verbose_name='Order')),
  32 + ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='Create Date')),
  33 + ('last_update', models.DateTimeField(auto_now=True, verbose_name='Last Update')),
  34 + ('groups', models.ManyToManyField(blank=True, related_name='resource_groups', to='students_group.StudentsGroup', verbose_name='Groups')),
  35 + ('students', models.ManyToManyField(blank=True, related_name='resource_students', to=settings.AUTH_USER_MODEL, verbose_name='Students')),
  36 + ('tags', models.ManyToManyField(blank=True, related_name='resource_tags', to='subjects.Tag', verbose_name='Markers')),
  37 + ('topic', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='resource_topic', to='topics.Topic', verbose_name='Topic')),
  38 + ],
  39 + options={
  40 + 'verbose_name': 'Resource',
  41 + 'verbose_name_plural': 'Resources',
  42 + },
  43 + ),
  44 + ]
... ...
topics/models.py
... ... @@ -2,7 +2,9 @@ from django.db import models
2 2 from autoslug.fields import AutoSlugField
3 3 from django.utils.translation import ugettext_lazy as _
4 4  
5   -from subjects.models import Subject
  5 +from subjects.models import Subject, Tag
  6 +from students_group.models import StudentsGroup
  7 +from users.models import User
6 8  
7 9 class Topic(models.Model):
8 10 name = models.CharField(_('Name'), max_length = 200)
... ... @@ -21,4 +23,26 @@ class Topic(models.Model):
21 23 ordering = ['order']
22 24  
23 25 def __str__(self):
24   - return self.name
25 26 \ No newline at end of file
  27 + return self.name
  28 +
  29 +class Resource(models.Model):
  30 + name = models.CharField(_('Name'), max_length = 200)
  31 + slug = AutoSlugField(_("Slug"), populate_from = 'name', unique = True)
  32 + brief_description = models.TextField(_('Brief Description'), blank = True)
  33 + show_window = models.BooleanField(_('Show in new window'), default = False)
  34 + all_students = models.BooleanField(_('All Students'), default = False)
  35 + visible = models.BooleanField(_('Visible'), default = True)
  36 + order = models.PositiveSmallIntegerField(_('Order'), null = True)
  37 + topic = models.ForeignKey(Topic, verbose_name = _('Topic'), related_name = "resource_topic", null = True)
  38 + students = models.ManyToManyField(User, verbose_name = _('Students'), related_name = 'resource_students', blank = True)
  39 + groups = models.ManyToManyField(StudentsGroup, verbose_name = _('Groups'), related_name = 'resource_groups', blank = True)
  40 + tags = models.ManyToManyField(Tag, verbose_name = _('Markers'), related_name = 'resource_tags', blank = True)
  41 + create_date = models.DateTimeField(_('Create Date'), auto_now_add = True)
  42 + last_update = models.DateTimeField(_('Last Update'), auto_now = True)
  43 +
  44 + class Meta:
  45 + verbose_name = _('Resource')
  46 + verbose_name_plural = _('Resources')
  47 +
  48 + def __str__(self):
  49 + return self.name
... ...
topics/templates/topics/list.html
... ... @@ -41,6 +41,23 @@
41 41 {% autoescape off %}
42 42 {{ topic.description }}
43 43 {% endautoescape %}
  44 +
  45 + {% if has_subject_permissions %}
  46 + <div class="row text-center">
  47 + <div class="btn-group add_resource">
  48 + <button type="button" class="btn btn-success btn-raised dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
  49 + <i class="fa fa-angle-right"></i> {% trans 'Add Resource' %}
  50 + </button>
  51 + <ul class="dropdown-menu">
  52 + <li><a href="#">{% trans 'Video Embed' %}</a></li>
  53 + <li><a href="#">{% trans 'Forum' %}</a></li>
  54 + <li><a href="#">{% trans 'File Link' %}</a></li>
  55 + <li><a href="{% url 'webpages:create' topic.slug %}">{% trans 'Webpage' %}</a></li>
  56 + <li><a href="#">{% trans 'Questionary' %}</a></li>
  57 + </ul>
  58 + </div>
  59 + </div>
  60 + {% endif %}
44 61 </div>
45 62 </div>
46 63 {% endif %}
... ...
webpage/__init__.py 0 → 100644
webpage/admin.py 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +from django.contrib import admin
  2 +
  3 +# Register your models here.
... ...
webpage/apps.py 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +from django.apps import AppConfig
  2 +
  3 +
  4 +class WebpageConfig(AppConfig):
  5 + name = 'webpage'
... ...
webpage/forms.py 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +# coding=utf-8
  2 +from django import forms
  3 +from django.forms.models import inlineformset_factory
  4 +from django.utils.translation import ugettext_lazy as _
  5 +
  6 +from pendencies.forms import PendenciesForm
  7 +from pendencies.models import Pendencies
  8 +
  9 +from .models import Webpage
  10 +
  11 +class WebpageForm(forms.ModelForm):
  12 + tags = forms.CharField(label = _('Tags'), required = False)
  13 +
  14 + class Meta:
  15 + model = Webpage
  16 + fields = ['name', 'content', 'brief_description', 'all_students', 'students', 'groups', 'show_window', 'visible']
  17 + widgets = {
  18 + 'content': forms.Textarea,
  19 + 'brief_description': forms.Textarea,
  20 + 'students': forms.SelectMultiple,
  21 + 'groups': forms.SelectMultiple,
  22 + }
  23 +
  24 +InlinePendenciesFormset = inlineformset_factory(Webpage, Pendencies, form = PendenciesForm, extra = 1, can_delete = True)
0 25 \ No newline at end of file
... ...
webpage/migrations/0001_initial.py 0 → 100644
... ... @@ -0,0 +1,30 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2017-01-19 21:09
  3 +from __future__ import unicode_literals
  4 +
  5 +from django.db import migrations, models
  6 +import django.db.models.deletion
  7 +
  8 +
  9 +class Migration(migrations.Migration):
  10 +
  11 + initial = True
  12 +
  13 + dependencies = [
  14 + ('topics', '0005_resource'),
  15 + ]
  16 +
  17 + operations = [
  18 + migrations.CreateModel(
  19 + name='Webpage',
  20 + fields=[
  21 + ('resource_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='topics.Resource')),
  22 + ('content', models.TextField(verbose_name='HTML Page Content')),
  23 + ],
  24 + options={
  25 + 'verbose_name': 'WebPage',
  26 + 'verbose_name_plural': 'WebPages',
  27 + },
  28 + bases=('topics.resource',),
  29 + ),
  30 + ]
... ...
webpage/migrations/__init__.py 0 → 100644
webpage/models.py 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +from django.db import models
  2 +from autoslug.fields import AutoSlugField
  3 +from django.utils.translation import ugettext_lazy as _
  4 +
  5 +from topics.models import Resource
  6 +
  7 +class Webpage(Resource):
  8 + content = models.TextField(_('HTML Page Content'))
  9 +
  10 + class Meta:
  11 + verbose_name = _('WebPage')
  12 + verbose_name_plural = _('WebPages')
  13 +
  14 + def __str__(self):
  15 + return self.name
0 16 \ No newline at end of file
... ...
webpage/templates/webpages/_form.html 0 → 100644
... ... @@ -0,0 +1,224 @@
  1 +{% load static i18n %}
  2 +{% load widget_tweaks %}
  3 +
  4 +<form method="post" action="" enctype="multipart/form-data">
  5 + {% csrf_token %}
  6 +
  7 + <div class="form-group{% if form.has_error %} has-error {% endif %} is-fileinput">
  8 + <label for="{{ form.name.auto_id }}">{{ form.name.label }} <span>*</span></label>
  9 + {% render_field form.name class='form-control' %}
  10 + </div>
  11 +
  12 + <div class="form-group{% if form.has_error %} has-error {% endif %} is-fileinput">
  13 + <label for="{{ form.content.auto_id }}">{{ form.content.label }} <span>*</span></label>
  14 + {% render_field form.content class='form-control text_wysiwyg' %}
  15 + </div>
  16 +
  17 + <legend>{% trans 'Common resources settings' %}</legend>
  18 +
  19 + <div class="form-group{% if form.has_error %} has-error {% endif %} is-fileinput">
  20 + <label for="{{ form.brief_description.auto_id }}">{{ form.brief_description.label }}</label>
  21 + {% render_field form.brief_description class='form-control text_wysiwyg' %}
  22 + </div>
  23 +
  24 + <div class="form-group{% if form.has_error %} has-error {% endif %} is-fileinput">
  25 + <label for="{{ form.tags.auto_id }}">{{ form.tags.label }}</label>
  26 + {% render_field form.tags class='form-control' data-role="tagsinput" %}
  27 + </div>
  28 +
  29 + <div class="panel-group" id="professors_accordion" role="tablist" aria-multiselectable="true">
  30 + <div class="panel panel-info">
  31 + <div class="panel-heading">
  32 + <div class="row">
  33 + <div class="col-md-12">
  34 + <a data-parent="#professors_accordion" data-toggle="collapse" href="#notifications">
  35 + <h4 class="panel-title">
  36 + <button class="btn btn-default btn-xs text-center cat-selector"><i class="fa fa-angle-right fa-2x" aria-hidden="true"></i></button><label>{% trans 'Pendencies Notifications' %}</label>
  37 + </h4>
  38 + </a>
  39 + </div>
  40 + </div>
  41 + </div>
  42 + <div id="notifications" class="panel-collapse collapse">
  43 + {{ pendencies_form.management_form }}
  44 + {{ pendencies_form.non_form_errors }}
  45 +
  46 + {% for notify in pendencies_form %}
  47 + <div class="notifies">
  48 + {% if notify.instance.pk %}{{ notify.DELETE }}{% endif %}
  49 + <div class="form-group{% if form.has_error %} has-error {% endif %}">
  50 + <label for="{{ notify.action.auto_id }}">
  51 + {{ notify.action.label }} {% render_field notify.action class='form-control' %}
  52 + </label>
  53 + </div>
  54 + <div class="form-group{% if form.has_error %} has-error {% endif %}">
  55 + <div class=" checkbox">
  56 + <label>
  57 + <input type="checkbox" class="begin_date" /> {{ notify.begin_date.label }}
  58 + </label>
  59 + {% render_field notify.begin_date class='form-control' %}
  60 + </div>
  61 + </div>
  62 + <div class="form-group{% if form.has_error %} has-error {% endif %}">
  63 + <div class=" checkbox">
  64 + <label>
  65 + <input type="checkbox" class="end_date" /> {{ notify.end_date.label }}
  66 + </label>
  67 + {% render_field notify.end_date class='form-control' %}
  68 + </div>
  69 + </div>
  70 + </div>
  71 + {% endfor %}
  72 + </div>
  73 + </div>
  74 +
  75 + <div class="panel panel-info">
  76 + <div class="panel-heading">
  77 + <div class="row">
  78 + <div class="col-md-12">
  79 + <a data-parent="#professors_accordion" data-toggle="collapse" href="#students">
  80 + <h4 class="panel-title">
  81 + <button class="btn btn-default btn-xs text-center cat-selector"><i class="fa fa-angle-right fa-2x" aria-hidden="true"></i></button><label for="{{ form.students.auto_id }}">{{ form.students.label }}</label>
  82 + </h4>
  83 + </a>
  84 + </div>
  85 + </div>
  86 + </div>
  87 + <div id="students" class="panel-collapse collapse">
  88 + <div class="form-group{% if form.has_error %} has-error {% endif %}">
  89 + <div class=" checkbox">
  90 + <label for="{{ form.all_students.auto_id }}">
  91 + {% render_field form.all_students %} {{ form.all_students.label }}
  92 + </label>
  93 + </div>
  94 + </div>
  95 +
  96 + <p><em>{% trans 'Attribute students to webpage' %}:</em></p>
  97 + {% render_field form.students class='form-control' %}
  98 +
  99 + <br clear="all" />
  100 +
  101 + <p><em>{% trans 'Attribute groups to webpage' %}:</em></p>
  102 + {% render_field form.groups class='form-control' %}
  103 + </div>
  104 + </div>
  105 + </div>
  106 +
  107 + <div class="form-group{% if form.has_error %} has-error {% endif %}">
  108 + <div class=" checkbox">
  109 + <label for="{{ form.show_window.auto_id }}">
  110 + {% render_field form.show_window %} {{ form.show_window.label }}
  111 + </label>
  112 + </div>
  113 + </div>
  114 +
  115 + <div class="form-group{% if form.has_error %} has-error {% endif %}">
  116 + <div class=" checkbox">
  117 + <label for="{{ form.visible.auto_id }}">
  118 + {% render_field form.visible %} {{ form.visible.label }}
  119 + </label>
  120 + </div>
  121 + </div>
  122 +
  123 + <div class="col-md-12 col-lg-12 col-sm-12 col-xs-12">
  124 + <div class="text-center">
  125 + <input type="submit" value="{% trans 'Save' %}" class="btn btn-raised btn-success" />
  126 + </div>
  127 + </div>
  128 +</form>
  129 +<script type="text/javascript">
  130 + $(function() {
  131 + $('.notifies').formset({
  132 + addText: '{% trans "Add new notification" %}',
  133 + deleteText: '{% trans "Remove this" %}'
  134 + });
  135 + });
  136 +
  137 + $('#id_groups').multiSelect({
  138 + selectableHeader: "<input type='text' class='search-input category-search-users' autocomplete='off' placeholder=' '>",
  139 + selectionHeader: "<input type='text' class='search-input category-search-users' autocomplete='off' placeholder=''>",
  140 + afterInit: function(ms){
  141 + var that = this,
  142 + $selectableSearch = that.$selectableUl.prev(),
  143 + $selectionSearch = that.$selectionUl.prev(),
  144 + selectableSearchString = '#'+that.$container.attr('id')+' .ms-elem-selectable:not(.ms-selected)',
  145 + selectionSearchString = '#'+that.$container.attr('id')+' .ms-elem-selection.ms-selected';
  146 +
  147 + that.qs1 = $selectableSearch.quicksearch(selectableSearchString)
  148 + .on('keydown', function(e){
  149 + if (e.which === 40){
  150 + that.$selectableUl.focus();
  151 + return false;
  152 + }
  153 + });
  154 +
  155 + that.qs2 = $selectionSearch.quicksearch(selectionSearchString)
  156 + .on('keydown', function(e){
  157 + if (e.which == 40){
  158 + that.$selectionUl.focus();
  159 + return false;
  160 + }
  161 + });
  162 + },
  163 + afterSelect: function(){
  164 + this.qs1.cache();
  165 + this.qs2.cache();
  166 + },
  167 + afterDeselect: function(){
  168 + this.qs1.cache();
  169 + this.qs2.cache();
  170 + }
  171 + });// Used to create multi-select css style
  172 +
  173 + $('#id_students').multiSelect({
  174 + selectableHeader: "<input type='text' class='search-input category-search-users' autocomplete='off' placeholder=' '>",
  175 + selectionHeader: "<input type='text' class='search-input category-search-users' autocomplete='off' placeholder=''>",
  176 + afterInit: function(ms){
  177 + var that = this,
  178 + $selectableSearch = that.$selectableUl.prev(),
  179 + $selectionSearch = that.$selectionUl.prev(),
  180 + selectableSearchString = '#'+that.$container.attr('id')+' .ms-elem-selectable:not(.ms-selected)',
  181 + selectionSearchString = '#'+that.$container.attr('id')+' .ms-elem-selection.ms-selected';
  182 +
  183 + that.qs1 = $selectableSearch.quicksearch(selectableSearchString)
  184 + .on('keydown', function(e){
  185 + if (e.which === 40){
  186 + that.$selectableUl.focus();
  187 + return false;
  188 + }
  189 + });
  190 +
  191 + that.qs2 = $selectionSearch.quicksearch(selectionSearchString)
  192 + .on('keydown', function(e){
  193 + if (e.which == 40){
  194 + that.$selectionUl.focus();
  195 + return false;
  196 + }
  197 + });
  198 + },
  199 + afterSelect: function(){
  200 + this.qs1.cache();
  201 + this.qs2.cache();
  202 + },
  203 + afterDeselect: function(){
  204 + this.qs1.cache();
  205 + this.qs2.cache();
  206 + }
  207 + });// Used to create multi-select css style
  208 +
  209 + $('.collapse').on('show.bs.collapse', function (e) {
  210 + if($(this).is(e.target)){
  211 + var btn = $(this).parent().find('.fa-angle-right');
  212 +
  213 + btn.switchClass("fa-angle-right", "fa-angle-down", 250, "easeInOutQuad");
  214 + }
  215 + });
  216 +
  217 + $('.collapse').on('hide.bs.collapse', function (e) {
  218 + if($(this).is(e.target)){
  219 + var btn = $(this).parent().find('.fa-angle-down');
  220 +
  221 + btn.switchClass("fa-angle-down", "fa-angle-right", 250, "easeInOutQuad");
  222 + }
  223 + });
  224 +</script>
0 225 \ No newline at end of file
... ...
webpage/templates/webpages/create.html 0 → 100644
... ... @@ -0,0 +1,35 @@
  1 +{% extends 'subjects/view.html' %}
  2 +
  3 +{% load static i18n django_bootstrap_breadcrumbs %}
  4 +
  5 +{% block style %}
  6 + {{block.super}}
  7 + <link rel="stylesheet" type="text/css" href="{% static "css/bootstrap-tagsinput.css" %}">
  8 +{% endblock %}
  9 +
  10 +{% block javascript %}
  11 + {{block.super}}
  12 + <script type="text/javascript" src="{% static "js/bootstrap-tagsinput.js" %} "></script>
  13 + <script type="text/javascript" src="{% static "js/jquery.formset.js" %} "></script>
  14 +{% endblock %}
  15 +
  16 +{% block breadcrumbs %}
  17 + {{ block.super }}
  18 +
  19 + {% breadcrumb topic 'subjects:view' topic.subject.slug %}
  20 +
  21 + {% trans 'Create Webpage' as bread %}
  22 + {% breadcrumb bread 'webpages:create' topic.slug %}
  23 +{% endblock %}
  24 +
  25 +{% block content %}
  26 + <div class="card">
  27 + <div class="card-content">
  28 + <div class="card-body">
  29 + {% include 'webpages/_form.html' %}
  30 + </div>
  31 + </div>
  32 + </div>
  33 + <br clear="all" />
  34 + <br clear="all" />
  35 +{% endblock %}
... ...
webpage/tests.py 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +from django.test import TestCase
  2 +
  3 +# Create your tests here.
... ...
webpage/urls.py 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +from django.conf.urls import url
  2 +from django.contrib.auth import views as auth_views
  3 +
  4 +from . import views
  5 +
  6 +urlpatterns = [
  7 + url(r'^create/(?P<slug>[\w_-]+)/$', views.CreateView.as_view(), name = 'create'),
  8 +]
... ...
webpage/views.py 0 → 100644
... ... @@ -0,0 +1,56 @@
  1 +from django.shortcuts import get_object_or_404, redirect, render
  2 +from django.views import generic
  3 +from django.contrib import messages
  4 +from django.core.urlresolvers import reverse, reverse_lazy
  5 +from django.utils.translation import ugettext_lazy as _
  6 +from django.contrib.auth.mixins import LoginRequiredMixin
  7 +
  8 +from amadeus.permissions import has_subject_permissions
  9 +
  10 +from topics.models import Topic
  11 +
  12 +from .forms import WebpageForm, InlinePendenciesFormset
  13 +from .models import Webpage
  14 +
  15 +class CreateView(LoginRequiredMixin, generic.edit.CreateView):
  16 + login_url = reverse_lazy("users:login")
  17 + redirect_field_name = 'next'
  18 +
  19 + template_name = 'webpages/create.html'
  20 + form_class = WebpageForm
  21 +
  22 + def dispatch(self, request, *args, **kwargs):
  23 + slug = self.kwargs.get('slug', '')
  24 + topic = get_object_or_404(Topic, slug = slug)
  25 +
  26 + if not has_subject_permissions(request.user, topic.subject):
  27 + return redirect(reverse_lazy('subjects:home'))
  28 +
  29 + return super(CreateView, self).dispatch(request, *args, **kwargs)
  30 +
  31 + def get(self, request, *args, **kwargs):
  32 + self.object = None
  33 +
  34 + form_class = self.get_form_class()
  35 + form = self.get_form(form_class)
  36 + pendencies_form = InlinePendenciesFormset()
  37 +
  38 + return self.render_to_response(self.get_context_data(form = form,pendencies_form = pendencies_form))
  39 +
  40 + def get_context_data(self, **kwargs):
  41 + context = super(CreateView, self).get_context_data(**kwargs)
  42 +
  43 + context['title'] = _('Create Webpage')
  44 +
  45 + slug = self.kwargs.get('slug', '')
  46 + topic = get_object_or_404(Topic, slug = slug)
  47 +
  48 + context['topic'] = topic
  49 + context['subject'] = topic.subject
  50 +
  51 + return context
  52 +
  53 + def get_success_url(self):
  54 + messages.success(self.request, _('Topic "%s" was created successfully!')%(self.object.name))
  55 +
  56 + return reverse_lazy('subjects:view', kwargs = {'slug': self.object.topic.subject.slug})
0 57 \ No newline at end of file
... ...