We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add live preview when editing static documents
When editing static document, let's split the screen vertically if it's width is more than 1920px, and horizontally otherwise, and add a live rendering when contents of the HTML editor area change. In the preview mode, use the same wrapper divs to make sure we pick up all styles and render the page as close to the final output as possible.

Quick illustration: http://www.htmlinstant.com/ or http://htmledit.squarefree.com/

Mockup screenshot:
![static_preview](https://cloud.githubusercontent.com/assets/1728158/7848828/1326968e-0484-11e5-856e-96a461976cdc.png)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pootle/apps/staticpages/urls.py`
Content:
```
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # Copyright (C) Pootle contributors.
5 #
6 # This file is a part of the Pootle project. It is distributed under the GPL3
7 # or later license. See the LICENSE file for a copy of the license and the
8 # AUTHORS file for copyright and authorship information.
9 
10 from django.conf.urls import include, patterns, url
11 
12 from .views import (AdminTemplateView, PageCreateView, PageDeleteView,
13                     PageUpdateView)
14 
15 
16 page_patterns = patterns('',
17     url(r'^legal/agreement/$',
18         'staticpages.views.legal_agreement',
19         name='pootle-staticpages-legal-agreement'),
20     url(r'^(?P<virtual_path>.+)/$',
21         'staticpages.views.display_page',
22         name='pootle-staticpages-display'),
23 )
24 
25 admin_patterns = patterns('',
26     url(r'^$',
27         AdminTemplateView.as_view(),
28         name='pootle-staticpages'),
29 
30     url(r'^(?P<page_type>[^/]+)/add/?$',
31         PageCreateView.as_view(),
32         name='pootle-staticpages-create'),
33     url(r'^(?P<page_type>[^/]+)/(?P<pk>\d+)/?$',
34         PageUpdateView.as_view(),
35         name='pootle-staticpages-edit'),
36     url(r'^(?P<page_type>[^/]+)/(?P<pk>\d+)/delete/?$',
37         PageDeleteView.as_view(),
38         name='pootle-staticpages-delete'),
39 )
40 
41 
42 urlpatterns = patterns('',
43     url(r'^pages/',
44         include(page_patterns)),
45 )
46
```

Path: `pootle/apps/staticpages/views.py`
Content:
```
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # Copyright (C) Pootle contributors.
5 #
6 # This file is a part of the Pootle project. It is distributed under the GPL3
7 # or later license. See the LICENSE file for a copy of the license and the
8 # AUTHORS file for copyright and authorship information.
9 
10 from django.core.exceptions import ObjectDoesNotExist
11 from django.core.urlresolvers import reverse_lazy
12 from django.http import Http404
13 from django.shortcuts import redirect, render
14 from django.template import loader, RequestContext
15 from django.utils.translation import ugettext_lazy as _
16 from django.views.generic import (CreateView, DeleteView, TemplateView,
17                                   UpdateView)
18 
19 from pootle.core.http import JsonResponse, JsonResponseBadRequest
20 from pootle.core.views import SuperuserRequiredMixin
21 from pootle_misc.util import ajax_required
22 
23 from .forms import agreement_form_factory
24 from .models import AbstractPage, LegalPage, StaticPage
25 
26 
27 ANN_TYPE = u'announcements'
28 ANN_VPATH = ANN_TYPE + u'/'
29 
30 
31 class PageModelMixin(object):
32     """Mixin used to set the view's page model according to the
33     `page_type` argument caught in a url pattern.
34     """
35 
36     def dispatch(self, request, *args, **kwargs):
37         self.page_type = kwargs.get('page_type', None)
38         self.model = {
39             'legal': LegalPage,
40             'static': StaticPage,
41             ANN_TYPE: StaticPage,
42         }.get(self.page_type)
43 
44         if self.model is None:
45             raise Http404
46 
47         return super(PageModelMixin, self).dispatch(request, *args, **kwargs)
48 
49     def get_context_data(self, **kwargs):
50         ctx = super(PageModelMixin, self).get_context_data(**kwargs)
51         ctx.update({
52             'has_page_model': True,
53             'page_display_name': self.model.display_name,
54         })
55         return ctx
56 
57     def get_form_kwargs(self):
58         kwargs = super(PageModelMixin, self).get_form_kwargs()
59         kwargs.update({'label_suffix': ''})
60         return kwargs
61 
62     def get_form(self, form_class):
63         form = super(PageModelMixin, self).get_form(form_class)
64 
65         if self.page_type == ANN_TYPE:
66             form.fields['virtual_path'].help_text = u'/pages/' + ANN_VPATH
67 
68         return form
69 
70     def form_valid(self, form):
71         if (self.page_type == ANN_TYPE and not
72             form.cleaned_data['virtual_path'].startswith(ANN_VPATH)):
73             orig_vpath = form.cleaned_data['virtual_path']
74             form.instance.virtual_path = ANN_VPATH + orig_vpath
75 
76         return super(PageModelMixin, self).form_valid(form)
77 
78 
79 class AdminCtxMixin(object):
80 
81     def get_context_data(self, **kwargs):
82         ctx = super(AdminCtxMixin, self).get_context_data(**kwargs)
83         ctx.update({
84             'page': 'admin-pages',
85         })
86         return ctx
87 
88 
89 class AdminTemplateView(SuperuserRequiredMixin, AdminCtxMixin, TemplateView):
90 
91     template_name = 'admin/staticpages/page_list.html'
92 
93     def get_context_data(self, **kwargs):
94         legal_pages = LegalPage.objects.all()
95         static_pages = StaticPage.objects.exclude(
96             virtual_path__startswith=ANN_VPATH,
97         )
98         announcements = StaticPage.objects.filter(
99             virtual_path__startswith=ANN_VPATH,
100         )
101 
102         ctx = super(AdminTemplateView, self).get_context_data(**kwargs)
103         ctx.update({
104             'legalpages': legal_pages,
105             'staticpages': static_pages,
106             ANN_TYPE: announcements,
107         })
108         return ctx
109 
110 
111 class PageCreateView(SuperuserRequiredMixin, AdminCtxMixin, PageModelMixin, CreateView):
112     fields = ('title', 'virtual_path', 'active', 'url', 'body')
113 
114     success_url = reverse_lazy('pootle-staticpages')
115     template_name = 'admin/staticpages/page_create.html'
116 
117     def get_initial(self):
118         initial = super(PageModelMixin, self).get_initial()
119 
120         initial_args = {
121             'title': _('Page Title'),
122         }
123 
124         if self.page_type != ANN_TYPE:
125             next_page_number = AbstractPage.max_pk() + 1
126             initial_args['virtual_path'] = 'page-%d' % next_page_number
127 
128         initial.update(initial_args)
129 
130         return initial
131 
132     def get_form(self, form_class):
133         form = super(PageCreateView, self).get_form(form_class)
134 
135         if self.page_type == ANN_TYPE:
136             del form.fields['url']
137             # Translators: 'projects' must not be translated.
138             msg = _(u'projects/<project_code> or <language_code> or '
139                     u'<language_code>/<project_code>')
140             form.fields['virtual_path'].widget.attrs['placeholder'] = msg
141             form.fields['virtual_path'].widget.attrs['size'] = 60
142 
143         return form
144 
145 
146 class PageUpdateView(SuperuserRequiredMixin, AdminCtxMixin, PageModelMixin, UpdateView):
147     fields = ('title', 'virtual_path', 'active', 'url', 'body')
148 
149     success_url = reverse_lazy('pootle-staticpages')
150     template_name = 'admin/staticpages/page_update.html'
151 
152     def get_context_data(self, **kwargs):
153         ctx = super(PageUpdateView, self).get_context_data(**kwargs)
154         ctx.update({
155             'show_delete': True,
156             'page_type': self.page_type,
157         })
158         return ctx
159 
160     def get_form_kwargs(self):
161         kwargs = super(PageUpdateView, self).get_form_kwargs()
162 
163         if self.page_type == ANN_TYPE:
164             orig_vpath = self.object.virtual_path
165             self.object.virtual_path = orig_vpath.replace(ANN_VPATH, '')
166             kwargs.update({'instance': self.object})
167 
168         return kwargs
169 
170 
171 class PageDeleteView(SuperuserRequiredMixin, PageModelMixin, DeleteView):
172 
173     success_url = reverse_lazy('pootle-staticpages')
174 
175 
176 def display_page(request, virtual_path):
177     """Displays an active page defined in `virtual_path`."""
178     page = None
179     for page_model in AbstractPage.__subclasses__():
180         try:
181             page = page_model.objects.live(request.user).get(
182                     virtual_path=virtual_path,
183                 )
184         except ObjectDoesNotExist:
185             pass
186 
187     if page is None:
188         raise Http404
189 
190     if page.url:
191         return redirect(page.url)
192 
193     template_name = 'staticpages/page_display.html'
194     if request.is_ajax():
195         template_name = 'staticpages/_body.html'
196 
197     ctx = {
198         'page': page,
199     }
200     return render(request, template_name, ctx)
201 
202 
203 def _get_rendered_agreement(request, form):
204     template = loader.get_template('staticpages/agreement.html')
205     return template.render(RequestContext(request, {'form': form}))
206 
207 
208 @ajax_required
209 def legal_agreement(request):
210     """Displays the pending documents to be agreed by the current user."""
211     pending_pages = LegalPage.objects.pending_user_agreement(request.user)
212     form_class = agreement_form_factory(pending_pages, request.user)
213 
214     if request.method == 'POST':
215         form = form_class(request.POST)
216 
217         if form.is_valid():
218             form.save()
219             return JsonResponse({})
220 
221         rendered_form = _get_rendered_agreement(request, form)
222         return JsonResponseBadRequest({'form': rendered_form})
223 
224     rendered_form = _get_rendered_agreement(request, form_class())
225     return JsonResponse({'form': rendered_form})
226
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pootle/apps/staticpages/urls.py b/pootle/apps/staticpages/urls.py
--- a/pootle/apps/staticpages/urls.py
+++ b/pootle/apps/staticpages/urls.py
@@ -39,7 +39,16 @@
 )
 
 
+xhr_patterns = patterns('',
+    url(r'^preview/?$',
+        'staticpages.views.preview_content',
+        name='pootle-xhr-preview'),
+)
+
+
 urlpatterns = patterns('',
     url(r'^pages/',
         include(page_patterns)),
+    url(r'^xhr/',
+        include(xhr_patterns)),
 )
diff --git a/pootle/apps/staticpages/views.py b/pootle/apps/staticpages/views.py
--- a/pootle/apps/staticpages/views.py
+++ b/pootle/apps/staticpages/views.py
@@ -17,6 +17,7 @@
                                   UpdateView)
 
 from pootle.core.http import JsonResponse, JsonResponseBadRequest
+from pootle.core.markup.filters import apply_markup_filter
 from pootle.core.views import SuperuserRequiredMixin
 from pootle_misc.util import ajax_required
 
@@ -223,3 +224,16 @@
 
     rendered_form = _get_rendered_agreement(request, form_class())
     return JsonResponse({'form': rendered_form})
+
+
+@ajax_required
+def preview_content(request):
+    """Returns content rendered based on the configured markup settings."""
+    if 'text' not in request.POST:
+        return JsonResponseBadRequest({
+            'msg': _('Text is missing'),
+        })
+
+    return JsonResponse({
+        'rendered': apply_markup_filter(request.POST['text']),
+    })

{"golden_diff": "diff --git a/pootle/apps/staticpages/urls.py b/pootle/apps/staticpages/urls.py\n--- a/pootle/apps/staticpages/urls.py\n+++ b/pootle/apps/staticpages/urls.py\n@@ -39,7 +39,16 @@\n )\n \n \n+xhr_patterns = patterns('',\n+    url(r'^preview/?$',\n+        'staticpages.views.preview_content',\n+        name='pootle-xhr-preview'),\n+)\n+\n+\n urlpatterns = patterns('',\n     url(r'^pages/',\n         include(page_patterns)),\n+    url(r'^xhr/',\n+        include(xhr_patterns)),\n )\ndiff --git a/pootle/apps/staticpages/views.py b/pootle/apps/staticpages/views.py\n--- a/pootle/apps/staticpages/views.py\n+++ b/pootle/apps/staticpages/views.py\n@@ -17,6 +17,7 @@\n                                   UpdateView)\n \n from pootle.core.http import JsonResponse, JsonResponseBadRequest\n+from pootle.core.markup.filters import apply_markup_filter\n from pootle.core.views import SuperuserRequiredMixin\n from pootle_misc.util import ajax_required\n \n@@ -223,3 +224,16 @@\n \n     rendered_form = _get_rendered_agreement(request, form_class())\n     return JsonResponse({'form': rendered_form})\n+\n+\n+@ajax_required\n+def preview_content(request):\n+    \"\"\"Returns content rendered based on the configured markup settings.\"\"\"\n+    if 'text' not in request.POST:\n+        return JsonResponseBadRequest({\n+            'msg': _('Text is missing'),\n+        })\n+\n+    return JsonResponse({\n+        'rendered': apply_markup_filter(request.POST['text']),\n+    })\n", "issue": "Add live preview when editing static documents\nWhen editing static document, let's split the screen vertically if it's width is more than 1920px, and horizontally otherwise, and add a live rendering when contents of the HTML editor area change. In the preview mode, use the same wrapper divs to make sure we pick up all styles and render the page as close to the final output as possible.\n\nQuick illustration: http://www.htmlinstant.com/ or http://htmledit.squarefree.com/\n\nMockup screenshot:\n![static_preview](https://cloud.githubusercontent.com/assets/1728158/7848828/1326968e-0484-11e5-856e-96a461976cdc.png)\n\n", "before_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n#\n# Copyright (C) Pootle contributors.\n#\n# This file is a part of the Pootle project. It is distributed under the GPL3\n# or later license. See the LICENSE file for a copy of the license and the\n# AUTHORS file for copyright and authorship information.\n\nfrom django.conf.urls import include, patterns, url\n\nfrom .views import (AdminTemplateView, PageCreateView, PageDeleteView,\n                    PageUpdateView)\n\n\npage_patterns = patterns('',\n    url(r'^legal/agreement/$',\n        'staticpages.views.legal_agreement',\n        name='pootle-staticpages-legal-agreement'),\n    url(r'^(?P<virtual_path>.+)/$',\n        'staticpages.views.display_page',\n        name='pootle-staticpages-display'),\n)\n\nadmin_patterns = patterns('',\n    url(r'^$',\n        AdminTemplateView.as_view(),\n        name='pootle-staticpages'),\n\n    url(r'^(?P<page_type>[^/]+)/add/?$',\n        PageCreateView.as_view(),\n        name='pootle-staticpages-create'),\n    url(r'^(?P<page_type>[^/]+)/(?P<pk>\\d+)/?$',\n        PageUpdateView.as_view(),\n        name='pootle-staticpages-edit'),\n    url(r'^(?P<page_type>[^/]+)/(?P<pk>\\d+)/delete/?$',\n        PageDeleteView.as_view(),\n        name='pootle-staticpages-delete'),\n)\n\n\nurlpatterns = patterns('',\n    url(r'^pages/',\n        include(page_patterns)),\n)\n", "path": "pootle/apps/staticpages/urls.py"}, {"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n#\n# Copyright (C) Pootle contributors.\n#\n# This file is a part of the Pootle project. It is distributed under the GPL3\n# or later license. See the LICENSE file for a copy of the license and the\n# AUTHORS file for copyright and authorship information.\n\nfrom django.core.exceptions import ObjectDoesNotExist\nfrom django.core.urlresolvers import reverse_lazy\nfrom django.http import Http404\nfrom django.shortcuts import redirect, render\nfrom django.template import loader, RequestContext\nfrom django.utils.translation import ugettext_lazy as _\nfrom django.views.generic import (CreateView, DeleteView, TemplateView,\n                                  UpdateView)\n\nfrom pootle.core.http import JsonResponse, JsonResponseBadRequest\nfrom pootle.core.views import SuperuserRequiredMixin\nfrom pootle_misc.util import ajax_required\n\nfrom .forms import agreement_form_factory\nfrom .models import AbstractPage, LegalPage, StaticPage\n\n\nANN_TYPE = u'announcements'\nANN_VPATH = ANN_TYPE + u'/'\n\n\nclass PageModelMixin(object):\n    \"\"\"Mixin used to set the view's page model according to the\n    `page_type` argument caught in a url pattern.\n    \"\"\"\n\n    def dispatch(self, request, *args, **kwargs):\n        self.page_type = kwargs.get('page_type', None)\n        self.model = {\n            'legal': LegalPage,\n            'static': StaticPage,\n            ANN_TYPE: StaticPage,\n        }.get(self.page_type)\n\n        if self.model is None:\n            raise Http404\n\n        return super(PageModelMixin, self).dispatch(request, *args, **kwargs)\n\n    def get_context_data(self, **kwargs):\n        ctx = super(PageModelMixin, self).get_context_data(**kwargs)\n        ctx.update({\n            'has_page_model': True,\n            'page_display_name': self.model.display_name,\n        })\n        return ctx\n\n    def get_form_kwargs(self):\n        kwargs = super(PageModelMixin, self).get_form_kwargs()\n        kwargs.update({'label_suffix': ''})\n        return kwargs\n\n    def get_form(self, form_class):\n        form = super(PageModelMixin, self).get_form(form_class)\n\n        if self.page_type == ANN_TYPE:\n            form.fields['virtual_path'].help_text = u'/pages/' + ANN_VPATH\n\n        return form\n\n    def form_valid(self, form):\n        if (self.page_type == ANN_TYPE and not\n            form.cleaned_data['virtual_path'].startswith(ANN_VPATH)):\n            orig_vpath = form.cleaned_data['virtual_path']\n            form.instance.virtual_path = ANN_VPATH + orig_vpath\n\n        return super(PageModelMixin, self).form_valid(form)\n\n\nclass AdminCtxMixin(object):\n\n    def get_context_data(self, **kwargs):\n        ctx = super(AdminCtxMixin, self).get_context_data(**kwargs)\n        ctx.update({\n            'page': 'admin-pages',\n        })\n        return ctx\n\n\nclass AdminTemplateView(SuperuserRequiredMixin, AdminCtxMixin, TemplateView):\n\n    template_name = 'admin/staticpages/page_list.html'\n\n    def get_context_data(self, **kwargs):\n        legal_pages = LegalPage.objects.all()\n        static_pages = StaticPage.objects.exclude(\n            virtual_path__startswith=ANN_VPATH,\n        )\n        announcements = StaticPage.objects.filter(\n            virtual_path__startswith=ANN_VPATH,\n        )\n\n        ctx = super(AdminTemplateView, self).get_context_data(**kwargs)\n        ctx.update({\n            'legalpages': legal_pages,\n            'staticpages': static_pages,\n            ANN_TYPE: announcements,\n        })\n        return ctx\n\n\nclass PageCreateView(SuperuserRequiredMixin, AdminCtxMixin, PageModelMixin, CreateView):\n    fields = ('title', 'virtual_path', 'active', 'url', 'body')\n\n    success_url = reverse_lazy('pootle-staticpages')\n    template_name = 'admin/staticpages/page_create.html'\n\n    def get_initial(self):\n        initial = super(PageModelMixin, self).get_initial()\n\n        initial_args = {\n            'title': _('Page Title'),\n        }\n\n        if self.page_type != ANN_TYPE:\n            next_page_number = AbstractPage.max_pk() + 1\n            initial_args['virtual_path'] = 'page-%d' % next_page_number\n\n        initial.update(initial_args)\n\n        return initial\n\n    def get_form(self, form_class):\n        form = super(PageCreateView, self).get_form(form_class)\n\n        if self.page_type == ANN_TYPE:\n            del form.fields['url']\n            # Translators: 'projects' must not be translated.\n            msg = _(u'projects/<project_code> or <language_code> or '\n                    u'<language_code>/<project_code>')\n            form.fields['virtual_path'].widget.attrs['placeholder'] = msg\n            form.fields['virtual_path'].widget.attrs['size'] = 60\n\n        return form\n\n\nclass PageUpdateView(SuperuserRequiredMixin, AdminCtxMixin, PageModelMixin, UpdateView):\n    fields = ('title', 'virtual_path', 'active', 'url', 'body')\n\n    success_url = reverse_lazy('pootle-staticpages')\n    template_name = 'admin/staticpages/page_update.html'\n\n    def get_context_data(self, **kwargs):\n        ctx = super(PageUpdateView, self).get_context_data(**kwargs)\n        ctx.update({\n            'show_delete': True,\n            'page_type': self.page_type,\n        })\n        return ctx\n\n    def get_form_kwargs(self):\n        kwargs = super(PageUpdateView, self).get_form_kwargs()\n\n        if self.page_type == ANN_TYPE:\n            orig_vpath = self.object.virtual_path\n            self.object.virtual_path = orig_vpath.replace(ANN_VPATH, '')\n            kwargs.update({'instance': self.object})\n\n        return kwargs\n\n\nclass PageDeleteView(SuperuserRequiredMixin, PageModelMixin, DeleteView):\n\n    success_url = reverse_lazy('pootle-staticpages')\n\n\ndef display_page(request, virtual_path):\n    \"\"\"Displays an active page defined in `virtual_path`.\"\"\"\n    page = None\n    for page_model in AbstractPage.__subclasses__():\n        try:\n            page = page_model.objects.live(request.user).get(\n                    virtual_path=virtual_path,\n                )\n        except ObjectDoesNotExist:\n            pass\n\n    if page is None:\n        raise Http404\n\n    if page.url:\n        return redirect(page.url)\n\n    template_name = 'staticpages/page_display.html'\n    if request.is_ajax():\n        template_name = 'staticpages/_body.html'\n\n    ctx = {\n        'page': page,\n    }\n    return render(request, template_name, ctx)\n\n\ndef _get_rendered_agreement(request, form):\n    template = loader.get_template('staticpages/agreement.html')\n    return template.render(RequestContext(request, {'form': form}))\n\n\n@ajax_required\ndef legal_agreement(request):\n    \"\"\"Displays the pending documents to be agreed by the current user.\"\"\"\n    pending_pages = LegalPage.objects.pending_user_agreement(request.user)\n    form_class = agreement_form_factory(pending_pages, request.user)\n\n    if request.method == 'POST':\n        form = form_class(request.POST)\n\n        if form.is_valid():\n            form.save()\n            return JsonResponse({})\n\n        rendered_form = _get_rendered_agreement(request, form)\n        return JsonResponseBadRequest({'form': rendered_form})\n\n    rendered_form = _get_rendered_agreement(request, form_class())\n    return JsonResponse({'form': rendered_form})\n", "path": "pootle/apps/staticpages/views.py"}], "after_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n#\n# Copyright (C) Pootle contributors.\n#\n# This file is a part of the Pootle project. It is distributed under the GPL3\n# or later license. See the LICENSE file for a copy of the license and the\n# AUTHORS file for copyright and authorship information.\n\nfrom django.conf.urls import include, patterns, url\n\nfrom .views import (AdminTemplateView, PageCreateView, PageDeleteView,\n                    PageUpdateView)\n\n\npage_patterns = patterns('',\n    url(r'^legal/agreement/$',\n        'staticpages.views.legal_agreement',\n        name='pootle-staticpages-legal-agreement'),\n    url(r'^(?P<virtual_path>.+)/$',\n        'staticpages.views.display_page',\n        name='pootle-staticpages-display'),\n)\n\nadmin_patterns = patterns('',\n    url(r'^$',\n        AdminTemplateView.as_view(),\n        name='pootle-staticpages'),\n\n    url(r'^(?P<page_type>[^/]+)/add/?$',\n        PageCreateView.as_view(),\n        name='pootle-staticpages-create'),\n    url(r'^(?P<page_type>[^/]+)/(?P<pk>\\d+)/?$',\n        PageUpdateView.as_view(),\n        name='pootle-staticpages-edit'),\n    url(r'^(?P<page_type>[^/]+)/(?P<pk>\\d+)/delete/?$',\n        PageDeleteView.as_view(),\n        name='pootle-staticpages-delete'),\n)\n\n\nxhr_patterns = patterns('',\n    url(r'^preview/?$',\n        'staticpages.views.preview_content',\n        name='pootle-xhr-preview'),\n)\n\n\nurlpatterns = patterns('',\n    url(r'^pages/',\n        include(page_patterns)),\n    url(r'^xhr/',\n        include(xhr_patterns)),\n)\n", "path": "pootle/apps/staticpages/urls.py"}, {"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n#\n# Copyright (C) Pootle contributors.\n#\n# This file is a part of the Pootle project. It is distributed under the GPL3\n# or later license. See the LICENSE file for a copy of the license and the\n# AUTHORS file for copyright and authorship information.\n\nfrom django.core.exceptions import ObjectDoesNotExist\nfrom django.core.urlresolvers import reverse_lazy\nfrom django.http import Http404\nfrom django.shortcuts import redirect, render\nfrom django.template import loader, RequestContext\nfrom django.utils.translation import ugettext_lazy as _\nfrom django.views.generic import (CreateView, DeleteView, TemplateView,\n                                  UpdateView)\n\nfrom pootle.core.http import JsonResponse, JsonResponseBadRequest\nfrom pootle.core.markup.filters import apply_markup_filter\nfrom pootle.core.views import SuperuserRequiredMixin\nfrom pootle_misc.util import ajax_required\n\nfrom .forms import agreement_form_factory\nfrom .models import AbstractPage, LegalPage, StaticPage\n\n\nANN_TYPE = u'announcements'\nANN_VPATH = ANN_TYPE + u'/'\n\n\nclass PageModelMixin(object):\n    \"\"\"Mixin used to set the view's page model according to the\n    `page_type` argument caught in a url pattern.\n    \"\"\"\n\n    def dispatch(self, request, *args, **kwargs):\n        self.page_type = kwargs.get('page_type', None)\n        self.model = {\n            'legal': LegalPage,\n            'static': StaticPage,\n            ANN_TYPE: StaticPage,\n        }.get(self.page_type)\n\n        if self.model is None:\n            raise Http404\n\n        return super(PageModelMixin, self).dispatch(request, *args, **kwargs)\n\n    def get_context_data(self, **kwargs):\n        ctx = super(PageModelMixin, self).get_context_data(**kwargs)\n        ctx.update({\n            'has_page_model': True,\n            'page_display_name': self.model.display_name,\n        })\n        return ctx\n\n    def get_form_kwargs(self):\n        kwargs = super(PageModelMixin, self).get_form_kwargs()\n        kwargs.update({'label_suffix': ''})\n        return kwargs\n\n    def get_form(self, form_class):\n        form = super(PageModelMixin, self).get_form(form_class)\n\n        if self.page_type == ANN_TYPE:\n            form.fields['virtual_path'].help_text = u'/pages/' + ANN_VPATH\n\n        return form\n\n    def form_valid(self, form):\n        if (self.page_type == ANN_TYPE and not\n            form.cleaned_data['virtual_path'].startswith(ANN_VPATH)):\n            orig_vpath = form.cleaned_data['virtual_path']\n            form.instance.virtual_path = ANN_VPATH + orig_vpath\n\n        return super(PageModelMixin, self).form_valid(form)\n\n\nclass AdminCtxMixin(object):\n\n    def get_context_data(self, **kwargs):\n        ctx = super(AdminCtxMixin, self).get_context_data(**kwargs)\n        ctx.update({\n            'page': 'admin-pages',\n        })\n        return ctx\n\n\nclass AdminTemplateView(SuperuserRequiredMixin, AdminCtxMixin, TemplateView):\n\n    template_name = 'admin/staticpages/page_list.html'\n\n    def get_context_data(self, **kwargs):\n        legal_pages = LegalPage.objects.all()\n        static_pages = StaticPage.objects.exclude(\n            virtual_path__startswith=ANN_VPATH,\n        )\n        announcements = StaticPage.objects.filter(\n            virtual_path__startswith=ANN_VPATH,\n        )\n\n        ctx = super(AdminTemplateView, self).get_context_data(**kwargs)\n        ctx.update({\n            'legalpages': legal_pages,\n            'staticpages': static_pages,\n            ANN_TYPE: announcements,\n        })\n        return ctx\n\n\nclass PageCreateView(SuperuserRequiredMixin, AdminCtxMixin, PageModelMixin, CreateView):\n    fields = ('title', 'virtual_path', 'active', 'url', 'body')\n\n    success_url = reverse_lazy('pootle-staticpages')\n    template_name = 'admin/staticpages/page_create.html'\n\n    def get_initial(self):\n        initial = super(PageModelMixin, self).get_initial()\n\n        initial_args = {\n            'title': _('Page Title'),\n        }\n\n        if self.page_type != ANN_TYPE:\n            next_page_number = AbstractPage.max_pk() + 1\n            initial_args['virtual_path'] = 'page-%d' % next_page_number\n\n        initial.update(initial_args)\n\n        return initial\n\n    def get_form(self, form_class):\n        form = super(PageCreateView, self).get_form(form_class)\n\n        if self.page_type == ANN_TYPE:\n            del form.fields['url']\n            # Translators: 'projects' must not be translated.\n            msg = _(u'projects/<project_code> or <language_code> or '\n                    u'<language_code>/<project_code>')\n            form.fields['virtual_path'].widget.attrs['placeholder'] = msg\n            form.fields['virtual_path'].widget.attrs['size'] = 60\n\n        return form\n\n\nclass PageUpdateView(SuperuserRequiredMixin, AdminCtxMixin, PageModelMixin, UpdateView):\n    fields = ('title', 'virtual_path', 'active', 'url', 'body')\n\n    success_url = reverse_lazy('pootle-staticpages')\n    template_name = 'admin/staticpages/page_update.html'\n\n    def get_context_data(self, **kwargs):\n        ctx = super(PageUpdateView, self).get_context_data(**kwargs)\n        ctx.update({\n            'show_delete': True,\n            'page_type': self.page_type,\n        })\n        return ctx\n\n    def get_form_kwargs(self):\n        kwargs = super(PageUpdateView, self).get_form_kwargs()\n\n        if self.page_type == ANN_TYPE:\n            orig_vpath = self.object.virtual_path\n            self.object.virtual_path = orig_vpath.replace(ANN_VPATH, '')\n            kwargs.update({'instance': self.object})\n\n        return kwargs\n\n\nclass PageDeleteView(SuperuserRequiredMixin, PageModelMixin, DeleteView):\n\n    success_url = reverse_lazy('pootle-staticpages')\n\n\ndef display_page(request, virtual_path):\n    \"\"\"Displays an active page defined in `virtual_path`.\"\"\"\n    page = None\n    for page_model in AbstractPage.__subclasses__():\n        try:\n            page = page_model.objects.live(request.user).get(\n                    virtual_path=virtual_path,\n                )\n        except ObjectDoesNotExist:\n            pass\n\n    if page is None:\n        raise Http404\n\n    if page.url:\n        return redirect(page.url)\n\n    template_name = 'staticpages/page_display.html'\n    if request.is_ajax():\n        template_name = 'staticpages/_body.html'\n\n    ctx = {\n        'page': page,\n    }\n    return render(request, template_name, ctx)\n\n\ndef _get_rendered_agreement(request, form):\n    template = loader.get_template('staticpages/agreement.html')\n    return template.render(RequestContext(request, {'form': form}))\n\n\n@ajax_required\ndef legal_agreement(request):\n    \"\"\"Displays the pending documents to be agreed by the current user.\"\"\"\n    pending_pages = LegalPage.objects.pending_user_agreement(request.user)\n    form_class = agreement_form_factory(pending_pages, request.user)\n\n    if request.method == 'POST':\n        form = form_class(request.POST)\n\n        if form.is_valid():\n            form.save()\n            return JsonResponse({})\n\n        rendered_form = _get_rendered_agreement(request, form)\n        return JsonResponseBadRequest({'form': rendered_form})\n\n    rendered_form = _get_rendered_agreement(request, form_class())\n    return JsonResponse({'form': rendered_form})\n\n\n@ajax_required\ndef preview_content(request):\n    \"\"\"Returns content rendered based on the configured markup settings.\"\"\"\n    if 'text' not in request.POST:\n        return JsonResponseBadRequest({\n            'msg': _('Text is missing'),\n        })\n\n    return JsonResponse({\n        'rendered': apply_markup_filter(request.POST['text']),\n    })\n", "path": "pootle/apps/staticpages/views.py"}]}