Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'release/2.3rc2'

  • Loading branch information...
commit b9bbddb9c56162bccd0254b145710a106767ad18 2 parents 686ed2f + 56e5867
@piquadrat piquadrat authored
Showing with 5,008 additions and 2,593 deletions.
  1. +5 −2 .gitignore
  2. +16 −0 .travis.yml
  3. +18 −0 AUTHORS
  4. +19 −1 CHANGELOG.txt
  5. +1 −1  cms/__init__.py
  6. +9 −4 cms/admin/change_list.py
  7. +1 −1  cms/admin/forms.py
  8. +91 −41 cms/admin/pageadmin.py
  9. +30 −8 cms/admin/permissionadmin.py
  10. +2 −1  cms/admin/placeholderadmin.py
  11. +5 −26 cms/appresolver.py
  12. +5 −1 cms/conf/__init__.py
  13. +3 −2 cms/conf/patch.py
  14. +7 −4 cms/forms/utils.py
  15. +2 −1  cms/forms/widgets.py
  16. BIN  cms/locale/it/LC_MESSAGES/django.mo
  17. +2 −2 cms/locale/it/LC_MESSAGES/django.po
  18. +167 −47 cms/menu.py
  19. +8 −5 cms/middleware/multilingual.py
  20. +15 −5 cms/models/managers.py
  21. +23 −13 cms/models/pagemodel.py
  22. +7 −4 cms/models/placeholdermodel.py
  23. +6 −2 cms/models/pluginmodel.py
  24. +6 −8 cms/plugin_rendering.py
  25. +5 −0 cms/plugins/file/migrations/0005_publisher2.py
  26. +2 −2 cms/plugins/file/templates/cms/plugins/file.html
  27. +5 −0 cms/plugins/flash/migrations/0005_publisher2.py
  28. +5 −0 cms/plugins/googlemap/migrations/0006_publisher2.py
  29. +1 −1  cms/plugins/inherit/models.py
  30. +5 −0 cms/plugins/link/migrations/0007_publisher2.py
  31. +5 −0 cms/plugins/picture/migrations/0007_publisher2.py
  32. +5 −0 cms/plugins/snippet/migrations/0004_publisher2.py
  33. +5 −0 cms/plugins/teaser/migrations/0002_publisher2.py
  34. +5 −0 cms/plugins/text/migrations/0005_publisher2.py
  35. +1 −0  cms/plugins/text/templates/cms/plugins/text_plugin_change_form.html
  36. +7 −7 cms/plugins/text/templates/cms/plugins/widgets/tinymce.html
  37. +2 −0  cms/plugins/text/templates/cms/plugins/widgets/wymeditor.html
  38. +1 −0  cms/plugins/twitter/templates/cms/plugins/twitter_recent_entries.html
  39. +1 −1  cms/plugins/video/templates/cms/plugins/video.html
  40. +9 −6 cms/signals.py
  41. +15 −0 cms/static/cms/css/pages.css
  42. +5 −1 cms/static/cms/css/plugins/cms.placeholders.css
  43. +2 −2 cms/static/cms/css/plugins/cms.toolbar.css
  44. +0 −851 cms/static/cms/css/toolbar.css
  45. +125 −126 cms/static/cms/js/change_form.js
  46. +138 −121 cms/static/cms/js/change_list.js
  47. +59 −1 cms/static/cms/js/csrf.js
  48. +9 −10 cms/static/cms/js/placeholder_editor_registry.js
  49. +186 −181 cms/static/cms/js/plugin_editor.js
  50. +15 −22 cms/static/cms/js/plugins/cms.base.js
  51. +10 −18 cms/static/cms/js/plugins/cms.placeholders.js
  52. +15 −0 cms/static/cms/js/plugins/cms.setup.js
  53. +14 −13 cms/static/cms/js/plugins/cms.toolbar.js
  54. +5 −7 cms/static/cms/js/tinymce.placeholdereditor.js
  55. +21 −22 cms/static/cms/js/wymeditor.placeholdereditor.js
  56. +5 −5 cms/templates/admin/cms/page/change_form.html
  57. +5 −4 cms/templates/admin/cms/page/change_list.html
  58. +11 −0 cms/templates/admin/cms/page/lazy_child_menu.html
  59. +8 −0 cms/templates/admin/cms/page/lazy_menu.html
  60. +9 −3 cms/templates/admin/cms/page/menu.html
  61. +26 −30 cms/templates/admin/cms/page/menu_item.html
  62. +7 −6 cms/templates/admin/cms/page/plugin_change_form.html
  63. +2 −2 cms/templates/admin/cms/page/plugin_forms_history.html
  64. +12 −5 cms/templates/admin/cms/page/plugin_forms_ok.html
  65. +2 −2 cms/templates/admin/cms/page/widgets/plugin_editor.html
  66. +1 −1  cms/templates/cms/new.html
  67. +2 −4 cms/templates/cms/toolbar/placeholder.html
  68. +5 −7 cms/templates/cms/toolbar/placeholder_wrapper.html
  69. +22 −13 cms/templates/cms/toolbar/toolbar.html
  70. +60 −3 cms/templatetags/cms_admin.py
  71. +34 −0 cms/templatetags/cms_js_tags.py
  72. +24 −20 cms/templatetags/cms_tags.py
  73. +0 −15 cms/templatetags/js.py
  74. +190 −0 cms/test_utils/cli.py
  75. +22 −0 cms/test_utils/compat.py
  76. +1 −1  cms/test_utils/fixtures/fakemlng.py
  77. 0  {tests/project/sampleapp → cms/test_utils/project}/__init__.py
  78. 0  {tests → cms/test_utils}/project/cms_urls_for_apphook_tests.py
  79. 0  {tests/project/pluginapp/plugins/manytomany_rel → cms/test_utils/project/fakemlng}/__init__.py
  80. 0  {tests → cms/test_utils}/project/fakemlng/fixtures/fakemlng.json
  81. 0  {tests → cms/test_utils}/project/fakemlng/models.py
  82. 0  {tests/project/pluginapp/plugins → cms/test_utils/project/fileapp}/__init__.py
  83. 0  {tests → cms/test_utils}/project/fileapp/models.py
  84. 0  {tests → cms/test_utils}/project/models.py
  85. 0  {tests → cms/test_utils}/project/noadmin_urls.py
  86. 0  {tests → cms/test_utils}/project/nonroot_urls.py
  87. 0  {tests/project/pluginapp → cms/test_utils/project/placeholderapp}/__init__.py
  88. +3 −2 {tests → cms/test_utils}/project/placeholderapp/admin.py
  89. 0  {tests → cms/test_utils}/project/placeholderapp/models.py
  90. +1 −1  {tests → cms/test_utils}/project/placeholderapp/views.py
  91. 0  {tests/project/placeholderapp → cms/test_utils/project/pluginapp}/__init__.py
  92. 0  {tests → cms/test_utils}/project/pluginapp/models.py
  93. 0  {tests/project/fileapp → cms/test_utils/project/pluginapp/plugins}/__init__.py
  94. 0  {tests/project/fakemlng → cms/test_utils/project/pluginapp/plugins/manytomany_rel}/__init__.py
  95. +2 −2 {tests → cms/test_utils}/project/pluginapp/plugins/manytomany_rel/cms_plugins.py
  96. +1 −1  {tests → cms/test_utils}/project/pluginapp/plugins/manytomany_rel/models.py
  97. 0  {tests/project → cms/test_utils/project/sampleapp}/__init__.py
  98. +1 −1  {tests → cms/test_utils}/project/sampleapp/admin.py
  99. +2 −2 {tests → cms/test_utils}/project/sampleapp/cms_app.py
  100. 0  {tests → cms/test_utils}/project/sampleapp/media/sampleapp/img/gift.jpg
  101. +1 −2  {tests → cms/test_utils}/project/sampleapp/menu.py
  102. 0  {tests → cms/test_utils}/project/sampleapp/models.py
  103. 0  {tests → cms/test_utils}/project/sampleapp/templates/sampleapp/category_view.html
  104. 0  {tests → cms/test_utils}/project/sampleapp/templates/sampleapp/home.html
  105. +1 −1  {tests → cms/test_utils}/project/sampleapp/urls.py
  106. +1 −1  {tests → cms/test_utils}/project/sampleapp/views.py
  107. 0  {tests → cms/test_utils}/project/second_cms_urls_for_apphook_tests.py
  108. +1 −1  {tests → cms/test_utils}/project/second_urls_for_apphook_tests.py
  109. 0  {tests → cms/test_utils}/project/templates/404.html
  110. 0  {tests → cms/test_utils}/project/templates/add_placeholder.html
  111. 0  {tests → cms/test_utils}/project/templates/base.html
  112. 0  {tests → cms/test_utils}/project/templates/col_three.html
  113. 0  {tests → cms/test_utils}/project/templates/col_two.html
  114. 0  {tests → cms/test_utils}/project/templates/extra_context.html
  115. 0  {tests → cms/test_utils}/project/templates/fail.html
  116. 0  {tests → cms/test_utils}/project/templates/menu/breadcrumb.html
  117. 0  {tests → cms/test_utils}/project/templates/menu/language_chooser.html
  118. 0  {tests → cms/test_utils}/project/templates/menu/menu.html
  119. 0  {tests → cms/test_utils}/project/templates/menu/sub_menu.html
  120. 0  {tests → cms/test_utils}/project/templates/menu/test_language_chooser.html
  121. 0  {tests → cms/test_utils}/project/templates/nav_playground.html
  122. 0  {tests → cms/test_utils}/project/templates/placeholder_tests/base.html
  123. 0  {tests → cms/test_utils}/project/templates/placeholder_tests/child.html
  124. 0  {tests → cms/test_utils}/project/templates/placeholder_tests/nested_super_level1.html
  125. 0  {tests → cms/test_utils}/project/templates/placeholder_tests/nested_super_level2.html
  126. 0  {tests → cms/test_utils}/project/templates/placeholder_tests/nested_super_level3.html
  127. 0  {tests → cms/test_utils}/project/templates/placeholder_tests/nested_super_level4.html
  128. 0  {tests → cms/test_utils}/project/templates/placeholder_tests/outside.html
  129. 0  {tests → cms/test_utils}/project/templates/placeholder_tests/outside_base.html
  130. +1 −0  cms/test_utils/project/templates/placeholder_tests/outside_nested.html
  131. 0  {tests → cms/test_utils}/project/templates/placeholder_tests/test_eleven.html
  132. 0  {tests → cms/test_utils}/project/templates/placeholder_tests/test_five.html
  133. 0  {tests → cms/test_utils}/project/templates/placeholder_tests/test_four.html
  134. 0  {tests → cms/test_utils}/project/templates/placeholder_tests/test_one.html
  135. 0  {tests → cms/test_utils}/project/templates/placeholder_tests/test_seven.html
  136. 0  {tests → cms/test_utils}/project/templates/placeholder_tests/test_six.html
  137. 0  {tests → cms/test_utils}/project/templates/placeholder_tests/test_three.html
  138. 0  {tests → cms/test_utils}/project/templates/placeholder_tests/test_two.html
  139. 0  {tests → cms/test_utils}/project/templates/placeholderapp.html
  140. 0  {tests → cms/test_utils}/project/templates/sidebar_submenu.html
  141. 0  {tests → cms/test_utils}/project/templates/sidebar_submenu_root.html
  142. +1 −0  cms/test_utils/project/templates/subdir/template.html
  143. 0  {tests → cms/test_utils}/project/templates/unicode_placeholder.html
  144. +2 −2 {tests → cms/test_utils}/project/urls.py
  145. +1 −1  {tests → cms/test_utils}/project/urls_for_apphook_tests.py
  146. +51 −0 cms/test_utils/runners.py
  147. +9 −8 cms/test_utils/testcases.py
  148. +26 −0 cms/test_utils/tmpdir.py
  149. +7 −0 cms/test_utils/util/urls.py
  150. +4 −1 cms/tests/__init__.py
  151. +108 −7 cms/tests/admin.py
  152. +19 −6 cms/tests/apphooks.py
  153. +13 −1 cms/tests/docs.py
  154. +3 −0  cms/tests/forms.py
  155. +4 −5 cms/tests/management.py
  156. +318 −110 cms/tests/menu.py
  157. +596 −0 cms/tests/menu_page_viewperm.py
  158. +524 −0 cms/tests/menu_page_viewperm_staff.py
  159. +3 −2 cms/tests/middleware.py
  160. +505 −0 cms/tests/nested_plugins.py
  161. +1 −1  cms/tests/nonroot.py
  162. +98 −5 cms/tests/page.py
  163. +65 −12 cms/tests/permmod.py
  164. +11 −6 cms/tests/placeholder.py
  165. +108 −3 cms/tests/plugins.py
  166. +26 −0 cms/tests/rendering.py
  167. +12 −10 cms/tests/reversion_tests.py
  168. +10 −3 cms/tests/settings.py
  169. +45 −17 cms/tests/templatetags.py
  170. +19 −3 cms/tests/views.py
  171. +1 −1  cms/utils/__init__.py
  172. +5 −2 cms/utils/admin.py
  173. +14 −5 cms/utils/helpers.py
  174. +2 −3 cms/utils/mail.py
  175. +2 −3 cms/utils/moderator.py
  176. +10 −6 cms/utils/page.py
  177. +5 −2 cms/utils/page_resolver.py
  178. +5 −5 cms/utils/permissions.py
  179. +20 −12 cms/utils/plugins.py
  180. +6 −3 cms/utils/reversion_hacks.py
  181. +9 −2 cms/views.py
  182. +13 −1 docs/advanced/i18n.rst
  183. +6 −3 docs/advanced/templatetags.rst
  184. +5 −0 docs/concepts/introduction.rst
  185. +121 −0 docs/concepts/menu_system.rst
  186. +104 −0 docs/concepts/multiple_languages.rst
  187. +1 −4 docs/contribution.rst
  188. +1 −1  docs/extending_cms/extending_examples.rst
  189. +1 −1  docs/extending_cms/placeholders.rst
  190. +20 −0 docs/faq/common_issues.rst
  191. +16 −6 docs/getting_started/configuration.rst
  192. +4 −4 docs/getting_started/installation.rst
  193. +20 −10 docs/getting_started/plugin_reference.rst
  194. +8 −1 docs/getting_started/tutorial.rst
  195. +14 −0 docs/index.rst
  196. +130 −0 docs/upgrade/2.1.rst
  197. +15 −5 docs/upgrade/2.2.rst
  198. +87 −0 docs/upgrade/2.3.rst
  199. +20 −1 docs/upgrade/index.rst
  200. +2 −2 menus/menu_pool.py
  201. +14 −3 menus/models.py
  202. +24 −0 runshell.py
  203. +49 −0 runtests.py
  204. +0 −121 runtests.sh
  205. +57 −0 runtestserver.py
  206. +14 −5 setup.py
  207. +0 −10 tests/.coveragerc
  208. +0 −121 tests/bootstrap.py
  209. +0 −41 tests/buildout.cfg
  210. +0 −9 tests/django-12.cfg
  211. +0 −9 tests/django-124.cfg
  212. +0 −8 tests/django-13.cfg
  213. +0 −16 tests/django-trunk.cfg
  214. +0 −16 tests/project/manage.py
  215. +0 −224 tests/project/settings.py
  216. +0 −18 tests/project/testrunner.py
View
7 .gitignore
@@ -1,4 +1,5 @@
*.pyc
+!.travis.yml
*.swp
*.lock
*.pid
@@ -7,7 +8,8 @@ cms/django
*.svn
.*
*.xml
-cms.sqlite
+/*env*/
+*.sqlite
cms/media/cms_page_media/
cms/docs/build
example/run
@@ -20,7 +22,8 @@ dist
.project
.pydevproject
.settings
-*.egg-info
+/*.egg-info/
+/*.egg/
develop-eggs
downloads
eggs
View
16 .travis.yml
@@ -0,0 +1,16 @@
+language: python
+python:
+ - "2.6"
+ - "2.7"
+env:
+ - DJANGO="django>=1.3,<1.4"
+ - DJANGO="django>=1.4,<1.5"
+install:
+ - pip install -q $DJANGO django-mptt==0.5.1 django-reversion==1.6 django-classy-tags==0.3.4.1 django-sekizai==0.6.1 html5lib==0.95 jinja2==2.6 PIL==1.1.7 pygments==1.5 south==0.7.5 sphinx==1.1.3 argparse
+script:
+ python runtests.py
+notifications:
+ email: false
+ irc:
+ - "irc.freenode.org#django-cms"
+ - "irc.freenode.org#django-cms-sprint"
View
18 AUTHORS
@@ -1,7 +1,9 @@
Current or previous core committers:
* Angelo Dini
+* Beni Wohlwend
* Chris Glass
+* Daniele Procida
* Eric Robitaille
* Jonas Obrist
* Patrick Lauber
@@ -9,6 +11,10 @@ Current or previous core committers:
* Stefan Foulis
* Øyvind Saltvik
+Current and previous core designers:
+
+* Christian Bertschy
+
Contributors (in alphabetical order):
* A. Bram Neijt
@@ -19,6 +25,10 @@ Contributors (in alphabetical order):
* Adrián Ribao
* Alberto Paro
* Alessandro Ronchi
+* Aleš Kocjančič
+* Alvin Mites
+* Andrew Cassidy
+* Andrew Schoen
* angular_circle
* Antoni Aloy López
* Arne Gellhaus
@@ -31,6 +41,7 @@ Contributors (in alphabetical order):
* Bernd Zeimetz
* beshrkayali
* Bob Karreman
+* Bouke Haarsma
* brightwhitefox
* Chanita Siridechkun
* Charpentier Johan
@@ -39,6 +50,7 @@ Contributors (in alphabetical order):
* Chris Hughes
* Chris Wesseling
* Christof Hagedorn
+* Conrado Bührer
* Daniele Procida
* DaNmarner
* Darryl Woods
@@ -56,6 +68,7 @@ Contributors (in alphabetical order):
* fcurella
* Filip Kazimierczak
* Frank Bieniek
+* Gabriel Hurley
* GaretJax
* George Marshall
* Gerard Świderski
@@ -80,10 +93,12 @@ Contributors (in alphabetical order):
* Jonathan Stoppani
* jordanjambazov
* Jorge Vargas (elpargo)
+* Joseph Bergantine
* kar1m
* Keryn Knight
* Kim Blomqvist
* kochin
+* Kristian Øllegaard
* Krzysztof Bandurski
* kunitoki
* Lars Smit
@@ -105,6 +120,7 @@ Contributors (in alphabetical order):
* Martin Kosír
* martinkosir
* mathijs
+* Matt Chisholm
* Maxim Bodyansky
* Maxime Haineault
* mbouchar
@@ -119,6 +135,7 @@ Contributors (in alphabetical order):
* neoprolog
* Orne Brocaar
* padelt
+* Paolo
* Patrick Toal
* Paul van der Linden
* pbgc
@@ -133,6 +150,7 @@ Contributors (in alphabetical order):
* pigletto
* Piotr Kilczuk
* poweredbypenguins
+* Rebecca Breu
* Remco Wendt
* Restless Being
* Robert Pogorzelski
View
20 CHANGELOG.txt
@@ -56,10 +56,28 @@
- Fixed a XSS issue in Text Plugins
-==== 2.2.0 (In Development) ====
+==== 2.2.0 (2011-09-10) ====
- Replaced the old plugin media framework with django-sekizai. (This changed some plugin templates which might cause problems with your CSS styling).
- Made django-mptt a proper dependency
- Removed support for django-dbgettext
- Google Maps Plugin now defaults to use HTTPS.
- Google Maps Plugin now uses the version 3 of their API, no longer requiring an API Key.
+
+
+==== 2.3.0 (in development) ====
+
+- Compatibility with Django 1.3.1 and 1.4 (1.2 support dropped)
+- Lazy admin page tree loading
+- Toolbar JS isolation
+- Destructive plugin actions fixed (cancel button, moving plugins)
+- Refactored tests
+- Fixed or clause of placeholder tag
+- Fixed double escaping of icon sources for inline plugins
+- Fixed order of PageSelectWidget
+- Fixed invalid HTML generated by file plugin
+- Fixed migration order of plugins
+- Fixed internationalized strings in JS not being escaped
+- django-reversion dependency upgraded to 1.6
+- django-sekizai dependency upgraded to 0.6.1 or higher
+- django-mptt dependency upgraded to 0.5.1 or higher
View
2  cms/__init__.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-__version__ = '2.2'
+__version__ = '2.3rc2'
# patch settings
try:
View
13 cms/admin/change_list.py
@@ -8,7 +8,7 @@
from django.contrib.admin.views.main import ChangeList, ALL_VAR, IS_POPUP_VAR, \
ORDER_TYPE_VAR, ORDER_VAR, SEARCH_VAR
from django.contrib.sites.models import Site
-
+import django
COPY_VAR = "copy"
@@ -54,9 +54,9 @@ class CMSChangeList(ChangeList):
real_queryset = False
def __init__(self, request, *args, **kwargs):
- super(CMSChangeList, self).__init__(request, *args, **kwargs)
from cms.utils.plugins import current_site
self._current_site = current_site(request)
+ super(CMSChangeList, self).__init__(request, *args, **kwargs)
try:
self.query_set = self.get_query_set(request)
except:
@@ -70,7 +70,10 @@ def __init__(self, request, *args, **kwargs):
def get_query_set(self, request=None):
if COPY_VAR in self.params:
del self.params[COPY_VAR]
- qs = super(CMSChangeList, self).get_query_set().drafts()
+ if django.VERSION[1] > 3:
+ qs = super(CMSChangeList, self).get_query_set(request).drafts()
+ else:
+ qs = super(CMSChangeList, self).get_query_set().drafts()
if request:
site = self._current_site
permissions = Page.permissions.get_change_id_list(request.user, site)
@@ -155,7 +158,7 @@ def set_items(self, request):
for page in pages:
- children = page.get_children()
+ children = list(page.get_children())
# note: We are using change_list permission here, because we must
# display also pages which user must not edit, but he haves a
@@ -195,6 +198,8 @@ def set_items(self, request):
if len(children):
# TODO: WTF!?!
# The last one is not the last... wait, what?
+ # children should NOT be a queryset. If it is, check that
+ # your django-mptt version is 0.5.1
children[-1].last = False
page.menu_level = 0
root_pages.append(page)
View
2  cms/admin/forms.py
@@ -167,7 +167,7 @@ def clean(self):
site_id = cleaned_data['site']
if id:
if Page.objects.filter(reverse_id=id, site=site_id, publisher_is_draft=True).exclude(pk=self.instance.pk).count():
- raise forms.ValidationError(_('A page with this reverse URL id exists already.'))
+ self._errors['reverse_id'] = self.error_class([_('A page with this reverse URL id exists already.')])
return cleaned_data
def clean_overwrite_url(self):
View
132 cms/admin/pageadmin.py
@@ -13,20 +13,23 @@
from cms.models.managers import PagePermissionsPermissionManager
from cms.models.placeholdermodel import Placeholder
from cms.plugin_pool import plugin_pool
+from cms.templatetags.cms_admin import admin_static_url
from cms.utils import (copy_plugins, helpers, moderator, permissions, plugins,
get_template_from_request, get_language_from_request,
placeholder as placeholder_utils, admin as admin_utils, cms_static_url)
from cms.utils.permissions import has_plugin_permission
from copy import deepcopy
+from distutils.version import LooseVersion
from django import template
from django.conf import settings
from django.contrib import admin
from django.contrib.admin.options import IncorrectLookupParameters
-from django.contrib.admin.util import unquote, get_deleted_objects
+from django.contrib.admin.util import get_deleted_objects
+from urllib2 import unquote
from django.contrib.sites.models import Site
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
from django.core.urlresolvers import reverse
-from django.db import transaction, models
+from django.db import router, transaction, models
from django.forms import CharField
from django.http import (HttpResponseRedirect, HttpResponse, Http404,
HttpResponseBadRequest, HttpResponseForbidden, HttpResponseNotAllowed)
@@ -38,15 +41,9 @@
from django.utils.translation import ugettext, ugettext_lazy as _
from menus.menu_pool import menu_pool
import django
-import inspect
-
-# silly hack to test features/ fixme
-if inspect.getargspec(get_deleted_objects)[0][-1] == 'using':
- from django.db import router
-else:
- router = False
+DJANGO_1_3 = LooseVersion(django.get_version()) < LooseVersion('1.4')
if 'reversion' in settings.INSTALLED_APPS:
import reversion
@@ -56,6 +53,17 @@
from django.contrib.admin import ModelAdmin
create_on_success = lambda x: x
+if DJANGO_1_3:
+ """
+ Backwards compatibility for Django < 1.4 and django-reversion 1.6
+ """
+ class ModelAdmin(ModelAdmin):
+ def get_inline_instances(self, request):
+ return self.inline_instances
+
+ def get_prepopulated_fields(self, request):
+ return self.prepopulated_fields
+
def contribute_fieldsets(cls):
if settings.CMS_MENU_TITLE_OVERWRITE:
@@ -168,7 +176,7 @@ class Media:
'css/jquery.dialog.css',
)]
}
- js = ['%sjs/jquery.min.js' % settings.ADMIN_MEDIA_PREFIX] + [cms_static_url(path) for path in [
+ js = ['%sjs/jquery.min.js' % admin_static_url()] + [cms_static_url(path) for path in [
'js/plugins/admincompat.js',
'js/libs/jquery.query.js',
'js/libs/jquery.ui.core.js',
@@ -204,6 +212,7 @@ def get_urls(self):
pat(r'^([0-9]+)/remove-delete-state/$', self.remove_delete_state),
pat(r'^([0-9]+)/dialog/copy/$', get_copy_dialog), # copy dialog
pat(r'^([0-9]+)/preview/$', self.preview_page), # copy dialog
+ pat(r'^([0-9]+)/descendants/$', self.descendants), # menu html for page descendants
pat(r'^(?P<object_id>\d+)/change_template/$', self.change_template), # copy dialog
)
@@ -461,7 +470,9 @@ def get_form(self, request, obj=None, **kwargs):
# remove permission inlines, if user isn't allowed to change them
def get_formsets(self, request, obj=None):
if obj:
- for inline in self.inline_instances:
+ inlines = self.get_inline_instances(request) if hasattr(self, 'get_inline_instances') \
+ else self.inline_instances
+ for inline in inlines:
if settings.CMS_PERMISSION and isinstance(inline, PagePermissionInlineAdmin) and not isinstance(inline, ViewRestrictionInlineAdmin):
if "recover" in request.path or "history" in request.path: #do not display permissions in recover mode
continue
@@ -489,7 +500,7 @@ def add_view(self, request, form_url='', extra_context=None):
extra_context.update({
'language': language,
})
- return super(PageAdmin, self).add_view(request, form_url, extra_context)
+ return super(PageAdmin, self).add_view(request, form_url, extra_context=extra_context)
def change_view(self, request, object_id, extra_context=None):
"""
@@ -518,7 +529,7 @@ def change_view(self, request, object_id, extra_context=None):
'page': obj,
'CMS_PERMISSION': settings.CMS_PERMISSION,
'CMS_MODERATOR': settings.CMS_MODERATOR,
- 'ADMIN_MEDIA_URL': settings.ADMIN_MEDIA_PREFIX,
+ 'ADMIN_MEDIA_URL': settings.STATIC_URL,
'has_change_permissions_permission': obj.has_change_permissions_permission(request),
'has_moderate_permission': obj.has_moderate_permission(request),
'moderation_level': moderation_level,
@@ -530,7 +541,7 @@ def change_view(self, request, object_id, extra_context=None):
}
extra_context = self.update_language_tab_context(request, obj, extra_context)
tab_language = request.GET.get("language", None)
- response = super(PageAdmin, self).change_view(request, object_id, extra_context)
+ response = super(PageAdmin, self).change_view(request, object_id, extra_context=extra_context)
if tab_language and response.status_code == 302 and response._headers['location'][1] == request.path :
location = response._headers['location']
@@ -639,12 +650,12 @@ def changelist_view(self, request, extra_context=None):
if not self.has_change_permission(request, None):
raise PermissionDenied
try:
- if hasattr(self, 'list_editable'):# django 1.1
+ if DJANGO_1_3:
cl = CMSChangeList(request, self.model, self.list_display, self.list_display_links, self.list_filter,
self.date_hierarchy, self.search_fields, self.list_select_related, self.list_per_page, self.list_editable, self)
- else:# django 1.0.2
+ else:
cl = CMSChangeList(request, self.model, self.list_display, self.list_display_links, self.list_filter,
- self.date_hierarchy, self.search_fields, self.list_select_related, self.list_per_page, self)
+ self.date_hierarchy, self.search_fields, self.list_select_related, self.list_per_page, self.list_max_show_all, self.list_editable, self)
except IncorrectLookupParameters:
# Wacky lookup parameters were given, so redirect to the main
# changelist page, without parameters, and pass an 'invalid=1'
@@ -667,14 +678,23 @@ def changelist_view(self, request, extra_context=None):
languages = settings.CMS_SITE_LANGUAGES[site_id]
else:
languages = [x[0] for x in settings.CMS_LANGUAGES]
-
+
+ # parse the cookie that saves which page trees have
+ # been opened already and extracts the page ID
+ djangocms_nodes_open = request.COOKIES.get('djangocms_nodes_open', '')
+ raw_nodes = unquote(djangocms_nodes_open).split(',')
+ try:
+ open_menu_trees = [int(c.split('page_', 1)[1]) for c in raw_nodes]
+ except IndexError:
+ open_menu_trees = []
+
context = {
'title': cl.title,
'is_popup': cl.is_popup,
'cl': cl,
'opts':opts,
'has_add_permission': self.has_add_permission(request),
- 'root_path': self.admin_site.root_path,
+ 'root_path': reverse('admin:index'),
'app_label': app_label,
'CMS_MEDIA_URL': settings.CMS_MEDIA_URL,
'softroot': settings.CMS_SOFTROOT,
@@ -683,6 +703,7 @@ def changelist_view(self, request, extra_context=None):
'has_recover_permission': 'reversion' in settings.INSTALLED_APPS and self.has_recover_permission(request),
'DEBUG': settings.DEBUG,
'site_languages': languages,
+ 'open_menu_trees': open_menu_trees,
}
if 'reversion' in settings.INSTALLED_APPS:
context['has_change_permission'] = self.has_change_permission(request)
@@ -935,19 +956,12 @@ def delete_translation(self, request, object_id, extra_context=None):
titleobj = get_object_or_404(Title, page__id=object_id, language=language)
saved_plugins = CMSPlugin.objects.filter(placeholder__page__id=object_id, language=language)
- if django.VERSION[1] > 2: # pragma: no cover
- # WARNING: Django 1.3 is not officially supported yet!
- using = router.db_for_read(self.model)
- kwargs = {
- 'admin_site': self.admin_site,
- 'user': request.user,
- 'using': using
- }
- else:
- kwargs = {
- 'admin_site': self.admin_site,
- 'user': request.user,
- }
+ using = router.db_for_read(self.model)
+ kwargs = {
+ 'admin_site': self.admin_site,
+ 'user': request.user,
+ 'using': using
+ }
deleted_objects, perms_needed = get_deleted_objects(
[titleobj],
titleopts,
@@ -993,8 +1007,8 @@ def delete_translation(self, request, object_id, extra_context=None):
"object": titleobj,
"deleted_objects": deleted_objects,
"perms_lacking": perms_needed,
- "opts": titleopts,
- "root_path": self.admin_site.root_path,
+ "opts": opts,
+ "root_path": reverse('admin:index'),
"app_label": app_label,
}
context.update(extra_context or {})
@@ -1042,7 +1056,7 @@ def change_status(self, request, page_id):
Switch the status of a page
"""
if request.method != 'POST':
- return HttpResponseNotAllowed
+ return HttpResponseNotAllowed(['POST'])
page = get_object_or_404(Page, pk=page_id)
if page.has_publish_permission(request):
page.published = not page.published
@@ -1057,7 +1071,7 @@ def change_innavigation(self, request, page_id):
"""
# why require post and still have page id in the URL???
if request.method != 'POST':
- return HttpResponseNotAllowed
+ return HttpResponseNotAllowed(['POST'])
page = get_object_or_404(Page, pk=page_id)
if page.has_change_permission(request):
page.in_navigation = not page.in_navigation
@@ -1065,6 +1079,18 @@ def change_innavigation(self, request, page_id):
return admin_utils.render_admin_menu_item(request, page)
return HttpResponseForbidden(_("You do not have permission to change this page's in_navigation status"))
+ def descendants(self, request, page_id):
+ """
+ Get html for descendants of given page
+ Used for lazy loading pages in change_list.js
+
+ Permission checks is done in admin_utils.get_admin_menu_item_context
+ which is called by admin_utils.render_admin_menu_item.
+ """
+ page = get_object_or_404(Page, pk=page_id)
+ return admin_utils.render_admin_menu_item(request, page,
+ template="admin/cms/page/lazy_menu.html")
+
@create_on_success
def add_plugin(self, request):
'''
@@ -1189,7 +1215,6 @@ def edit_plugin(self, request, plugin_id):
from reversion.models import Version
pre_edit = request.path.split("/edit-plugin/")[0]
version_id = pre_edit.split("/")[-1]
- Version.objects.get(pk=version_id)
version = get_object_or_404(Version, pk=version_id)
rev_objs = []
for related_version in version.revision.version_set.all():
@@ -1227,7 +1252,7 @@ def edit_plugin(self, request, plugin_id):
pass
if request.method == "POST":
# set the continue flag, otherwise will plugin_admin make redirect to list
- # view, which actually does'nt exists
+ # view, which actually doesn't exists
request.POST['_continue'] = True
if 'reversion' in settings.INSTALLED_APPS and ('history' in request.path or 'recover' in request.path):
@@ -1235,6 +1260,27 @@ def edit_plugin(self, request, plugin_id):
context = RequestContext(request)
return render_to_response(plugin_admin.render_template, plugin_admin.render(context, instance, plugin_admin.placeholder))
+ if request.POST.get("_cancel", False):
+ # cancel button was clicked
+ context = {
+ 'CMS_MEDIA_URL': settings.CMS_MEDIA_URL,
+ 'plugin': cms_plugin,
+ 'is_popup': True,
+ 'name': unicode(cms_plugin),
+ "type": cms_plugin.get_plugin_name(),
+ 'plugin_id': plugin_id,
+ 'icon': force_escape(escapejs(cms_plugin.get_instance_icon_src())),
+ 'alt': force_escape(escapejs(cms_plugin.get_instance_icon_alt())),
+ 'cancel': True,
+ }
+ instance = cms_plugin.get_plugin_instance()[0]
+ if not instance:
+ # cancelled before any content was added to plugin
+ cms_plugin.delete()
+ context.update({
+ "deleted":True,
+ })
+ return render_to_response('admin/cms/page/plugin_forms_ok.html', context, RequestContext(request))
if not instance:
# instance doesn't exist, call add view
@@ -1268,8 +1314,8 @@ def edit_plugin(self, request, plugin_id):
'name': unicode(saved_object),
"type": saved_object.get_plugin_name(),
'plugin_id': plugin_id,
- 'icon': force_escape(escapejs(saved_object.get_instance_icon_src())),
- 'alt': force_escape(escapejs(saved_object.get_instance_icon_alt())),
+ 'icon': force_escape(saved_object.get_instance_icon_src()),
+ 'alt': force_escape(saved_object.get_instance_icon_alt()),
}
return render_to_response('admin/cms/page/plugin_forms_ok.html', context, RequestContext(request))
@@ -1302,6 +1348,10 @@ def move_plugin(self, request):
# plugin positions are 0 based, so just using count here should give us 'last_position + 1'
position = CMSPlugin.objects.filter(placeholder=placeholder).count()
plugin.position = position
+ # update the placeholder on all descendant plugins as well
+ for child in plugin.get_descendants():
+ child.placeholder = placeholder
+ child.save()
plugin.save()
success = True
if 'ids' in request.POST:
@@ -1377,7 +1427,7 @@ def change_moderation(self, request, page_id):
"""
from cms.models.moderatormodels import MASK_PAGE, MASK_CHILDREN, MASK_DESCENDANTS
if request.method != 'POST':
- return HttpResponseNotAllowed
+ return HttpResponseNotAllowed(['POST'])
page = get_object_or_404(Page, id=page_id)
moderate = request.POST.get('moderate', None)
if moderate is not None and page.has_moderate_permission(request):
View
38 cms/admin/permissionadmin.py
@@ -1,26 +1,48 @@
# -*- coding: utf-8 -*-
+from cms.admin.forms import (GlobalPagePermissionAdminForm,
+ PagePermissionInlineAdminForm, ViewRestrictionInlineAdminForm)
+from cms.exceptions import NoPermissionsException
+from cms.models import Page, PagePermission, GlobalPagePermission, PageUser
+from cms.utils.permissions import get_user_permission_level
from copy import deepcopy
+from distutils.version import LooseVersion
from django.conf import settings
+from django.contrib import admin
from django.template.defaultfilters import title
from django.utils.translation import ugettext as _
+import django
-from django.contrib import admin
-from cms.exceptions import NoPermissionsException
-from cms.models import Page, PagePermission, GlobalPagePermission, PageUser
-from cms.utils.permissions import get_user_permission_level
-from cms.admin.forms import (GlobalPagePermissionAdminForm,
- PagePermissionInlineAdminForm, ViewRestrictionInlineAdminForm)
+DJANGO_1_3 = LooseVersion(django.get_version()) < LooseVersion('1.4')
PAGE_ADMIN_INLINES = []
-class PagePermissionInlineAdmin(admin.TabularInline):
+class TabularInline(admin.TabularInline):
+ pass
+
+if DJANGO_1_3 and 'reversion' in settings.INSTALLED_APPS:
+ """
+ Backwards compatibility for Django < 1.4 and django-reversion 1.6
+ """
+ class TabularInline(TabularInline):
+ def get_prepopulated_fields(self, request, obj=None):
+ return self.prepopulated_fields
+ from reversion.admin import helpers
+ class CompatInlineAdminFormSet(helpers.InlineAdminFormSet):
+ def __init__(self, inline, formset, fieldsets, prepopulated_fields=None,
+ readonly_fields=None, model_admin=None):
+ super(CompatInlineAdminFormSet, self).__init__(inline, formset, fieldsets, readonly_fields, model_admin)
+ helpers.InlineAdminFormSet = CompatInlineAdminFormSet
+
+
+class PagePermissionInlineAdmin(TabularInline):
model = PagePermission
# use special form, so we can override of user and group field
form = PagePermissionInlineAdminForm
classes = ['collapse', 'collapsed']
exclude = ['can_view']
+ extra = 0 # edit page load time boost
def queryset(self, request):
"""
@@ -67,7 +89,7 @@ def get_formset(self, request, obj=None, **kwargs):
return formset_cls
class ViewRestrictionInlineAdmin(PagePermissionInlineAdmin):
- extra = 1
+ extra = 0 # edit page load time boost
form = ViewRestrictionInlineAdminForm
verbose_name = _("View restriction")
verbose_name_plural = _("View restrictions")
View
3  cms/admin/placeholderadmin.py
@@ -15,6 +15,7 @@
from django.template import RequestContext
from django.template.defaultfilters import force_escape, escapejs
from django.utils.translation import ugettext as _
+from cms.templatetags.cms_admin import admin_static_url
class PlaceholderAdmin(ModelAdmin):
@@ -29,7 +30,7 @@ class Media:
'css/plugin_editor.css',
)]
}
- js = ['%sjs/jquery.min.js' % settings.ADMIN_MEDIA_PREFIX] + [cms_static_url(path) for path in [
+ js = ['%sjs/jquery.min.js' % admin_static_url()] + [cms_static_url(path) for path in [
'js/plugins/admincompat.js',
'js/csrf.js',
'js/libs/jquery.query.js',
View
31 cms/appresolver.py
@@ -147,7 +147,6 @@ def get_app_patterns():
the title path and then included into the cms url patterns.
"""
from cms.models import Title
- from cms.models.pagemodel import Page
try:
current_site = Site.objects.get_current()
except Site.DoesNotExist:
@@ -159,14 +158,7 @@ def get_app_patterns():
# use draft(). This can be done, because url patterns are used just
# in frontend
is_draft = not settings.CMS_MODERATOR
- try:
- home = Page.objects.get_home()
- home_titles = home.title_set.all()
- except NoHomeFound:
- home_titles = []
- home_slugs = {}
- for title in home_titles:
- home_slugs[title.language] = title.slug
+
title_qs = Title.objects.filter(page__publisher_is_draft=is_draft, page__site=current_site)
if 'cms.middleware.multilingual.MultilingualURLMiddleware' in settings.MIDDLEWARE_CLASSES:
@@ -178,24 +170,11 @@ def get_app_patterns():
# Loop over all titles with an application hooked to them
for title in title_qs.exclude(application_urls=None).exclude(application_urls='').select_related():
- if settings.CMS_FLAT_URLS:
- if title.language in home_slugs:
- path = title.slug.split(home_slugs[title.language] + "/", 1)[-1]
- else:
- path = title.slug
- if use_namespaces:
- mixid = "%s:%s:%s" % (path + "/", title.application_urls, title.language)
- else:
- mixid = "%s:%s" % (path + "/", title.application_urls)
+ path = title.path
+ if use_namespaces:
+ mixid = "%s:%s:%s" % (path + "/", title.application_urls, title.language)
else:
- if title.language in home_slugs:
- path = title.path.split(home_slugs[title.language] + "/", 1)[-1]
- else:
- path = title.path
- if use_namespaces:
- mixid = "%s:%s:%s" % (path + "/", title.application_urls, title.language)
- else:
- mixid = "%s:%s" % (path + "/", title.application_urls)
+ mixid = "%s:%s" % (path + "/", title.application_urls)
if mixid in included:
# don't add the same thing twice
continue
View
6 cms/conf/__init__.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
from django.conf import settings
from patch import pre_patch, post_patch, post_patch_check
+import warnings
@@ -14,6 +15,9 @@ def patch_settings():
return
patch_settings.ALREADY_PATCHED = True
+ if getattr(settings, 'CMS_FLAT_URLS', False):
+ warnings.warn("CMS_FLAT_URLS are deprecated and will be removed in django CMS 2.4!", DeprecationWarning)
+
from cms.conf import global_settings
# patch settings
@@ -30,4 +34,4 @@ def patch_settings():
if settings.DEBUG:
# check if settings are correct, call this only if debugging is enabled
post_patch_check()
-patch_settings.ALREADY_PATCHED = False
+patch_settings.ALREADY_PATCHED = False
View
5 cms/conf/patch.py
@@ -55,7 +55,8 @@ def post_patch_check():
continue
if not validate_template(template[0], ['js', 'css']):
raise ImproperlyConfigured(
- "All templates defined in CMS_TEMPLATES must have at least the "
- "'js' and 'css' sekizai namespaces. The template %r does not. "
+ "The 'js' and 'css' sekizai namespaces must be present in each template, "
+ "- or a template it inherits from - defined in CMS_TEMPLATES. "
+ "I can't find the namespaces in %r."
% template[0]
)
View
11 cms/forms/utils.py
@@ -8,6 +8,7 @@
from django.core.cache import cache
from django.db.models.signals import post_save, post_delete
from django.utils import translation
+from django.utils.datastructures import SortedDict
from django.utils.safestring import mark_safe
@@ -19,11 +20,13 @@ def update_site_and_page_choices(lang=None):
title_queryset = Title.objects.filter(page__publisher_is_draft=False)
else:
title_queryset = Title.objects.filter(page__publisher_is_draft=True)
- title_queryset = title_queryset.select_related('page', 'page__site')
- pages = defaultdict(lambda: defaultdict(dict))
+ title_queryset = title_queryset.select_related('page', 'page__site').order_by('page__tree_id', 'page__lft', 'page__rght')
+ pages = defaultdict(SortedDict)
sites = {}
for title in title_queryset:
- pages[title.page.site.pk][title.page.pk][title.language] = title
+ page = pages[title.page.site.pk].get(title.page.pk, {})
+ page[title.language] = title
+ pages[title.page.site.pk][title.page.pk] = page
sites[title.page.site.pk] = title.page.site.name
site_choices = []
@@ -93,4 +96,4 @@ def clean_page_choices_cache(sender, **kwargs):
post_save.connect(clean_page_choices_cache, sender=Page)
post_save.connect(clean_site_choices_cache, sender=Site)
post_delete.connect(clean_page_choices_cache, sender=Page)
-post_delete.connect(clean_site_choices_cache, sender=Site)
+post_delete.connect(clean_site_choices_cache, sender=Site)
View
3  cms/forms/widgets.py
@@ -12,6 +12,7 @@
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext as _
import copy
+from cms.templatetags.cms_admin import admin_static_url
class PageSelectWidget(MultiWidget):
"""A widget that allows selecting a page by first selecting a site and then
@@ -170,7 +171,7 @@ def render(self, name, value, attrs=None, choices=()):
add_url = '../../../cms/pageuser/add/'
output.append(u'<a href="%s" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \
(add_url, name))
- output.append(u'<img src="%simg/admin/icon_addlink.gif" width="10" height="10" alt="%s"/></a>' % (settings.ADMIN_MEDIA_PREFIX, _('Add Another')))
+ output.append(u'<img src="%simg/admin/icon_addlink.gif" width="10" height="10" alt="%s"/></a>' % (admin_static_url(), _('Add Another')))
return mark_safe(u''.join(output))
View
BIN  cms/locale/it/LC_MESSAGES/django.mo
Binary file not shown
View
4 cms/locale/it/LC_MESSAGES/django.po
@@ -1289,7 +1289,7 @@ msgstr "Impostazioni colore"
#: plugins/video/models.py:9
msgid "movie file"
-msgstr "richiesta di spostamento"
+msgstr "file video"
#: plugins/video/models.py:9
msgid "use .flv file or h264 encoded video file"
@@ -1297,7 +1297,7 @@ msgstr "Usa file un file video .flv o codificato h264"
#: plugins/video/models.py:10
msgid "movie url"
-msgstr "richiesta di modifica"
+msgstr "indirizzo video"
#: plugins/video/models.py:10
#, fuzzy
View
214 cms/menu.py
@@ -2,51 +2,99 @@
from collections import defaultdict
from cms.apphook_pool import apphook_pool
from cms.models.moderatormodels import (ACCESS_DESCENDANTS,
- ACCESS_PAGE_AND_DESCENDANTS, ACCESS_CHILDREN, ACCESS_PAGE_AND_CHILDREN)
+ ACCESS_PAGE_AND_DESCENDANTS, ACCESS_CHILDREN, ACCESS_PAGE_AND_CHILDREN, ACCESS_PAGE)
from cms.models.permissionmodels import PagePermission, GlobalPagePermission
from cms.models.titlemodels import Title
from cms.utils import get_language_from_request
from cms.utils.i18n import get_fallback_languages
from cms.utils.moderator import get_page_queryset, get_title_queryset
from cms.utils.plugins import current_site
-from django.conf import settings
-from django.contrib.sites.models import Site
-from django.db.models.query_utils import Q
from menus.base import Menu, NavigationNode, Modifier
from menus.menu_pool import menu_pool
+from django.conf import settings
+from django.contrib.sites.models import Site
+from django.db.models.query_utils import Q
+from django.contrib.auth.models import Permission
def get_visible_pages(request, pages, site=None):
- # This code is basically a many-pages-at-once version of
- # Page.has_view_permission, check there to see wtf is going on here.
- if request.user.is_staff and settings.CMS_PUBLIC_FOR in ('staff', 'all'):
- return [page.pk for page in pages]
- page_ids = []
+ """
+ This code is basically a many-pages-at-once version of
+ Page.has_view_permission.
+ pages contains all published pages
+ check if there is ANY restriction
+ that needs a permission page visibility calculation
+ """
+ is_setting_public_all = settings.CMS_PUBLIC_FOR == 'all'
+ is_setting_public_staff = settings.CMS_PUBLIC_FOR == 'staff'
+ is_auth_user = request.user.is_authenticated()
+ visible_page_ids = []
+ restricted_pages = defaultdict(list)
pages_perms_q = Q()
+
for page in pages:
+ # taken from for_page as multiple at once version
page_q = Q(page__tree_id=page.tree_id) & (
Q(page=page)
| (Q(page__level__lt=page.level) & (Q(grant_on=ACCESS_DESCENDANTS) | Q(grant_on=ACCESS_PAGE_AND_DESCENDANTS)))
| (Q(page__level=page.level - 1) & (Q(grant_on=ACCESS_CHILDREN) | Q(grant_on=ACCESS_PAGE_AND_CHILDREN)))
)
pages_perms_q |= page_q
+
+
pages_perms_q &= Q(can_view=True)
page_permissions = PagePermission.objects.filter(pages_perms_q).select_related('page', 'group__users')
-
- restricted_pages = defaultdict(list)
+
for perm in page_permissions:
- restricted_pages[perm.page.pk].append(perm)
+ # collect the pages that are affected by permissions
+ if perm is not None and perm not in restricted_pages[perm.page.pk]:
+ # affective restricted pages gathering
+ # using mptt functions
+ # add the page with the perm itself
+ if perm.grant_on in [ACCESS_PAGE, ACCESS_PAGE_AND_CHILDREN ,ACCESS_PAGE_AND_DESCENDANTS]:
+ restricted_pages[perm.page.pk].append(perm)
+ # add children
+ if perm.grant_on in [ACCESS_CHILDREN, ACCESS_PAGE_AND_CHILDREN]:
+ child_ids = perm.page.get_children().values_list('id', flat=True)
+ for id in child_ids:
+ restricted_pages[id].append(perm)
+ # add descendants
+ elif perm.grant_on in [ACCESS_DESCENDANTS, ACCESS_PAGE_AND_DESCENDANTS]:
+ child_ids = perm.page.get_descendants().values_list('id', flat=True)
+ for id in child_ids:
+ restricted_pages[id].append(perm)
+ # anonymous
+ # no restriction applied at all
+ if (not is_auth_user and
+ is_setting_public_all and
+ not restricted_pages):
+ return [page.pk for page in pages]
+
if site is None:
site = current_site(request)
- if request.user.is_authenticated():
- #return self.filter(Q(user=user) | Q(group__user=user))
+ # authenticated user and global permission
+ if is_auth_user:
global_page_perm_q = Q(
Q(user=request.user) | Q(group__user=request.user)
) & Q(can_view=True) & Q(Q(sites__in=[site.pk]) | Q(sites__isnull=True))
global_view_perms = GlobalPagePermission.objects.filter(global_page_perm_q).exists()
+
+ #no page perms edgcase - all visible
+ if ((is_setting_public_all or (
+ is_setting_public_staff and request.user.is_staff))and
+ not restricted_pages and
+ not global_view_perms):
+ return [page.pk for page in pages]
+ #no page perms edgcase - none visible
+ elif (is_setting_public_staff and
+ not request.user.is_staff and
+ not restricted_pages and
+ not global_view_perms):
+ return []
+
def has_global_perm():
if has_global_perm.cache < 0:
@@ -54,38 +102,56 @@ def has_global_perm():
return bool(has_global_perm.cache)
has_global_perm.cache = -1
- def has_permission(page):
+ def has_permission_membership(page):
"""
- PagePermission tests
+ PagePermission user group membership tests
"""
- for perm in restricted_pages[page.pk]:
- if perm.user_id == request.user.pk:
- return True
- for perm in restricted_pages[page.pk]:
+ user_pk = request.user.pk
+ page_pk = page.pk
+ has_perm = False
+ for perm in restricted_pages[page_pk]:
+ if perm.user_id == user_pk:
+ has_perm = True
if not perm.group_id:
continue
- if request.user.pk in perm.group.user_set.values_list('id', flat=True):
- return True
- return False
+ group_user_ids = perm.group.user_set.values_list('pk', flat=True)
+ if user_pk in group_user_ids:
+ has_perm = True
+ return has_perm
for page in pages:
+ to_add = False
+ # default to false, showing a restricted page is bad
+ # explicitly check all the conditions
+ # of settings and permissions
is_restricted = page.pk in restricted_pages
-
- if request.user.is_authenticated():
+ # restricted_pages contains as key any page.pk that is
+ # affected by a permission grant_on
+ if is_auth_user:
# a global permission was given to the request's user
if global_view_perms:
- page_ids.append(page.pk)
- # authenticated user, no restriction and public for all
- elif settings.CMS_PUBLIC_FOR == 'all':
- page_ids.append(page.pk)
- elif has_permission(page):
- page_ids.append(page.pk)
+ to_add = True
+ # setting based handling of unrestricted pages
+ elif not is_restricted and (
+ is_setting_public_all or (
+ is_setting_public_staff and request.user.is_staff)
+ ):
+ # authenticated user, no restriction and public for all
+ # or
+ # authenticated staff user, no restriction and public for staff
+ to_add = True
+ # check group and user memberships to restricted pages
+ elif is_restricted and has_permission_membership(page):
+ to_add = True
elif has_global_perm():
- page_ids.append(page.pk)
- elif not is_restricted and settings.CMS_PUBLIC_FOR == 'all':
- # anonymous user, no restriction saved in database
- page_ids.append(page.pk)
- return page_ids
+ to_add = True
+ # anonymous user, no restriction
+ elif not is_restricted and is_setting_public_all:
+ to_add = True
+ # store it
+ if to_add:
+ visible_page_ids.append(page.pk)
+ return visible_page_ids
def page_to_node(page, home, cut):
'''
@@ -178,7 +244,6 @@ def get_nodes(self, request):
# cache view perms
visible_pages = get_visible_pages(request, pages, site)
-
for page in pages:
# Pages are ordered by tree_id, therefore the first page is the root
# of the page tree (a.k.a "home")
@@ -190,8 +255,6 @@ def get_nodes(self, request):
page.home_pk_cache = home.pk
if first and page.pk != home.pk:
home_cut = True
- elif not settings.CMS_PUBLIC_FOR == 'all':
- continue
if (page.parent_id == home.pk or page.parent_id in home_children) and home_cut:
home_children.append(page.pk)
if (page.pk == home.pk and home.in_navigation) or page.pk != home.pk:
@@ -277,7 +340,70 @@ def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb):
class SoftRootCutter(Modifier):
"""
- If anyone understands this, PLEASE write a meaningful description here!
+ Ask evildmp/superdmp if you don't understand softroots!
+
+ Softroot description from the docs:
+
+ A soft root is a page that acts as the root for a menu navigation tree.
+
+ Typically, this will be a page that is the root of a significant new
+ section on your site.
+
+ When the soft root feature is enabled, the navigation menu for any page
+ will start at the nearest soft root, rather than at the real root of
+ the site’s page hierarchy.
+
+ This feature is useful when your site has deep page hierarchies (and
+ therefore multiple levels in its navigation trees). In such a case, you
+ usually don’t want to present site visitors with deep menus of nested
+ items.
+
+ For example, you’re on the page -Introduction to Bleeding-?, so the menu
+ might look like this:
+
+ School of Medicine
+ Medical Education
+ Departments
+ Department of Lorem Ipsum
+ Department of Donec Imperdiet
+ Department of Cras Eros
+ Department of Mediaeval Surgery
+ Theory
+ Cures
+ Bleeding
+ Introduction to Bleeding <this is the current page>
+ Bleeding - the scientific evidence
+ Cleaning up the mess
+ Cupping
+ Leaches
+ Maggots
+ Techniques
+ Instruments
+ Department of Curabitur a Purus
+ Department of Sed Accumsan
+ Department of Etiam
+ Research
+ Administration
+ Contact us
+ Impressum
+
+ which is frankly overwhelming.
+
+ By making -Department of Mediaeval Surgery-? a soft root, the menu
+ becomes much more manageable:
+
+ Department of Mediaeval Surgery
+ Theory
+ Cures
+ Bleeding
+ Introduction to Bleeding <current page>
+ Bleeding - the scientific evidence
+ Cleaning up the mess
+ Cupping
+ Leaches
+ Maggots
+ Techniques
+ Instruments
"""
def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb):
# only apply this modifier if we're pre-cut (since what we do is cut)
@@ -305,13 +431,7 @@ def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb):
else:
# if it's not a soft root, walk ancestors (upwards!)
nodes = self.find_ancestors_and_remove_children(selected, nodes)
- # remove child-softroots from descendants (downwards!)
- nodes = self.find_and_remove_children(selected, nodes)
- else:
- # for all nodes in root, remove child-sofroots (downwards!)
- for node in root_nodes:
- self.find_and_remove_children(node, nodes)
- return nodes
+ return nodes
def find_and_remove_children(self, node, nodes):
for n in node.children:
View
13 cms/middleware/multilingual.py
@@ -6,6 +6,7 @@
from django.utils import translation
import re
import urllib
+import urlparse
SUPPORTED = dict(settings.CMS_LANGUAGES)
@@ -38,7 +39,7 @@ def patch_response(content, pages_root, language):
# If the regex matches, the extracted path we want is stored in the fourth group (\4).
quoted_root = urllib.quote(pages_root)
ignore_paths = ['%s%s/' % (quoted_root, l[0]) for l in settings.CMS_LANGUAGES]
- ignore_paths += [settings.MEDIA_URL, settings.ADMIN_MEDIA_PREFIX]
+ ignore_paths += [settings.MEDIA_URL, settings.STATIC_URL]
if getattr(settings,'STATIC_URL', False):
ignore_paths += [settings.STATIC_URL]
@@ -53,7 +54,7 @@ def patch_response(content, pages_root, language):
# For understanding this regex, please read the documentation for HREF_URL_FIX_RE above.
ignore_paths = ['%s%s/' % (pages_root, l[0]) for l in settings.CMS_LANGUAGES]
- ignore_paths += [settings.MEDIA_URL, settings.ADMIN_MEDIA_PREFIX]
+ ignore_paths += [settings.MEDIA_URL, settings.STATIC_URL]
if getattr(settings,'STATIC_URL', False):
ignore_paths += [settings.STATIC_URL]
FORM_URL_FIX_RE = re.compile(ur'<form([^>]+)action=("|\')(?=%s)(?!(%s))(%s(.*?))("|\')(.*?)>' % (
@@ -110,7 +111,7 @@ def process_response(self, request, response):
# testing this and throwing an exception otherwise, would probably be a good idea
if not path.startswith(settings.MEDIA_URL) and \
- not path.startswith(settings.ADMIN_MEDIA_PREFIX) and \
+ not path.startswith(settings.STATIC_URL) and \
not (getattr(settings,'STATIC_URL', False) and path.startswith(settings.STATIC_URL)) and \
response.status_code == 200 and \
response._headers['content-type'][1].split(';')[0] == "text/html":
@@ -128,10 +129,12 @@ def process_response(self, request, response):
if (response.status_code == 301 or response.status_code == 302 ):
location = response['Location']
+ if location.startswith('.'):
+ location = urlparse.urljoin(request.path, location)
+ response['Location'] = location
if not has_lang_prefix(location) and location.startswith("/") and \
not location.startswith(settings.MEDIA_URL) and \
- not (getattr(settings,'STATIC_URL', False) and location.startswith(settings.STATIC_URL)) and \
- not location.startswith(settings.ADMIN_MEDIA_PREFIX):
+ not (getattr(settings,'STATIC_URL', False) and location.startswith(settings.STATIC_URL)):
response['Location'] = "/%s%s" % (language, location)
response.set_cookie("django_language", language)
return response
View
20 cms/models/managers.py
@@ -343,13 +343,23 @@ def for_page(self, page):
"""
from cms.models import ACCESS_DESCENDANTS, ACCESS_CHILDREN,\
ACCESS_PAGE_AND_CHILDREN, ACCESS_PAGE_AND_DESCENDANTS
+ # code taken from
+ # https://github.com/divio/django-cms/issues/1113#issuecomment-3376790
+ q_tree = Q(page__tree_id=page.tree_id)
+ q_page = Q(page=page)
- q = Q(page__tree_id=page.tree_id) & (
- Q(page=page)
- | (Q(page__level__lt=page.level) & (Q(grant_on=ACCESS_DESCENDANTS) | Q(grant_on=ACCESS_PAGE_AND_DESCENDANTS)))
- | (Q(page__level=page.level - 1) & (Q(grant_on=ACCESS_CHILDREN) | Q(grant_on=ACCESS_PAGE_AND_CHILDREN)))
- )
+ # NOTE: '... or 0' is used for test cases,
+ # if the page is not saved through mptt
+ left_right = {
+ 'page__%s__lte' % page._mptt_meta.left_attr: getattr(page, page._mptt_meta.left_attr) or 0,
+ 'page__%s__gte' % page._mptt_meta.right_attr: getattr(page, page._mptt_meta.right_attr) or 0,
+ }
+ q_parents = Q(**left_right)
+ q_desc = (Q(page__level__lt=page.level) & (Q(grant_on=ACCESS_DESCENDANTS) | Q(grant_on=ACCESS_PAGE_AND_DESCENDANTS)))
+ q_kids = (Q(page__level=page.level - 1) & (Q(grant_on=ACCESS_CHILDREN) | Q(grant_on=ACCESS_PAGE_AND_CHILDREN)))
+ q = q_tree & q_parents & (q_page | q_desc | q_kids)
return self.filter(q).order_by('page__level')
+
class PagePermissionsPermissionManager(models.Manager):
"""Page permissions permission manager.
View
36 cms/models/pagemodel.py
@@ -286,6 +286,8 @@ def copy_page(self, target, site, position='first-child',
ph.pk = None # make a new instance
ph.save()
page.placeholders.add(ph)
+ # update the page copy
+ page_copy = page
if plugins:
copy_plugins_to(plugins, ph)
@@ -680,17 +682,12 @@ def get_template_name(self):
def has_view_permission(self, request):
from cms.models.permissionmodels import PagePermission, GlobalPagePermission
from cms.utils.plugins import current_site
- # staff is allowed to see everything
- if request.user.is_staff and settings.CMS_PUBLIC_FOR in ('staff', 'all'):
- return True
-
+
if not self.publisher_is_draft and self.publisher_public:
return self.publisher_public.has_view_permission(request)
# does any restriction exist?
- # direct
# inherited and direct
- is_restricted = PagePermission.objects.for_page(self).filter(can_view=True).exists()
-
+ is_restricted = PagePermission.objects.for_page(page=self).filter(can_view=True).exists()
if request.user.is_authenticated():
site = current_site(request)
global_perms_q = Q(can_view=True) & Q(
@@ -698,13 +695,26 @@ def has_view_permission(self, request):
)
global_view_perms = GlobalPagePermission.objects.with_user(
request.user).filter(global_perms_q).exists()
+
# a global permission was given to the request's user
if global_view_perms:
return True
- # authenticated user, no restriction and public for all
- if (not is_restricted and not global_view_perms and
- settings.CMS_PUBLIC_FOR == 'all'):
- return True
+
+ elif not is_restricted:
+ if ((settings.CMS_PUBLIC_FOR == 'all') or
+ (settings.CMS_PUBLIC_FOR == 'staff' and
+ request.user.is_staff)):
+ return True
+
+ # a restricted page and an authenticated user
+ elif is_restricted:
+ opts = self._meta
+ codename = '%s.view_%s' % (opts.app_label, opts.object_name.lower())
+ user_perm = request.user.has_perm(codename)
+ generic_perm = self.has_generic_permission(request, "view")
+ return (user_perm or generic_perm)
+
+
else:
#anonymous user
if is_restricted or not settings.CMS_PUBLIC_FOR == 'all':
@@ -922,7 +932,7 @@ def get_next_filtered_sibling(self, **filters):
Returns this model instance's next sibling in the tree, or
``None`` if it doesn't have a next sibling.
"""
- opts = self._meta
+ opts = self._mptt_meta
if self.is_root_node():
filters.update({
'%s__isnull' % opts.parent_attr: True,
@@ -955,7 +965,7 @@ def get_previous_filtered_sibling(self, **filters):
Returns this model instance's previous sibling in the tree, or
``None`` if it doesn't have a previous sibling.
"""
- opts = self._meta
+ opts = self._mptt_meta
if self.is_root_node():
filters.update({
'%s__isnull' % opts.parent_attr: True,
View
11 cms/models/placeholdermodel.py
@@ -7,8 +7,6 @@
from django.utils.translation import ugettext_lazy as _
import operator
-
-
class Placeholder(models.Model):
slot = models.CharField(_("slot"), max_length=50, db_index=True, editable=False)
default_width = models.PositiveSmallIntegerField(_("width"), null=True, editable=False)
@@ -22,9 +20,15 @@ def __unicode__(self):
def get_add_url(self):
return self._get_url('add_plugin')
+ def get_move_url(self):
+ return self._get_url('move_plugin')
+
+ def get_remove_url(self):
+ return self._get_url('remove_plugin')
+
def get_changelist_url(self):
return self._get_url('changelist')
-
+
def _get_url(self, key):
model = self._get_attached_model()
if not model:
@@ -120,7 +124,6 @@ def _get_attached_models(self):
Returns a list of models of attached to this placeholder.
"""
return [field.model for field in self._get_attached_fields()]
-
def get_plugins_list(self):
return list(self.get_plugins())
View
8 cms/models/pluginmodel.py
@@ -52,8 +52,12 @@ def __new__(cls, name, bases, attrs):
# 'myapp_' bit from the db_table name.
if [base for base in bases if isinstance(base, PluginModelBase)]:
splitter = '%s_' % new_class._meta.app_label
- splitted = new_class._meta.db_table.split(splitter, 1)
- table_name = 'cmsplugin_%s' % splitted[1]
+
+ if splitter in new_class._meta.db_table:
+ splitted = new_class._meta.db_table.split(splitter, 1)
+ table_name = 'cmsplugin_%s' % splitted[1]
+ else:
+ table_name = new_class._meta.db_table
new_class._meta.db_table = table_name
return new_class
View
14 cms/plugin_rendering.py
@@ -149,16 +149,14 @@ def render_placeholder_toolbar(placeholder, context, content, name_fallback=None
else:
slot = None
installed_plugins = plugin_pool.get_all_plugins(slot, page)
- name = get_placeholder_conf(slot, template, "name", title(slot))
+ name = get_placeholder_conf("name", slot, template, title(slot))
name = _(name)
context.push()
- context.update({
- 'installed_plugins': installed_plugins,
- 'language': get_language_from_request(request),
- 'placeholder_label': name,
- 'placeholder': placeholder,
- 'page': page,
- })
+ context['installed_plugins'] = installed_plugins
+ context['language'] = get_language_from_request(request)
+ context['placeholder_label'] = name
+ context['placeholder'] = placeholder
+ context['page'] = page
toolbar = render_to_string("cms/toolbar/placeholder.html", context)
context.pop()
return "".join([toolbar, content])
View
5 cms/plugins/file/migrations/0005_publisher2.py
@@ -4,6 +4,11 @@
from cms.plugins.file.models import *
class Migration:
+ needed_by = (
+ # Migration after cms.publisher2, keep migrations in sync with real db
+ # Fixes migration error in MySQL
+ ("cms", "0022_login_required_added.py"),
+ )
def forwards(self, orm):
View
4 cms/plugins/file/templates/cms/plugins/file.html
@@ -3,7 +3,7 @@
<p class="plugin_file">
<a href="{{ object.file.url }}">
{% if object.get_icon_url %}<img src="{{ object.get_icon_url }}" alt="" />{% endif %}
- {% if object.title %}<span class="filetitle">{{ object.title }}{% else %}{{ object.get_file_name }}{% endif %} {% if object.file_exists %}<span class="filesize">({{ object.file.size|filesizeformat }})</span>{% else %}({% trans "file missing!" %})</span>{% endif %}
+ {% if object.title %}<span class="filetitle">{{ object.title }}{% else %}{{ object.get_file_name }}{% endif %} {% if object.file_exists %}<span class="filesize">({{ object.file.size|filesizeformat }})</span>{% else %}({% trans "file missing!" %}){% endif %}{% if object.title %}</span>{% endif %}
</a>
</p>
-{% endif %}
+{% endif %}
View
5 cms/plugins/flash/migrations/0005_publisher2.py
@@ -4,6 +4,11 @@
from cms.plugins.flash.models import *
class Migration:
+ needed_by = (
+ # Migration after cms.publisher2, keep migrations in sync with real db
+ # Fixes migration error in MySQL
+ ("cms", "0022_login_required_added.py"),
+ )
def forwards(self, orm):
View
5 cms/plugins/googlemap/migrations/0006_publisher2.py
@@ -4,6 +4,11 @@
from cms.plugins.googlemap.models import *
class Migration:
+ needed_by = (
+ # Migration after cms.publisher2, keep migrations in sync with real db
+ # Fixes migration error in MySQL
+ ("cms", "0022_login_required_added.py"),
+ )
def forwards(self, orm):
View
2  cms/plugins/inherit/models.py
@@ -1,7 +1,7 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
from cms.models import CMSPlugin, Page
-from cms import settings
+from django.conf import settings
class InheritPagePlaceholder(CMSPlugin):
"""
View
5 cms/plugins/link/migrations/0007_publisher2.py
@@ -4,6 +4,11 @@
from cms.plugins.link.models import *
class Migration:
+ needed_by = (
+ # Migration after cms.publisher2, keep migrations in sync with real db
+ # Fixes migration error in MySQL
+ ("cms", "0022_login_required_added.py"),
+ )
def forwards(self, orm):
View
5 cms/plugins/picture/migrations/0007_publisher2.py
@@ -4,6 +4,11 @@
from cms.plugins.picture.models import *
class Migration:
+ needed_by = (
+ # Migration after cms.publisher2, keep migrations in sync with real db
+ # Fixes migration error in MySQL
+ ("cms", "0022_login_required_added.py"),
+ )
def forwards(self, orm):
View
5 cms/plugins/snippet/migrations/0004_publisher2.py
@@ -4,6 +4,11 @@
from cms.plugins.snippet.models import *
class Migration:
+ needed_by = (
+ # Migration after cms.publisher2, keep migrations in sync with real db
+ # Fixes migration error in MySQL
+ ("cms", "0022_login_required_added.py"),
+ )
def forwards(self, orm):
View
5 cms/plugins/teaser/migrations/0002_publisher2.py
@@ -4,6 +4,11 @@
from cms.plugins.teaser.models import *
class Migration:
+ needed_by = (
+ # Migration after cms.publisher2, keep migrations in sync with real db
+ # Fixes migration error in MySQL
+ ("cms", "0022_login_required_added.py"),
+ )
def forwards(self, orm):
View
5 cms/plugins/text/migrations/0005_publisher2.py
@@ -4,6 +4,11 @@
from cms.plugins.text.models import *
class Migration:
+ needed_by = (
+ # Migration after cms.publisher2, keep migrations in sync with real db
+ # Fixes migration error in MySQL
+ ("cms", "0022_login_required_added.py"),
+ )
def forwards(self, orm):
View
1  cms/plugins/text/templates/cms/plugins/text_plugin_change_form.html
@@ -6,6 +6,7 @@
{% include "cms/plugins/text_plugin_fieldset.html" %}
{% endfor %}
<script type="text/javascript" src="{{ STATIC_URL }}cms/js/libs/classy.min.js"></script>
+<script type="text/javascript" src="{{ STATIC_URL }}cms/js/plugins/cms.setup.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}cms/js/plugins/cms.base.js"></script>
<script type="text/javascript">
jQuery(document).ready(function ($) {
View
14 cms/plugins/text/templates/cms/plugins/widgets/tinymce.html
@@ -41,7 +41,7 @@
texteditor = get_editor("{{ name }}");
// First create db instance using AJAX post back
- add_plugin(pluginvalue, parent_id, language)
+ add_plugin(pluginvalue, parent_id, language);
}
});
{% for p in installed_plugins %}
@@ -84,11 +84,11 @@
tinymce.PluginManager.add('cmsplugins', tinymce.plugins.CMSPluginEditor);
function init_plugin_editor(placeholder){
- var toolbar = get_plugin_html()
- var html = '<table class="mceToolbar mceToolbarRow3 Enabled"><tbody>'
- html += '<td class="mceToolbarStart mceToolbarStartListBox mceFirst">'
- html += '<span></span>'
- html += '</td><td>' + toolbar + '</td></tbody></table>'
+ var toolbar = get_plugin_html();
+ var html = '<table class="mceToolbar mceToolbarRow3 Enabled"><tbody>';
+ html += '<td class="mceToolbarStart mceToolbarStartListBox mceFirst">';
+ html += '<span></span>';
+ html += '</td><td>' + toolbar + '</td></tbody></table>';
$("td.mceToolbar").append(html);
init_buttons(placeholder);
}
@@ -113,7 +113,7 @@
return;
}
// First create db instance using AJAX post back
- add_plugin(pluginvalue, parent_id, language)
+ add_plugin(pluginvalue, parent_id, language);
}).css("cursor", "pointer").css("margin", "5px");
View
2  cms/plugins/text/templates/cms/plugins/widgets/wymeditor.html
@@ -1,5 +1,6 @@
{% load i18n %}
<script type="text/javascript">
+//<![CDATA]
// Global var, for storing callbacks, see below.
var editPluginPopupCallbacks = {};
@@ -111,4 +112,5 @@
+ '</li>';
return html;
}
+//]]>
</script>
View
1  cms/plugins/twitter/templates/cms/plugins/twitter_recent_entries.html
@@ -1,4 +1,5 @@
{% load i18n sekizai_tags %}
+{% addtoblock "js" %}<script type="text/javascript" src="{{ STATIC_URL }}admin/js/jquery.min.js"></script>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{{ STATIC_URL }}cms/js/libs/jquery.tweet.js"></script>{% endaddtoblock %}
{% addtoblock "js" %}
<script type="text/javascript">
View
2  cms/plugins/video/templates/cms/plugins/video.html
@@ -1,4 +1,4 @@
-{% load i18n sekizai_tags js %}
+{% load i18n sekizai_tags cms_js_tags %}
{% addtoblock "js" %}<script type="text/javascript" src="{{ STATIC_URL }}cms/js/libs/swfobject.min.js"></script>{% endaddtoblock %}
{% addtoblock "js" %}
<script type="text/javascript">
View
15 cms/signals.py
@@ -49,12 +49,14 @@ def update_title(title):
if title.page.is_home():
title.path = ''
- else:
+ elif not title.has_url_overwrite:
title.path = u'%s' % slug
- if parent_page_id:
- parent_title = Title.objects.get_title(parent_page_id, language=title.language, language_fallback=True)
- if parent_title:
- title.path = (u'%s/%s' % (parent_title.path, slug)).lstrip("/")
+
+ if parent_page_id:
+ parent_title = Title.objects.get_title(parent_page_id,
+ language=title.language, language_fallback=True)
+ if parent_title:
+ title.path = (u'%s/%s' % (parent_title.path, slug)).lstrip("/")
def pre_save_title(instance, raw, **kwargs):
"""Save old state to instance and setup path
@@ -91,7 +93,8 @@ def post_save_title(instance, raw, created, **kwargs):
page__lft__gt=instance.page.lft,
page__rght__lt=instance.page.rght,
page__tree_id__exact=instance.page.tree_id,
- language=instance.language
+ language=instance.language,
+ has_url_overwrite=False,
).order_by('page__tree_id', 'page__parent', 'page__lft')
for descendant_title in descendant_titles:
View
15 cms/static/cms/css/pages.css
@@ -192,6 +192,21 @@ div#sitemap li, div#sitemap ul{list-style-type: none;}
float:left;
line-height:27px;
margin-right:10px;
+ font-size: 14px;
+}
+
+#sitemap li .move-target-container a:hover {
+ text-decoration: none;
+}
+
+#sitemap li .move-target{
+ display:inline-block;
+ padding: 2px 8px;
+ border-left: 1px solid grey;
+}
+
+#sitemap li .move-target:first-child{
+ border-left:none;
}
#sitemap li .col-softroot,
View
6 cms/static/cms/css/plugins/cms.placeholders.css
@@ -7,6 +7,10 @@
/*##################################################|*/
/* #PLACEHOLDERS# */
+.cms_placeholder { display:-moz-inline-box; -moz-box-orient:vertical; display:inline-block; float:left;
+ vertical-align:middle; *vertical-align:auto; width:100%;
+ clear:both; overflow:hidden; }
+
.cms_placeholder-bar { height:36px; border:1px solid #ddd !important;
background:#fff url('../../images/toolbar/toolbar_bg.gif') repeat-x left bottom; }
@@ -92,4 +96,4 @@
/* #PLACEHOLDERS/IE6# */
*html .cms_placeholder-subnav { width:200px; }
-*html .cms_placeholder-icon { background-image: url('../../images/toolbar/sprite_toolbar-ie.png') !important; }
+*html .cms_placeholder-icon { background-image: url('../../images/toolbar/sprite_toolbar-ie.png') !important; }
View
4 cms/static/cms/css/plugins/cms.toolbar.css
@@ -67,9 +67,9 @@
.cms_toolbar-item_logo .cms_toolbar-item_logo-link:hover { background-position:-120px top; }
/* #TOOLBAR/items/login# */
-#cms_toolbar-item_login label { float:left; cursor:pointer; padding:4px 10px 0 0; }
+#cms_toolbar-item_login label { float:left; cursor:pointer; padding:4px 10px 0 0; width: auto; }
#cms_toolbar-item_login div { float:left; }
-#cms_toolbar-item_login div input { color:#000; width:150px; border:1px solid #ddd; padding:4px 5px; margin-right:10px;
+#cms_toolbar-item_login div input { color:#000; width:150px; border:1px solid #ddd; padding:4px 5px; margin-right:10px; margin-top:0;
-webkit-border-radius:5px; -moz-border-radius:5px; border-radius:5px; }
#cms_toolbar-item_login div input:hover { border:1px solid #999; }
.cms_toolbar_error input[type=text], .cms_toolbar_error input[type=password] { border:1px solid #f99 !important; }
View
851 cms/static/cms/css/toolbar.css
@@ -1,851 +0,0 @@
-/* styles for the frontend editing toolbar */
-
-#cms_toolbar_spacer
-{
- height:41px;
-}
-