Commits

Kai Diefenbach committed 9b52575

First reasonable working version

Comments (0)

Files changed (18)

lfc_compositor/admin.py

 from django.contrib import admin
 
-# Add your admin site registrations here, eg.
-# from lfc_compositor.models import Author
-# admin.site.register(Author)
+from lfc_compositor.models import Composite
+admin.site.register(Composite)
+
+from lfc_compositor.models import Row
+admin.site.register(Row)

lfc_compositor/models.py

         """
         return Row.objects.filter(parent=self)
 
-    def render(self, request):
+    def render(self, request, edit=False):
         """
         """
+        rows = self.get_rows()
+        amount = len(rows)-1
         content = ""
-        for row in self.get_rows():
-            content += row.render(request)
+        for i, row in enumerate(self.get_rows()):
+            if i == 0:
+                is_first = True
+            else:
+                is_first = False
+
+            if i == amount:
+                is_last = True
+            else:
+                is_last = False
+
+            content += row.render(request, edit, is_first, is_last)
 
         return render_to_string("lfc_compositor/widgets/composite.html", RequestContext(request, {
             "composite" : self,
-            "content" : content
+            "content" : content,
+            "edit" : edit,
         }))
 
     def form(self, **kwargs):
         model = Composite
         fields = ("title", "display_title", "slug", "tags")
 
+    def extra(self, request):
+        return self.instance.render(request, True)
+
 class Row(models.Model):
     """A row for composite. A row can have multiple columns.
 
         The composite the of the row.
     """
     parent = models.ForeignKey(Composite, verbose_name=_(u"Parent"), related_name="rows")
-    position = models.IntegerField(default=1000)
+    position = models.IntegerField(default=1)
+    width = models.FloatField(default=100)
+
+    class Meta:
+        ordering = ("position", )
 
     def __unicode__(self):
         return "Row %s" % self.id
 
         return searchable_text.strip()
 
-    def render(self, request):
+    def render(self, request, edit=False, first_row=False, last_row=False):
+        columns = self.get_columns()
+        amount = len(columns) - 1
         content = ""
-        for column in self.get_columns():
-            content += column.render(request)
+        for i, column in enumerate(self.get_columns()):
+            if i == 0:
+                first_col = True
+            else:
+                first_col = False
+
+            if i == amount:
+                last_col = True
+            else:
+                last_col = False
+
+            content += column.render(request, edit, first_col, last_col)
 
         return render_to_string("lfc_compositor/widgets/row.html", RequestContext(request, {
             "row" : self,
-            "content" : content
+            "content" : content,
+            "edit" : edit,
+            "first_row" : first_row,
+            "last_row" : last_row,            
         }))
 
 class Column(models.Model):
         The composite the of the row.
     """
     parent = models.ForeignKey(Row, verbose_name=_(u"Parent"), related_name="columns")
-    position = models.IntegerField(default=1000)
+    position = models.IntegerField(default=1)
+    width = models.IntegerField(blank=True, null=True)
+
+    class Meta:
+        ordering = ("position", )
 
     def get_searchable_text(self):
         """
         """
         return self.widgets.order_by("position")
 
-    def render(self, request):
+    def render(self, request, edit=False, first_col=False, last_col=False):
         """
         """
+        widgets = self.get_widgets()
+        amount = len(widgets)-1
+        
         content = ""
-        for widget in self.get_widgets():
-            content += widget.render(request)
+        for i, widget in enumerate(widgets):
+
+            if i == 0:
+                first_widget = True
+            else:
+                first_widget = False
+
+            if i == amount:
+                last_widget = True
+            else:
+                last_widget = False
+            
+            content += widget.render(request, edit, first_widget, last_widget)
 
         columns = self.parent.columns.count()
 
             "content" : content,
             "column" : self,
             "width" : width,
+            "edit" : edit,
+            "deletable" : columns > 1,
+            "first_col" : first_col,
+            "last_col" : last_col,
         }))
 
 class Widget(models.Model):
         """
         return ""
 
-    def render(self, request):
-        return self.get_content_object().render(request)
+    def render(self, request, edit=False, first_widget=False, last_widget=False):
+        return self.get_content_object().render(request, edit, first_widget, last_widget)
 
 class TextWidget(Widget):
     """A simple text widget.
         """
         return TextWidgetForm(**kwargs)
 
-    def render(self, request):
+    def render(self, request, edit=False, first_widget=False, last_widget=False):
         return render_to_string("lfc_compositor/widgets/text.html", RequestContext(request, {
             "widget" : self,
+            "edit" : edit,
+            "first_widget" : first_widget, 
+            "last_widget" : last_widget,
         }))
 
 class TextWidgetForm(forms.ModelForm):
     class Meta:
         model = TextWidget
-        fields = ("position", "content", )
+        fields = ("content", )
 
 class ImageWidget(Widget):
     """An simple image widget.
         """
         return ImageWidgetForm(**kwargs)
 
-    def render(self, request):
+    def render(self, request, edit=False, first_widget=False, last_widget=False):
         """Renders the widget as HTML.
         """
         image_url = getattr(self.image, "url_%s" % self.get_size_display())
         return render_to_string("lfc_compositor/widgets/image.html", RequestContext(request, {
             "widget" : self,
             "image_url" : image_url,
+            "edit" : edit,
+            "first_widget" : first_widget, 
+            "last_widget" : last_widget,            
         }))
 
 class ImageWidgetForm(forms.ModelForm):
     class Meta:
         model = ImageWidget
-        fields = ("position", "size", "image", )
+        fields = ("size", "image", )
 
 class TextWithImageWidget(Widget):
     """A text with a image widget. The image can be at the left or right site.
         sizes=((60, 60), (100, 100), (200, 200), (400, 400), (600, 600), (800, 800)))
     image_position = models.IntegerField(_(u"Position"), default = LEFT)
     size = models.PositiveSmallIntegerField(_(u"Size"), choices=((0, "60x60"), (1, "100x100"), (2, "200x200"), (3, "400x400"), (4, "600x600"), (5, "800x800")), default=2)
-    
+
     def get_searchable_text(self):
         return self.content
 
         """
         return TextWithImageWidgetForm(**kwargs)
 
-    def render(self, request):
+    def render(self, request, edit=False, first_widget=False, last_widget=False):
         image_url = getattr(self.image, "url_%s" % self.get_size_display())
         return render_to_string("lfc_compositor/widgets/text_with_image.html", RequestContext(request, {
             "widget" : self,
             "image_url" : image_url,
             "IMAGE_LEFT" : self.image_position == LEFT,
+            "edit" : edit,
+            "first_widget" : first_widget, 
+            "last_widget" : last_widget,            
         }))
 
 class TextWithImageWidgetForm(forms.ModelForm):
     class Meta:
         model = TextWithImageWidget
-        fields = ("position", "image", "size",  "image_position", "content")
+        fields = ("image", "size",  "image_position", "content")
 
 class ReferenceWidget(Widget):
     """A widget to display existing content.
         The referenced content object.
     """
     reference = models.ForeignKey(BaseContent, verbose_name=_(u"Reference"), blank=True, null=True)
+    display_title = models.BooleanField(default=True)
+    display_link = models.BooleanField(default=False)
+    words = models.IntegerField(blank=True, null=True)
 
     def get_searchable_text(self):
         try:
         """
         return ReferenceWidgetForm(**kwargs)
 
-    def render(self, request):
+    def render(self, request, edit=False, first_widget=False, last_widget=False):
         # content = self.reference.get_content_object()
         return render_to_string("lfc_compositor/widgets/reference.html", RequestContext(request, {
             "widget" : self,
+            "edit" : edit,
+            "first_widget" : first_widget, 
+            "last_widget" : last_widget,            
         }))
 
 class ReferenceWidgetForm(forms.ModelForm):
     class Meta:
         model = ReferenceWidget
-        fields = ("position", "reference", )
+        fields = ("reference", "words", "display_title", "display_link")

lfc_compositor/static/compositor.css

     vertical-align: top;
 }
 
-#composite-dialog {
-    background-color:#eee;
-    display:none;
-    padding:15px 50px 15px 15px;
-    text-align:left;
-    border:2px solid #333;
-    z-index:1000;
+table.lfc-compositor-default {
+    width: 100%;
 }
 
+table.lfc-compositor-default td {
+    padding-right: 20px;
+}
 
-#overlay div.close {
-    background-image:url(../img/close.png);
-    position:absolute;
-    right:5px;
-    top:0px;
-    cursor:pointer;
-    height:35px;
-    width:35px;
-}
+table.lfc-compositor-default td.last {
+    padding-right: 0;
+}

lfc_compositor/static/compositor.js

 $(function() {
-    var overlay = $("#composite-dialog").overlay({ closeOnClick: false, api:true, speed:100, expose: {color: '#eee', loadSpeed:100 } });
-    $("a.compositor-edit").click(function() {
+    
+    overlay = $("#overlay").overlay({
+            closeOnClick: false,
+            oneInstance: false,
+            api:true,
+            speed:1,
+            expose: {color: '#222', loadSpeed:1 }
+    });
+    
+    $(".compositor-width").live("change", function() {
+        var url = $(this).attr("data");
+        var value = $(this).attr("value");
+        $.post(url, { "width" : value }, function(data) {            
+            $("#core-data-extra").html(data);
+        });
+    });
+    
+    $(".cp-hover").live("mouseover", function() {
+        var id = $(this).attr("id");
+        $("." + id).css("background-color", "#ddd");
+    })
+
+    $(".cp-hover").live("mouseout", function() {
+        var id = $(this).attr("id");
+        $("." + id).css("background-color", "transparent");        
+    })
+        
+    $(".compositor-link").live("click", function() {
+        var url = $(this).attr("href");
+        $.post(url, function(data) {
+            $("#core-data-extra").html(data);
+        })        
+        return false;
+    });    
+
+    $(".compositor-link-2").live("click", function() {
         var url = $(this).attr("href");
         $.get(url, function(data) {
-            $("#composite-dialog").html(data)
+            $("#overlay .content").html(data);
             overlay.load();
+        })        
+        return false;
+    });    
+
+    $(".compositor-form-button-2").live("click", function() {
+        $(this).parents("form:first").ajaxSubmit({
+            success : function(data) {
+                $("#core-data-extra").html(data);
+                overlay.close();
+            }
         })
+        return false;
+    });    
 
+    $(".compositor-form-button").live("click", function() {
+        // show_ajax_loading();
+        $(this).parents("form:first").ajaxSubmit({
+            success : function(data) {
+                $("#overlay .content").html(data);
+                overlay.load();
+
+                // hide_ajax_loading();
+            }
+        })
+        return false;
+    });    
+    
+    // Delete dialog
+    var compositor_delete_dialog = $("#compositor-yesno").overlay({ closeOnClick: false, api:true, loadSpeed: 1, expose: {color: '#222', loadSpeed:1 } });
+
+    $(".compositor-delete-link").live("click", function() {
+        $("#compositor-delete-url").html($(this).attr("href"));
+        compositor_delete_dialog.load();
         return false;
     });
+
+    var buttons = $("#compositor-yesno button").live("click", function(e) {
+        compositor_delete_dialog.close();
+        var yes = buttons.index(this) === 0;
+        var url = $("#compositor-delete-url").html();
+        if (yes) {
+            $.get(url, function(data) {
+                $("#core-data-extra").html(data);
+                overlay.close();
+            });
+        }
+    });
+    
 })

lfc_compositor/static/static

+../../parts/lfc_compositor/lfc_compositor/static

lfc_compositor/templates/lfc_compositor/composite.html

     <div>
         {% render %}
     </div>
-    <div id="composite-dialog"><div id="close"></div></div>
+
+    <div class="overlay" id="overlay">
+        <div class="content"></div>
+    </div>
 
 {% endblock %}

lfc_compositor/templates/lfc_compositor/widgets/add_form.html

+{% load i18n %}
+<form action="{% url compositor_add_widget %}"
+      method="POST"
+      enctype="multipart/form-data">
+
+    <h1>{% trans "Add Widget" %}</h1>
+
+    <table>
+        {% include "lfc/manage/lfc_form.html" %}
+    </table>
+    
+    <input type="hidden" name="type" value="{{ type }}" />
+    <input type="hidden" name="column_id" value="{{ column_id }}" />
+    
+    <input class="compositor-form-button-2"
+           type="submit" />
+</form>
+
+<script>
+    $(function() {
+        $("#id_content").cleditor();
+    })    
+</script>

lfc_compositor/templates/lfc_compositor/widgets/column.html

 {% load i18n %}
 
-<td width="{{ width }}%">
+<td class="column-{{ column.id }}" {% if column.width %}width="{{ column.width }}%"{% endif %}>
+    {% if edit %}
+        <div style="clear: both">
+            {% if deletable %}
+                <a class="cp-hover compositor-link compositor-delete-column"
+                   id="column-{{ column.id }}"
+                   href="{% url compositor_delete_column column.id %}">
+                    <img src="{{ MEDIA_URL }}lfc/icons/delete.png" alt='{% trans "Delete Column" %}' title='{% trans "Delete Column" %}'/>
+                </a>
+            {% endif %}
+            {% if not first_col %}
+                <a class="cp-hover compositor-link"
+                   id="column-{{ column.id }}"
+                   href="{% url compositor_move_column column.id %}?direction=0">
+                    <img src="{{ MEDIA_URL }}lfc/icons/arrow_left.png" alt='{% trans "Left" %}' title='{% trans "Left" %}' />
+                </a>                
+            {% endif %}
+            {% if not last_col %}
+                <a class="cp-hover compositor-link"
+                   id="column-{{ column.id }}"
+                   href="{% url compositor_move_column column.id %}?direction=1">
+                    <img src="{{ MEDIA_URL }}lfc/icons/arrow_right.png" alt='{% trans "Right" %}' title='{% trans "Right" %}' />
+                </a>
+            {% endif %}
+            <input type="text"
+                   style="width:40px"
+                   {% if column.width %}value="{{ column.width }}{% endif %}"
+                   data="{% url compositor_change_width column.id %}"
+                   class="compositor-width" />
+       </div>
 
-    {% if request.user.is_superuser %}
-        <a href="{% url compositor_delete_column column.id %}">delete column</a>
-        <form action="{% url compositor_add_widget column.id %}">
+        {{ content|safe }}
+
+        <form style="clear: both; padding: 10px 0" action="{% url compositor_add_widget_form %}"
+              method="POST">
             <select name="type">
                 <option value="textwidget">{% trans "Text" %}</option>
                 <option value="imagewidget">{% trans "Image" %}</option>
                 <option value="textwithimagewidget">{% trans "Text with Image" %}</option>
                 <option value="referencewidget">{% trans "Reference" %}</option>
             </select>
-            <input type="submit" value='{% trans "Go" %}' />
+
+            <input type="hidden" name="column_id" value="{{ column.id }}">
+            <input class="compositor-form-button" type="submit" value='{% trans "Add Widget" %}' />
         </form>
+    {% else %}
+        {{ content|safe }}
     {% endif %}
-
-    {{ content|safe }}
 </td>

lfc_compositor/templates/lfc_compositor/widgets/composite.html

+{% load i18n %}
 {{ content|safe }}
-{% if request.user.is_superuser %}
-    <a href="{% url compositor_add_row composite.id %}">add row</a>
+{% if edit %}
+    <div>
+        <a class="compositor-link" 
+           href="{% url compositor_add_row composite.id %}">
+           <img src="{{ MEDIA_URL }}lfc/icons/add.png" alt='{% trans "Add Row" %}' title='{% trans "Add Row" %}'/>           
+        </a>
+    </div>
 {% endif %}

lfc_compositor/templates/lfc_compositor/widgets/form.html

         {% include "lfc/manage/lfc_form.html" %}
     </table>
 
-    <input type="submit" />
-</form>
+    <input class="compositor-form-button-2" 
+           type="submit" />
+</form>
+
+<script>
+    $(function() {
+        $("#id_content").cleditor();
+    })    
+</script>

lfc_compositor/templates/lfc_compositor/widgets/image.html

+{% load i18n %}
 <div>
-    <img alt="image" src="{{ image_url }}" />
-    {% if request.user.is_superuser %}
-        <div>
-            <a class="compositor-edit" href="{% url compositor_get_widget_form widget.id %}">Edit</a>
-            <a class="compositor-delete" href="{% url compositor_delete_widget widget.id %}">Delete</a>
-        </div>
+    {% if edit %}
+        {% include "lfc_compositor/widgets/widget_navigation.html" %}
     {% endif %}
+    <img class="widget-{{ widget.id }}" 
+         alt="image" src="{{ image_url }}" />
 </div>

lfc_compositor/templates/lfc_compositor/widgets/reference.html

+{% load i18n %}
 <div>
-    {{ widget.reference.get_content_object.text|safe }}
-    {% if request.user.is_superuser %}
-        <div>
-            <a class="compositor-edit" href="{% url compositor_get_widget_form widget.id %}">Edit</a>
-            <a class="compositor-delete" href="{% url compositor_delete_widget widget.id %}">Delete</a>
-        </div>
+    {% if edit %}
+        {% include "lfc_compositor/widgets/widget_navigation.html" %}
     {% endif %}
+    <div class="widget-{{ widget.id }}">
+        {% if widget.display_title %}
+            <h1>
+                <a href="{{ widget.reference.get_content_object.get_absolute_url }}">{{ widget.reference.get_content_object.title }}</a>                
+            </h1>
+        {% endif %}
+        {% if widget.words %}
+            {{ widget.reference.get_content_object.text|truncatewords_html:widget.words|safe }}
+        {% else %}
+            {{ widget.reference.get_content_object.text|safe }}
+        {% endif %}
+        
+        {% if widget.display_link %}
+            <p><a href="{{ widget.reference.get_content_object.get_absolute_url }}">{% trans "More" %}</a></p>
+        {% endif %}
+    </div>
 <div>

lfc_compositor/templates/lfc_compositor/widgets/row.html

-{% if request.user.is_superuser %}
-    <div>
-        <a href="{% url compositor_delete_row row.id %}">delete row</a>
-        <a href="{% url compositor_add_column row.id %}">add column</a>
+{% load i18n %}
+{% if edit %}
+    <div style="background-color: transparent">
+
+        {% if not first_row %}
+            <a class="cp-hover compositor-link"
+               id="row-{{ row.id }}"
+               href="{% url compositor_move_row row.id %}?direction=0">
+               <img src="{{ MEDIA_URL }}lfc/icons/arrow_up.png" alt='{% trans "Up" %}' title='{% trans "Up" %}' />
+            </a>
+        {% endif %}
+
+        {% if not last_row %}
+            <a class="cp-hover compositor-link"
+               id="row-{{ row.id }}"
+               href="{% url compositor_move_row row.id %}?direction=1">
+               <img src="{{ MEDIA_URL }}lfc/icons/arrow_down.png" alt='{% trans "Down" %}' title='{% trans "Down" %}' />
+            </a>
+        {% endif %}
+
+        <a class="cp-hover compositor-link"
+           id="row-{{ row.id }}"
+           href="{% url compositor_delete_row row.id %}">
+            <img src="{{ MEDIA_URL }}lfc/icons/delete.png" alt='{% trans "Delete Row" %}' title='{% trans "Delete Row" %}'/>
+        </a>
+        <a class="compositor-link"
+           href="{% url compositor_add_column row.id %}">
+            <img src="{{ MEDIA_URL }}lfc/icons/add.png" alt='{% trans "Add Column" %}' title='{% trans "Add Column" %}'/>
+        </a>
     </div>
 {% endif %}
-<table class="lfc-compositor-default" {% if request.user.is_superuser %}border="1"{% endif %}>
-    <tr>{{ content|safe }}</tr>
+<table class="row-{{ row.id }} lfc-compositor-default">
+    <tr class="compositor-row row-{{ row.id }}" >{{ content|safe }}</tr>
 </table>

lfc_compositor/templates/lfc_compositor/widgets/text.html

+{% load i18n %}
 <div>
-    <p>
+    {% if edit %}
+        {% include "lfc_compositor/widgets/widget_navigation.html" %}
+    {% endif %}
+    <div class="widget-{{ widget.id }}">
         {{ widget.content|safe }} 
-    </p>
-    {% if request.user.is_superuser %}
-        <div>
-            <a class="compositor-edit" href="{% url compositor_get_widget_form widget.id %}">Edit</a> |
-            <a class="compositor-delete" href="{% url compositor_delete_widget widget.id %}">Delete</a>
-        </div>
-    {% endif %}
+    </div>
 <div>

lfc_compositor/templates/lfc_compositor/widgets/text_with_image.html

+{% load i18n %}
 <div>
+    {% if edit %}
+        {% include "lfc_compositor/widgets/widget_navigation.html" %}
+    {% endif %}
+
     {% if IMAGE_LEFT  %}
-        <img alt="image" class="left" src="{{ image_url }}" /><p>{{ widget.content|safe }}</p>
+        <img alt="image" class="widget-{{ widget.id }} left" src="{{ image_url }}" /><p>{{ widget.content|safe }}</p>
     {% else %}
-        <img alt="image" class="right" src="{{ image_url }}" /><p>{{ widget.content|safe }}</p>
-    {% endif %}
-    {% if request.user.is_superuser %}
-        <div>
-            <a class="compositor-edit" href="{% url compositor_get_widget_form widget.id %}">Edit</a>
-            <a class="compositor-delete" href="{% url compositor_delete_widget widget.id %}">Delete</a>
-        </div>
+        <img alt="image" class="widget-{{ widget.id }} right" src="{{ image_url }}" /><p>{{ widget.content|safe }}</p>
     {% endif %}
 </div>

lfc_compositor/templates/lfc_compositor/widgets/widget_navigation.html

+{% load i18n %}
+<div style="clear: both; background-color: transparent">
+    {% if not first_widget %}
+        <a class="compositor-link"
+           id="widget-{{ widget.id }}"
+           href="{% url compositor_move_widget widget.id %}?direction=0">
+            <img src="{{ MEDIA_URL }}lfc/icons/arrow_up.png" alt='{% trans "Up" %}' title='{% trans "Up" %}' />
+        </a>
+    {% endif %}
+
+    {% if not last_widget %}
+        <a class="compositor-link"
+           id="widget-{{ widget.id }}"
+           href="{% url compositor_move_widget widget.id %}?direction=1">
+            <img src="{{ MEDIA_URL }}lfc/icons/arrow_down.png" alt='{% trans "Down" %}' title='{% trans "Down" %}' />
+        </a>
+    {% endif %}
+    <a class="cp-hover compositor-delete-link" id="widget-{{ widget.id }}" href="{% url compositor_delete_widget widget.id %}">
+       <img src="{{ MEDIA_URL }}lfc/icons/delete.png" alt='{% trans "Delete Widget" %}' title='{% trans "Delete Widget" %}'/>
+    </a>
+    <a class="cp-hover compositor-link-2" id="widget-{{ widget.id }}" href="{% url compositor_edit_widget_form widget.id %}">
+       <img src="{{ MEDIA_URL }}lfc/icons/edit.png" alt='{% trans "Edit" %}' title='{% trans "Edit" %}'/>
+    </a>
+</div>

lfc_compositor/urls.py

     url(r'^delete-column/(?P<id>\d*)$', "delete_column", name="compositor_delete_column"),
     
     
-    url(r'^add-widget/(?P<id>\d*)$', "add_widget", name="compositor_add_widget"),
+    url(r'^add-widget$', "add_widget", name="compositor_add_widget"),
+    url(r'^add-widget-form$', "add_widget_form", name="compositor_add_widget_form"),
 
-    url(r'^get-widget-form/(?P<id>\d*)$', "get_widget_form", name="compositor_get_widget_form"),
+    url(r'^edit-widget-form/(?P<id>\d*)$', "edit_widget_form", name="compositor_edit_widget_form"),
     url(r'^save-widget/(?P<id>\d*)$', "save_widget", name="compositor_save_widget"),
     url(r'^delete-widget/(?P<id>\d*)$', "delete_widget", name="compositor_delete_widget"),
 
+    url(r'^move-column/(?P<id>\d*)$', "move_column", name="compositor_move_column"),
+    url(r'^move-row/(?P<id>\d*)$', "move_row", name="compositor_move_row"),
+    url(r'^move-widget/(?P<id>\d*)$', "move_widget", name="compositor_move_widget"),
+    url(r'^change-width/(?P<id>\d*)$', "change_width", name="compositor_change_width"),
+
 )

lfc_compositor/views.py

 from lfc_compositor.models import Row
 from lfc_compositor.models import Widget
 
+def change_width(request, id):
+    """Changes the width of the column with passed id.
+    """
+    column = Column.objects.get(pk=id)
+    try:
+        width = request.POST.get("width")
+    except ValueError:
+        pass
+    else:
+        column.width = width
+        column.save()
+
+    composite = _get_composite(column)
+    return HttpResponse(composite.render(request, edit=True))
+
+def move_column(request, id):
+    """Moves passed column to passed direction.
+    """
+    column = Column.objects.get(pk=id)
+    direction = request.REQUEST.get("direction", "0")
+
+    if direction == "1":
+        column.position += 15
+    else:
+        column.position -= 15
+        if column.position < 0:
+            column.position = 0
+    column.save()
+    update_columns(column.parent)
+
+    composite = _get_composite(column)
+    return HttpResponse(composite.render(request, edit=True))
+
+def move_row(request, id):
+    """Moves passed column to passed direction.
+    """
+    row = Row.objects.get(pk=id)
+    direction = request.REQUEST.get("direction", "0")
+
+    if direction == "1":
+        row.position += 15
+    else:
+        row.position -= 15
+        if row.position < 0:
+            row.position = 0
+    row.save()
+
+    composite = _get_composite(row)
+    update_rows(composite)
+    return HttpResponse(composite.render(request, edit=True))
+
+def move_widget(request, id):
+    """Moves passed column to passed direction.
+    """
+    widget = Widget.objects.get(pk=id)
+    direction = request.REQUEST.get("direction", "0")
+
+    if direction == "1":
+        widget.position += 15
+    else:
+        widget.position -= 15
+        if widget.position < 0:
+            widget.position = 0
+
+    widget.save()
+    composite = _get_composite(widget)
+    update_widgets(widget.parent)
+
+    return HttpResponse(composite.render(request, edit=True))
+
 def save_widget(request, id):
     """Save the widget with the passed id. Data is passed via POST request.
     """
     if form.is_valid():
         form.save()
 
-    return HttpResponseRedirect(_get_composite(widget).get_absolute_url())
+    composite = _get_composite(widget)
+    return HttpResponse(composite.render(request, edit=True))
 
-def get_widget_form(request, id, template="lfc_compositor/widgets/form.html"):
+def edit_widget_form(request, id, template="lfc_compositor/widgets/form.html"):
     """Returns the form of the widget with the id.
     """
     widget = Widget.objects.get(pk=id)
 
     return HttpResponse(html)
 
+def add_row(request, id):
+    """Adds a row to the composite with passed id.
+    """
+    composite = Composite.objects.get(pk=id)
+
+    amount = Row.objects.filter(parent=composite).count()
+    row = Row.objects.create(parent=composite, position=amount*10)
+    Column.objects.create(parent=row, position=10)
+
+    return HttpResponse(composite.render(request, edit=True))
+
+def add_column(request, id):
+    """Adds a column to the row with passed id.
+    """
+    row = Row.objects.get(pk=id)
+
+    amount = Column.objects.filter(parent=row).count()
+    column = Column.objects.create(parent=row, position=amount*10)
+    update_columns(column.parent)
+    composite = _get_composite(row)
+    return HttpResponse(composite.render(request, edit=True))
+
+def add_widget_form(request, template="lfc_compositor/widgets/add_form.html"):
+    """Display the add form for a widget with passed type.
+    """
+    column_id = request.POST.get("column_id")
+    type = request.POST.get("type")
+    ct = ContentType.objects.filter(model=type)[0]
+    mc = ct.model_class()
+    form = mc().form()
+
+    html = render_to_string(template, RequestContext(request, {
+        "form" : form,
+        "column_id" : column_id,
+        "type" : type,
+    }))
+
+    return HttpResponse(html)
+
+def add_widget(request):
+    """Adds a widget.
+    """
+    column_id = request.POST.get("column_id")
+    column = Column.objects.get(pk=column_id)
+
+    amount = Widget.objects.filter(parent=column).count()
+
+    type = request.POST.get("type")
+    ct = ContentType.objects.filter(model=type)[0]
+    mc = ct.model_class()
+    form = mc().form(data=request.POST, files=request.FILES)
+
+    widget = form.save(commit=False)
+    widget.parent = column
+    widget.position = amount*10
+    widget.save()
+
+    update_widgets(column)
+
+    composite = _get_composite(column)
+    return HttpResponse(composite.render(request, edit=True))
+
+def delete_column(request, id):
+    """Deletes the column with passed id
+    """
+    try:
+        column = Column.objects.get(pk=id)
+    except Column.DoesNotExist:
+        pass
+    else:
+        composite = _get_composite(column)
+        row = column.parent
+        column.delete()
+
+    update_columns(row)
+    return HttpResponse(composite.render(request, edit=True))
+
+def delete_row(request, id):
+    """Deletes row with passed id.
+    """
+    try:
+        row = Row.objects.get(pk=id)
+    except Row.DoesNotExist:
+        pass
+    else:
+        composite = _get_composite(row)
+        row.delete()
+
+    update_rows(composite)
+    return HttpResponse(composite.render(request, edit=True))
+
+def delete_widget(request, id):
+    """Deletes the widget with the passed id.
+    """
+    try:
+        widget = Widget.objects.get(pk=id)
+    except Widget.DoesNotExist:
+        pass
+    else:
+        composite = _get_composite(widget)
+        widget.delete()
+
+    return HttpResponse(composite.render(request, edit=True))
+
 def _get_composite(obj):
     composite = obj
     while isinstance(composite, Composite) == False:
 
     return composite
 
-def add_row(request, id):
-    """
-    """
-    composite = Composite.objects.get(pk=id)
-    row = Row.objects.create(parent=composite)
+def update_widgets(column):
+    for i, widget in enumerate(Widget.objects.filter(parent=column)):
+        widget.position = (i+1) * 10
+        widget.save()
 
-    return HttpResponseRedirect(composite.get_absolute_url())
+def update_rows(composite):
+    for i, row in enumerate(Row.objects.filter(parent=composite)):
+        row.position = (i+1) * 10
+        row.save()
 
-def delete_row(request, id):
-    """
-    """
-    try:
-        row = Row.objects.get(pk=id)
-    except Row.DoesNotExist:
-        pass
-    else:
-        row.delete()
-
-    return HttpResponseRedirect(request.META.get("HTTP_REFERER"))
-
-def add_column(request, id):
-    """
-    """
-    row = Row.objects.get(pk=id)
-    column = Column.objects.create(parent=row)
-
-    return HttpResponseRedirect(_get_composite(row).get_absolute_url())
-
-def delete_column(request, id):
-    """
-    """
-    try:
-        column = Column.objects.get(pk=id)
-    except Column.DoesNotExist:
-        pass
-    else:
-        column.delete()
-
-    return HttpResponseRedirect(request.META.get("HTTP_REFERER"))
-
-def add_widget(request, id):
-    """
-    """
-    column = Column.objects.get(pk=id)
-
-    type = request.REQUEST.get("type")
-    ct = ContentType.objects.filter(model=type)[0]
-    mc = ct.model_class()
-    form = mc().form
-
-    mc.objects.create(parent=column)
-
-    return HttpResponseRedirect(_get_composite(column).get_absolute_url())
-
-def delete_widget(request, id):
-    """
-    """
-    try:
-        widget = Widget.objects.get(pk=id)
-    except Widget.DoesNotExist:
-        pass
-    else:
-        widget.delete()
-
-    return HttpResponseRedirect(request.META.get("HTTP_REFERER"))
+def update_columns(row):
+    for i, column in enumerate(Column.objects.filter(parent=row)):
+        column.position = (i+1) * 10
+        column.save()