def test_edit_bootstrap_row(rf, bootstrap_row): row_plugin, row_model = bootstrap_row request = rf.get('/') ModelForm = row_plugin.get_form(request, row_model) data = {'num_children': 3} form = ModelForm(data, None, instance=row_model) assert form.is_valid() row_plugin.save_model(request, row_model, form, False) container_model, container_plugin = row_model.parent.get_plugin_instance() plugin_list = [container_model, row_model] # we now should have three columns attached to the row assert row_model.get_descendant_count() == 3 for cms_plugin in row_model.get_descendants(): column_model, column_plugin = cms_plugin.get_plugin_instance() assert isinstance(column_model, CascadeElement) assert isinstance(column_plugin, BootstrapColumnPlugin) assert column_model.parent.id == row_model.id plugin_list.append(column_model) # change data inside the first column cms_plugin = row_model.get_descendants().first() column_model, column_plugin = cms_plugin.get_plugin_instance() data = { 'xs-column-width': 'col', 'sm-column-offset': 'offset-sm-1', 'sm-column-width': 'col-sm-3' } ModelForm = column_plugin.get_form(request, column_model) form = ModelForm(data, None, instance=column_model) assert form.is_valid() column_plugin.save_model(request, column_model, form, True) # change data inside the last column cms_plugin = row_model.get_descendants().last() column_model, column_plugin = cms_plugin.get_plugin_instance() data = { 'xs-column-width': 'col', 'sm-responsive-utils': 'hidden-sm', 'sm-column-width': 'col-sm-4' } ModelForm = column_plugin.get_form(request, column_model) form = ModelForm(data, None, instance=column_model) assert form.is_valid() column_plugin.save_model(request, column_model, form, False) # render the plugin and check the output context = { 'request': request, } content_renderer = ContentRenderer(request) row_model.parent.child_plugin_instances for plugin in plugin_list: plugin.refresh_from_db() build_plugin_tree(plugin_list) html = content_renderer.render_plugin(container_model, context) html = strip_spaces_between_tags(html).strip() assert html == '<div class="container"><div class="row"><div class="col col-sm-3 offset-sm-1">' \ '</div><div class="col"></div><div class="col col-sm-4 hidden-sm"></div></div></div>'
def get_form_elements(self): from .utils import get_nested_plugins if self.child_plugin_instances is None: # 3.1 and 3.0 compatibility if CMS_31: # default ordering is by path ordering = ('path', ) else: ordering = ('tree_id', 'level', 'position') descendants = self.get_descendants().order_by(*ordering) # Set parent_id to None in order to # fool the build_plugin_tree function. # This is sadly necessary to avoid getting all nodes # higher than the form. parent_id = self.parent_id self.parent_id = None # Important that this is a list in order to modify # the current instance descendants_with_self = [self] + list(descendants) # Let the cms build the tree build_plugin_tree(descendants_with_self) # Set back the original parent self.parent_id = parent_id if self._form_elements is None: children = get_nested_plugins(self) children_instances = downcast_plugins(children) self._form_elements = [ p for p in children_instances if is_form_element(p) ] return self._form_elements
def get_form_elements(self): from .utils import get_nested_plugins if self.child_plugin_instances is None: # 3.1 and 3.0 compatibility if CMS_31: # default ordering is by path ordering = ('path',) else: ordering = ('tree_id', 'level', 'position') descendants = self.get_descendants().order_by(*ordering) # Set parent_id to None in order to # fool the build_plugin_tree function. # This is sadly necessary to avoid getting all nodes # higher than the form. parent_id = self.parent_id self.parent_id = None # Important that this is a list in order to modify # the current instance descendants_with_self = [self] + list(descendants) # Let the cms build the tree build_plugin_tree(descendants_with_self) # Set back the original parent self.parent_id = parent_id if self._form_elements is None: children = get_nested_plugins(self) children_instances = downcast_plugins(children) self._form_elements = [ p for p in children_instances if is_form_element(p)] return self._form_elements
def test_section(self): heading_model = add_plugin(self.placeholder, HeadingPlugin, 'en', target=self.column_model) self.assertIsInstance(heading_model, CascadeElement) heading_plugin = heading_model.get_plugin_class_instance(self.admin_site) self.assertIsInstance(heading_plugin, HeadingPlugin) ModelForm = heading_plugin.get_form(self.request, heading_model) post_data = QueryDict('', mutable=True) post_data.update(tag_type='h2', content="Hello", element_id='foo') form = ModelForm(post_data, None, instance=heading_model) html = form.as_p() needle = '<input id="id_glossary_element_id" name="element_id" type="text" value="foo" />' self.assertInHTML(needle, html) self.assertTrue(form.is_valid()) heading_plugin.save_model(self.request, heading_model, form, False) # check identifier html = heading_plugin.get_identifier(heading_model) expected = '<code>h2</code>: Hello <code>id="foo"</code>' self.assertHTMLEqual(html, expected) # render the Container Plugin with the Heading Plgin as a child self.plugin_list.append(heading_model) build_plugin_tree(self.plugin_list) # context = get_request_context(self.request) # html = heading_model.render_plugin(context) html = self.get_html(heading_model, self.get_request_context()) expected = '<h2 id="foo">Hello</h2>' self.assertHTMLEqual(html, expected) # add another heading model with the same id heading_model = add_plugin(self.placeholder, HeadingPlugin, 'en', target=self.column_model) form = ModelForm(post_data, None, instance=heading_model) self.assertFalse(form.is_valid()) expected = '<ul class="errorlist"><li>glossary<ul class="errorlist"><li>The element ID 'foo' is not unique for this page.</li></ul></li></ul>' self.assertHTMLEqual(str(form.errors), expected)
def test_edit_accordion_group(rf, admin_site, bootstrap_accordion): request = rf.get('/') accordion_plugin, accordion_model = bootstrap_accordion first_group = accordion_model.get_first_child() group_model, group_plugin = first_group.get_plugin_instance(admin_site) data = {'heading': "Hello", 'body_padding': 'on'} ModelForm = group_plugin.get_form(request, group_model) form = ModelForm(data, None, instance=group_model) assert form.is_valid() group_plugin.save_model(request, group_model, form, False) assert group_model.glossary['heading'] == "Hello" assert group_model.glossary['body_padding'] is True # render the plugin build_plugin_tree([accordion_model, group_model]) context = RequestContext(request) content_renderer = ContentRenderer(request) html = content_renderer.render_plugin(accordion_model, context).strip() html = html.replace('\n', '').replace('\t', '') expected = """<div id="cmsplugin_{accordion_id}" class="accordion"><div class="card"> <div class="card-header" id="heading_{group_id}"><h5 class="mb-0"> <button class="btn btn-link" type="button" data-toggle="collapse" data-target="#collapse_{group_id}" aria-expanded="true" aria-controls="collapse_{group_id}"> Hello</button></h5></div> <div id="collapse_{group_id}" class="collapse" aria-labelledby="heading_{group_id}" data-parent="#cmsplugin_{accordion_id}"> <div class="card-body"></div></div></div></div>""".format( accordion_id=accordion_model.id, group_id=group_model.id) expected = expected.replace('\n', '').replace('\t', '') assert html == expected
def get_form_elements(self): from .utils import get_nested_plugins if self.child_plugin_instances is None: descendants = self.get_descendants().order_by('path') # Set parent_id to None in order to # fool the build_plugin_tree function. # This is sadly necessary to avoid getting all nodes # higher than the form. parent_id = self.parent_id self.parent_id = None # Important that this is a list in order to modify # the current instance descendants_with_self = [self] + list(descendants) # Let the cms build the tree build_plugin_tree(descendants_with_self) # Set back the original parent self.parent_id = parent_id if self._form_elements is None: children = get_nested_plugins(self) children_instances = downcast_plugins(children) self._form_elements = [ p for p in children_instances if is_form_element(p)] return self._form_elements
def test_plugin_context(self): # create container wrapper_model = add_plugin(self.placeholder, SimpleWrapperPlugin, 'en', glossary={'tag_type': 'naked'}) wrapper_plugin = wrapper_model.get_plugin_class_instance(self.admin_site) self.assertIsInstance(wrapper_plugin, SimpleWrapperPlugin) # add an `if`-segment with some text as child if_segment_model = add_plugin(self.placeholder, SegmentPlugin, 'en', target=wrapper_model, glossary={'open_tag': 'if', 'condition': 'user.is_superuser'}) self.assertIsInstance(if_segment_model.get_plugin_class_instance(), SegmentPlugin) text_model_admin = add_plugin(self.placeholder, TextPlugin, 'en', target=if_segment_model, body='<p>User is admin</p>') self.assertIsInstance(text_model_admin.get_plugin_class_instance(), TextPlugin) # add an `elif`-segment with some text as child elif_segment_model = add_plugin(self.placeholder, SegmentPlugin, 'en', target=wrapper_model, glossary={'open_tag': 'elif', 'condition': 'user.is_authenticated'}) self.assertIsInstance(elif_segment_model.get_plugin_class_instance(), SegmentPlugin) text_model_staff = add_plugin(self.placeholder, TextPlugin, 'en', target=elif_segment_model, body='<p>User is staff</p>') self.assertIsInstance(text_model_staff.get_plugin_class_instance(), TextPlugin) # add an `else`-segment with some text as child else_segment_model = add_plugin(self.placeholder, SegmentPlugin, 'en', target=wrapper_model, glossary={'open_tag': 'else'}) self.assertIsInstance(else_segment_model.get_plugin_class_instance(), SegmentPlugin) text_model_anon = add_plugin(self.placeholder, TextPlugin, 'en', target=else_segment_model, body='<p>User is anonymous</p>') self.assertIsInstance(text_model_anon.get_plugin_class_instance(), TextPlugin) # build the DOM plugin_list = [wrapper_model, if_segment_model, text_model_admin, elif_segment_model, text_model_staff, else_segment_model, text_model_anon] build_plugin_tree(plugin_list) # render the plugins as admin user context = get_request_context(self.request) html = wrapper_model.render_plugin(context) soup = BeautifulSoup(html) self.assertHTMLEqual(soup.p.text, 'User is admin') # render the plugins as staff user self.request.user = self.get_staff_user_with_no_permissions() context = get_request_context(self.request) html = wrapper_model.render_plugin(context) soup = BeautifulSoup(html) self.assertHTMLEqual(soup.p.text, 'User is staff') # render the plugins as anonymous user self.request.user = AnonymousUser context = get_request_context(self.request) html = wrapper_model.render_plugin(context) soup = BeautifulSoup(html) self.assertHTMLEqual(soup.p.text, 'User is anonymous')
def test_plugin_context(self): # create container wrapper_model = add_plugin(self.placeholder, SimpleWrapperPlugin, 'en', glossary={'tag_type': 'naked'}) wrapper_plugin = wrapper_model.get_plugin_class_instance(self.admin_site) self.assertIsInstance(wrapper_plugin, SimpleWrapperPlugin) # add an `if`-segment with some text as child if_segment_model = add_plugin(self.placeholder, SegmentPlugin, 'en', target=wrapper_model, glossary={'open_tag': 'if', 'condition': 'user.is_superuser'}) self.assertIsInstance(if_segment_model.get_plugin_class_instance(), SegmentPlugin) text_model_admin = add_plugin(self.placeholder, TextPlugin, 'en', target=if_segment_model, body='<p>User is admin</p>') self.assertIsInstance(text_model_admin.get_plugin_class_instance(), TextPlugin) # add an `elif`-segment with some text as child elif_segment_model = add_plugin(self.placeholder, SegmentPlugin, 'en', target=wrapper_model, glossary={'open_tag': 'elif', 'condition': 'user.is_authenticated'}) self.assertIsInstance(elif_segment_model.get_plugin_class_instance(), SegmentPlugin) text_model_staff = add_plugin(self.placeholder, TextPlugin, 'en', target=elif_segment_model, body='<p>User is staff</p>') self.assertIsInstance(text_model_staff.get_plugin_class_instance(), TextPlugin) # add an `else`-segment with some text as child else_segment_model = add_plugin(self.placeholder, SegmentPlugin, 'en', target=wrapper_model, glossary={'open_tag': 'else'}) self.assertIsInstance(else_segment_model.get_plugin_class_instance(), SegmentPlugin) text_model_anon = add_plugin(self.placeholder, TextPlugin, 'en', target=else_segment_model, body='<p>User is anonymous</p>') self.assertIsInstance(text_model_anon.get_plugin_class_instance(), TextPlugin) # build the DOM plugin_list = [wrapper_model, if_segment_model, text_model_admin, elif_segment_model, text_model_staff, else_segment_model, text_model_anon] build_plugin_tree(plugin_list) # render the plugins as admin user soup = BeautifulSoup(self.get_html(wrapper_model, self.get_request_context()), 'html.parser') self.assertHTMLEqual(soup.p.text, 'User is admin') # render the plugins as staff user self.request.user = self.staff_user soup = BeautifulSoup(self.get_html(wrapper_model, self.get_request_context()), 'html.parser') self.assertHTMLEqual(soup.p.text, 'User is staff') # render the plugins as anonymous user self.request.user = AnonymousUser soup = BeautifulSoup(self.get_html(wrapper_model, self.get_request_context()), 'html.parser') self.assertHTMLEqual(soup.p.text, 'User is anonymous')
def render(self, context, instance, placeholder): from cms.utils.plugins import downcast_plugins, build_plugin_tree context = super(AliasPlugin, self).render(context, instance, placeholder) request = context.get('request') if not request or instance.is_recursive(): return context if instance.plugin_id: plugins = instance.plugin.get_descendants().order_by('placeholder', 'path') plugins = [instance.plugin] + list(plugins) plugins = downcast_plugins(plugins, request=request) plugins = list(plugins) plugins[0].parent_id = None plugins = build_plugin_tree(plugins) context['plugins'] = plugins if instance.alias_placeholder_id: toolbar = get_toolbar_from_request(request) renderer = toolbar.content_renderer content = renderer.render_placeholder( placeholder=instance.alias_placeholder, context=context, editable=False, ) context['content'] = mark_safe(content) return context
def get_children(self, obj): """ Some plugins can contain children This method supposed to get children and prepare and return together with parent object :param obj: :return: """ data = [] plugin = obj.get_plugin_class() if not (getattr(plugin, 'allow_children', False) and getattr(plugin, 'child_classes', None)): return data children = obj.get_descendants().order_by('placeholder', 'path') children = [obj] + list(children) children = list(downcast_plugins(children)) children[0].parent_id = None children = list(build_plugin_tree(children)) def get_plugin_data(child_plugin): serializer = get_serializer(child_plugin, model=child_plugin._meta.model, context=self.context) plugin_data = serializer.data plugin_data['inlines'] = self.get_inlines(child_plugin) if child_plugin.child_plugin_instances: plugin_data['children'] = [] for plug in child_plugin.child_plugin_instances: plugin_data['children'].append(get_plugin_data(plug)) return plugin_data for child in children[0].child_plugin_instances or []: data.append(get_plugin_data(child)) return data
def render(self, context, instance, placeholder): from cms.utils.plugins import downcast_plugins, build_plugin_tree context = super(AliasPlugin, self).render(context, instance, placeholder) cms_content_renderer = context.get('cms_content_renderer') if not cms_content_renderer or instance.is_recursive(): return context if instance.plugin_id: plugins = instance.plugin.get_descendants().order_by('placeholder', 'path') plugins = [instance.plugin] + list(plugins) plugins = downcast_plugins(plugins, request=cms_content_renderer.request) plugins = list(plugins) plugins[0].parent_id = None plugins = build_plugin_tree(plugins) context['plugins'] = plugins if instance.alias_placeholder_id: content = cms_content_renderer.render_placeholder( placeholder=instance.alias_placeholder, context=context, editable=False, ) context['content'] = mark_safe(content) return context
def _render_plugins(self, plugins, context): for plg in plugins: inst, name = plg.get_plugin_instance() if inst is None: # Ghost plugin continue # Get child plugins for this plugin instance, if any child plugins # exist try: # django CMS 3- plugins = ( inst .get_descendants(include_self=True) .order_by('placeholder', 'tree_id', 'level', 'position') ) except (FieldError, TypeError): # django CMS 3.1+ plugins = inst.get_descendants().order_by('path') plugins = [inst] + list(plugins) plugin_tree = downcast_plugins(plugins, select_placeholder=True) plugin_tree = list(plugin_tree) plugin_tree[0].parent_id = None plugin_tree = build_plugin_tree(plugin_tree) # Replace plugin instance with plugin instance with correct # child_plugin_instances set yield self._render_plugin(plugin_tree[0], context)
def get_children(self, obj): """ Some plugins can contain children This method supposed to get children and prepare and return together with parent object :param obj: :return: """ data = [] plugin = obj.get_plugin_class() if not(getattr(plugin, 'allow_children', False) and getattr(plugin, 'child_classes', None)): return data children = obj.get_descendants().order_by('placeholder', 'path') children = [obj] + list(children) children = list(downcast_plugins(children)) children[0].parent_id = None children = list(build_plugin_tree(children)) def get_plugin_data(child_plugin): serializer = get_serializer(child_plugin, model=child_plugin._meta.model, context=self.context) plugin_data = serializer.data plugin_data['inlines'] = self.get_inlines(child_plugin) if child_plugin.child_plugin_instances: plugin_data['children'] = [] for plug in child_plugin.child_plugin_instances: plugin_data['children'].append(get_plugin_data(plug)) return plugin_data for child in children[0].child_plugin_instances or []: data.append(get_plugin_data(child)) return data
def render_alias_plugin(context, instance): renderer = context.get('cms_content_renderer') if instance.plugin: plugins = instance.plugin.get_descendants().order_by( 'placeholder', 'path') plugins = [instance.plugin] + list(plugins) plugins = downcast_plugins(plugins, request=renderer.request) plugins = list(plugins) plugins[0].parent_id = None plugins = build_plugin_tree(plugins) content = renderer.render_plugin( instance=plugins[0], context=context, editable=False, ) return mark_safe(content) if instance.alias_placeholder: content = renderer.render_placeholder( placeholder=instance.alias_placeholder, context=context, editable=False, ) return mark_safe(content) return ''
def render(self, context, instance, placeholder): template_vars = { 'object': instance, 'placeholder': placeholder, } lang = instance.from_language request = context.get('request', None) if not lang: if 'request' in context: lang = get_language_from_request(request) else: lang = settings.LANGUAGE_CODE page = instance.placeholder.page from_page = instance.from_page if page.publisher_is_draft: from_page = from_page.get_draft_object() else: from_page = from_page.get_public_object() plugins = get_cmsplugin_queryset(request).filter( placeholder__page=from_page, language=lang, placeholder__slot__iexact=placeholder, parent__isnull=True).order_by('position').select_related() plugin_output = [] template_vars['parent_plugins'] = plugins for plg in plugins: tmpctx = copy.copy(context) tmpctx.update(template_vars) inst, name = plg.get_plugin_instance() if inst is None: continue # Get child plugins for this plugin instance, if any child plugins # exist try: # django CMS 3- plugins = [inst] + list( inst.get_descendants(include_self=True).order_by( 'placeholder', 'tree_id', 'level', 'position')) except (FieldError, TypeError): # django CMS 3.1+ plugins = [inst] + list( inst.get_descendants().order_by('path')) plugin_tree = downcast_plugins(plugins) plugin_tree[0].parent_id = None plugin_tree = build_plugin_tree(plugin_tree) # Replace plugin instance with plugin instance with correct # child_plugin_instances set inst = plugin_tree[0] outstr = inst.render_plugin(tmpctx, placeholder) plugin_output.append(outstr) template_vars['parent_output'] = plugin_output context.update(template_vars) return context
def render(self, context, instance, placeholder): template_vars = { 'object': instance, 'placeholder': placeholder, } lang = instance.from_language request = context.get('request', None) if not lang: if 'request' in context: lang = get_language_from_request(request) else: lang = settings.LANGUAGE_CODE page = instance.placeholder.page from_page = instance.from_page if page.publisher_is_draft: from_page = from_page.get_draft_object() else: from_page = from_page.get_public_object() plugins = get_cmsplugin_queryset(request).filter( placeholder__page=from_page, language=lang, placeholder__slot__iexact=placeholder, parent__isnull=True ).order_by('position').select_related() plugin_output = [] template_vars['parent_plugins'] = plugins for plg in plugins: tmpctx = copy.copy(context) tmpctx.update(template_vars) inst, name = plg.get_plugin_instance() if inst is None: continue # Get child plugins for this plugin instance, if any child plugins # exist try: # django CMS 3- plugins = [inst] + list(inst.get_descendants(include_self=True) .order_by('placeholder', 'tree_id', 'level', 'position')) except (FieldError, TypeError): # django CMS 3.1+ plugins = [inst] + list(inst.get_descendants().order_by('path')) plugin_tree = downcast_plugins(plugins) plugin_tree[0].parent_id = None plugin_tree = build_plugin_tree(plugin_tree) # Replace plugin instance with plugin instance with correct # child_plugin_instances set inst = plugin_tree[0] outstr = inst.render_plugin(tmpctx, placeholder) plugin_output.append(outstr) template_vars['parent_output'] = plugin_output context.update(template_vars) return context
def test_section(self): heading_model = add_plugin(self.placeholder, HeadingPlugin, 'en', target=self.column_model) self.assertIsInstance(heading_model, CascadeElement) heading_plugin = heading_model.get_plugin_class_instance( self.admin_site) self.assertIsInstance(heading_plugin, HeadingPlugin) ModelForm = heading_plugin.get_form(self.request, heading_model) post_data = QueryDict('', mutable=True) post_data.update(tag_type='h2', content="Hello", element_id='foo') form = ModelForm(post_data, None, instance=heading_model) html = form.as_p() needle = '<input id="id_glossary_element_id" name="element_id" type="text" value="foo" />' self.assertInHTML(needle, html) self.assertTrue(form.is_valid()) heading_plugin.save_model(self.request, heading_model, form, False) # check identifier html = heading_plugin.get_identifier(heading_model) expected = '<code>h2</code>: Hello <code>id="foo"</code>' self.assertHTMLEqual(html, expected) # render the Container Plugin with the Heading Plgin as a child self.plugin_list.append(heading_model) build_plugin_tree(self.plugin_list) # context = get_request_context(self.request) # html = heading_model.render_plugin(context) html = self.get_html(heading_model, self.get_request_context()) expected = '<h2 id="foo">Hello</h2>' self.assertHTMLEqual(html, expected) # add another heading model with the same id heading_model = add_plugin(self.placeholder, HeadingPlugin, 'en', target=self.column_model) form = ModelForm(post_data, None, instance=heading_model) self.assertFalse(form.is_valid()) expected = '<ul class="errorlist"><li>glossary<ul class="errorlist"><li>The element ID `foo` is not unique for this page.</li></ul></li></ul>' print(str(form.errors)) self.assertHTMLEqual(str(form.errors), expected)
def build_accordion_plugins(self): # create container container_model = add_plugin(self.placeholder, BootstrapContainerPlugin, 'en', glossary={'breakpoints': BS3_BREAKPOINT_KEYS}) container_plugin = container_model.get_plugin_class_instance(self.admin_site) self.assertIsInstance(container_plugin, BootstrapContainerPlugin) # add one row row_model = add_plugin(self.placeholder, BootstrapRowPlugin, 'en', target=container_model, glossary={}) row_plugin = row_model.get_plugin_class_instance() self.assertIsInstance(row_plugin, BootstrapRowPlugin) # add one column column_model = add_plugin(self.placeholder, BootstrapColumnPlugin, 'en', target=row_model, glossary={'xs-column-width': 'col-xs-12', 'sm-column-width': 'col-sm-6', 'md-column-width': 'col-md-4', 'lg-column-width': 'col-lg-3'}) column_plugin = column_model.get_plugin_class_instance() self.assertIsInstance(column_plugin, BootstrapColumnPlugin) # add accordion plugin accordion_model = add_plugin(self.placeholder, BootstrapAccordionPlugin, 'en', target=column_model) accordion_plugin = accordion_model.get_plugin_class_instance(self.admin_site) self.assertIsInstance(accordion_plugin, BootstrapAccordionPlugin) accordion_plugin.cms_plugin_instance = accordion_model.cmsplugin_ptr # add accordion panel panel_model = add_plugin(self.placeholder, BootstrapAccordionPanelPlugin, 'en', target=accordion_model, glossary={'panel_type': "panel-danger", 'panel_title': "Foo"}) panel_plugin = panel_model.get_plugin_class_instance(self.admin_site) self.assertIsInstance(panel_plugin, BootstrapAccordionPanelPlugin) panel_plugin.cms_plugin_instance = panel_model.cmsplugin_ptr # render the plugins plugin_list = [container_model, row_model, column_model, accordion_model, panel_model] build_plugin_tree(plugin_list) context = get_request_context(self.request) self.assertEqual(accordion_plugin.get_identifier(accordion_model), 'with 1 panel') self.assertEqual(panel_plugin.get_identifier(panel_model), 'Foo') return container_model.render_plugin(context)
def build_accordion_plugins(self): # create container container_model = add_plugin(self.placeholder, BootstrapContainerPlugin, 'en', glossary={'breakpoints': BS3_BREAKPOINT_KEYS}) container_plugin = container_model.get_plugin_class_instance() self.assertIsInstance(container_plugin, BootstrapContainerPlugin) # add one row row_model = add_plugin(self.placeholder, BootstrapRowPlugin, 'en', target=container_model, glossary={}) row_plugin = row_model.get_plugin_class_instance() self.assertIsInstance(row_plugin, BootstrapRowPlugin) # add one column column_model = add_plugin(self.placeholder, BootstrapColumnPlugin, 'en', target=row_model, glossary={'xs-column-width': 'col-xs-12', 'sm-column-width': 'col-sm-6', 'md-column-width': 'col-md-4', 'lg-column-width': 'col-lg-3'}) column_plugin = column_model.get_plugin_class_instance() self.assertIsInstance(column_plugin, BootstrapColumnPlugin) # add accordion plugin accordion_model = add_plugin(self.placeholder, BootstrapAccordionPlugin, 'en', target=column_model) accordion_plugin = accordion_model.get_plugin_class_instance() self.assertIsInstance(accordion_plugin, BootstrapAccordionPlugin) accordion_plugin.cms_plugin_instance = accordion_model.cmsplugin_ptr # add accordion panel panel_model = add_plugin(self.placeholder, BootstrapAccordionPanelPlugin, 'en', target=accordion_model, glossary={'panel_type': "panel-danger", 'panel_title': "Foo"}) panel_plugin = panel_model.get_plugin_class_instance() self.assertIsInstance(panel_plugin, BootstrapAccordionPanelPlugin) panel_plugin.cms_plugin_instance = panel_model.cmsplugin_ptr # render the plugins plugin_list = [container_model, row_model, column_model, accordion_model, panel_model] build_plugin_tree(plugin_list) self.assertEqual(accordion_plugin.get_identifier(accordion_model), 'with 1 panel') self.assertEqual(panel_plugin.get_identifier(panel_model), 'Foo') return self.get_html(container_model, self.get_request_context())
def get_plugin_tree_as_json(request, plugins): from cms.utils.plugins import ( build_plugin_tree, downcast_plugins, get_plugin_restrictions, ) tree_data = [] tree_structure = [] restrictions = {} toolbar = get_toolbar_from_request(request) template = toolbar.templates.drag_item_template placeholder = plugins[0].placeholder host_page = placeholder.page copy_to_clipboard = placeholder.pk == toolbar.clipboard.pk plugins = downcast_plugins(plugins, select_placeholder=True) plugin_tree = build_plugin_tree(plugins) get_plugin_info = get_plugin_toolbar_info def collect_plugin_data(plugin): child_classes, parent_classes = get_plugin_restrictions( plugin=plugin, page=host_page, restrictions_cache=restrictions, ) plugin_info = get_plugin_info( plugin, children=child_classes, parents=parent_classes, ) tree_data.append(plugin_info) for plugin in plugin.child_plugin_instances or []: collect_plugin_data(plugin) with force_language(toolbar.toolbar_language): for root_plugin in plugin_tree: collect_plugin_data(root_plugin) context = { 'plugin': root_plugin, 'request': request, 'clipboard': copy_to_clipboard, 'cms_toolbar': toolbar, } tree_structure.append(template.render(context)) tree_data.reverse() return json.dumps({ 'html': '\n'.join(tree_structure), 'plugins': tree_data })
def render(self, context, instance, placeholder): context['instance'] = instance context['placeholder'] = placeholder if instance.plugin_id: plugins = instance.plugin.get_descendants(include_self=True).order_by('placeholder', 'tree_id', 'level', 'position') plugins = downcast_plugins(plugins) plugins[0].parent_id = None plugins = build_plugin_tree(plugins) context['plugins'] = plugins if instance.alias_placeholder_id: content = render_placeholder(instance.alias_placeholder, context) context['content'] = mark_safe(content) return context
def render(self, context, instance, placeholder): context['instance'] = instance context['placeholder'] = placeholder if instance.plugin_id: plugins = instance.plugin.get_descendants().order_by('placeholder', 'path') plugins = [instance.plugin] + list(plugins) plugins = downcast_plugins(plugins) plugins[0].parent_id = None plugins = build_plugin_tree(plugins) context['plugins'] = plugins if instance.alias_placeholder_id: content = render_placeholder(instance.alias_placeholder, context) context['content'] = mark_safe(content) return context
def render(self, context, instance, placeholder): from cms.utils.plugins import downcast_plugins, build_plugin_tree context['instance'] = instance context['placeholder'] = placeholder if instance.plugin_id: plugins = instance.plugin.get_descendants().order_by( 'placeholder', 'path') plugins = [instance.plugin] + list(plugins) plugins = downcast_plugins(plugins) plugins[0].parent_id = None plugins = build_plugin_tree(plugins) context['plugins'] = plugins if instance.alias_placeholder_id: content = render_placeholder(instance.alias_placeholder, context) context['content'] = mark_safe(content) return context
def get_plugin_tree(model, **kwargs): """ Plugins in django CMS are highly related to a placeholder. This function builds a plugin tree for a plugin with no placeholder context. Makes as many database queries as many levels are in the tree. This is ok as forms shouldn't form very deep trees. """ plugin = model.objects.get(**kwargs) plugin.parent = None current_level = [plugin] plugin_list = [plugin] while get_next_level(current_level).exists(): current_level = get_next_level(current_level) current_level = downcast_plugins(queryset=current_level) plugin_list += current_level return build_plugin_tree(plugin_list)[0]
def render_plugin(request, plugin_id, template_name='responsive_wrapper/render_plugin.html'): try: instance = CMSPlugin.objects.get(pk=hashid_to_int(plugin_id)) except CMSPlugin.DoesNotExist: msg = _('Plugin not found.') return HttpResponseNotFound(force_text(msg)) try: # django CMS 3- descendants = instance.get_descendants(include_self=True) \ .order_by('placeholder', 'tree_id', 'level', 'position') except (FieldError, TypeError): # django CMS 3.1+ descendants = instance.get_descendants().order_by('path') plugins = [instance] + list(descendants) plugins = downcast_plugins(plugins) plugins[0].parent_id = None plugins = build_plugin_tree(plugins) context = RequestContext(request) context['plugins'] = plugins return render_to_response(template_name, {}, context)
def render_alias_plugin(context, instance): request = context['request'] toolbar = get_toolbar_from_request(request) renderer = toolbar.content_renderer source = (instance.plugin or instance.alias_placeholder) # In edit mode, content is shown regardless of the source page publish status. # In published mode, content is shown only if the source page is published. if not (toolbar.edit_mode_active) and source and source.page: # this is bad but showing unpublished content is worse can_see_content = source.page.is_published(instance.language) else: can_see_content = True if can_see_content and instance.plugin: plugins = instance.plugin.get_descendants().order_by( 'placeholder', 'path') plugins = [instance.plugin] + list(plugins) plugins = downcast_plugins(plugins, request=request) plugins = list(plugins) plugins[0].parent_id = None plugins = build_plugin_tree(plugins) content = renderer.render_plugin( instance=plugins[0], context=context, editable=False, ) return mark_safe(content) if can_see_content and instance.alias_placeholder: content = renderer.render_placeholder( placeholder=instance.alias_placeholder, context=context, editable=False, ) return mark_safe(content) return ''
def test_jumbotron_plugin(self): # create container container_model = add_plugin(self.placeholder, BootstrapContainerPlugin, 'en', glossary={'breakpoints': BS3_BREAKPOINT_KEYS}) container_plugin = container_model.get_plugin_class_instance(self.admin_site) self.assertIsInstance(container_plugin, BootstrapContainerPlugin) # add one row row_model = add_plugin(self.placeholder, BootstrapRowPlugin, 'en', target=container_model, glossary={}) row_plugin = row_model.get_plugin_class_instance() self.assertIsInstance(row_plugin, BootstrapRowPlugin) # add one column column_model = add_plugin(self.placeholder, BootstrapColumnPlugin, 'en', target=row_model, glossary={'xs-column-width': 'col-xs-12', 'sm-column-width': 'col-sm-6', 'md-column-width': 'col-md-4', 'lg-column-width': 'col-lg-3'}) column_plugin = column_model.get_plugin_class_instance() self.assertIsInstance(column_plugin, BootstrapColumnPlugin) # add Jumbotron plugin jumbotron_model = add_plugin(self.placeholder, BootstrapJumbotronPlugin, 'en', target=column_model) self.assertIsInstance(jumbotron_model, ImagePropertyMixin) self.assertIsInstance(jumbotron_model, ImageBackgroundMixin) jumbotron_plugin = jumbotron_model.get_plugin_class_instance(self.admin_site) self.assertIsInstance(jumbotron_plugin, BootstrapJumbotronPlugin) jumbotron_plugin.cms_plugin_instance = jumbotron_model.cmsplugin_ptr # edit jumbotron model post_data = QueryDict('', mutable=True) post_data.update({ 'background-size': 'auto', 'background-repeat': 'no-repeat', 'background-width-height-width': '', 'background-attachment': 'fixed', 'background-color_color': '#aabbcc', 'background-color_disabled': '', 'background-vertical-position': 'center', 'background-horizontal-position': 'center', 'breakpoints': ['xs', 'sm', 'md', 'lg'], 'extra_inline_styles:Paddings-padding-bottom': '', 'background-width-height-height': '', 'container_max_heights-xs': '100%', 'container_max_heights-sm': '100%', 'container_max_heights-md': '100%', 'container_max_heights-lg': '100%', 'extra_inline_styles:Paddings-padding-top': '200px', 'resize-options': ['crop', 'subject_location', 'high_resolution'], 'image_file': str(self.image.pk), }) ModelForm = jumbotron_plugin.get_form(self.request, jumbotron_model) form = ModelForm(post_data, None, instance=jumbotron_model) self.assertTrue(form.is_valid()) jumbotron_plugin.save_model(self.request, jumbotron_model, form, False) del jumbotron_model._image_model # invalidate cache self.assertEqual(jumbotron_plugin.get_identifier(jumbotron_model), 'Demo Image') # render the plugins plugin_list = [container_model, row_model, column_model, jumbotron_model] build_plugin_tree(plugin_list) context = get_request_context(self.request) html = container_model.render_plugin(context) print(html) self.assertHTMLEqual(""" <div class="container"><div class="row"><div class="col-xs-12 col-sm-6 col-md-4 col-lg-3"> <div id="cascadeelement_id-{}" class="jumbotron"></div> </div></div></div>""".format(jumbotron_model.pk), html) self.assertEqual('background-color: #aabbcc;', jumbotron_model.background_color) self.assertEqual('background-position: center center;', jumbotron_model.background_position) self.assertEqual('background-repeat: no-repeat;', jumbotron_model.background_repeat) self.assertEqual('background-attachment: fixed;', jumbotron_model.background_attachment) self.assertEqual('background-size: auto;', jumbotron_model.background_size)
def test_plugin_context(self): # create container container_model = add_plugin( self.placeholder, BootstrapContainerPlugin, 'en', glossary={'breakpoints': CASCADE_BREAKPOINTS_LIST}) container_plugin = container_model.get_plugin_class_instance( self.admin_site) self.assertIsInstance(container_plugin, BootstrapContainerPlugin) # add one row row_model = add_plugin(self.placeholder, BootstrapRowPlugin, 'en', target=container_model, glossary={}) row_plugin = row_model.get_plugin_class_instance() self.assertIsInstance(row_plugin, BootstrapRowPlugin) # add one column column_model = add_plugin(self.placeholder, BootstrapColumnPlugin, 'en', target=row_model, glossary={ 'xs-column-width': 'col-xs-12', 'sm-column-width': 'col-sm-6', 'md-column-width': 'col-md-4', 'lg-column-width': 'col-lg-3' }) column_plugin = column_model.get_plugin_class_instance() self.assertIsInstance(column_plugin, BootstrapColumnPlugin) # add an image image_model = add_plugin(self.placeholder, BootstrapImagePlugin, 'en', target=column_model) self.assertIsInstance(image_model, SharableCascadeElement) image_plugin = image_model.get_plugin_class_instance(self.admin_site) self.assertIsInstance(image_plugin, BootstrapImagePlugin) image_plugin.cms_plugin_instance = image_model.cmsplugin_ptr # upload an image and change the form ModelForm = image_plugin.get_form(self.request, image_model) image = self.upload_demo_image() post_data = QueryDict('', mutable=True) post_data.update({ 'image_file': image.pk, 'link_type': 'none', 'image-width-fixed': '300px' }) image_model._image_model = image form = ModelForm(post_data, None, instance=image_model) self.assertTrue(form.is_valid()) image_plugin.save_model(self.request, image_model, form, False) # render the plugins plugin_list = [container_model, row_model, column_model, image_model] build_plugin_tree(plugin_list) context = get_request_context(self.request) html = container_model.render_plugin(context) soup = BeautifulSoup(html) self.assertEqual(soup.img['height'], '100') self.assertEqual(soup.img['width'], '300') self.assertTrue( 'demo_image.png__300x100_q85_subsampling-2' in str(soup.img)) # use a responsive image post_data.setlist('image-shapes', ['img-responsive']) form = ModelForm(post_data, None, instance=image_model) self.assertTrue(form.is_valid()) image_plugin.save_model(self.request, image_model, form, False) html = container_model.render_plugin(context) soup = BeautifulSoup(html) self.assertTrue('img-responsive' in soup.img['class']) sizes = [s.strip() for s in soup.img['sizes'].split(',')] self.assertTrue('(max-width: 768px) 720px' in sizes) self.assertTrue( '(min-width: 768px) and (max-width: 992px) 345px' in sizes) self.assertTrue( '(min-width: 992px) and (max-width: 1200px) 293px' in sizes) self.assertTrue('(min-width: 1200px) 262px' in sizes) srcsets = [s.strip() for s in soup.img['srcset'].split(',')] self.assertEqual( len([ s for s in srcsets if s.endswith( 'demo_image.png__293x98_q85_subsampling-2.jpg 293w') ]), 1) self.assertEqual( len([ s for s in srcsets if s.endswith( 'demo_image.png__720x240_q85_subsampling-2.jpg 720w') ]), 1) self.assertEqual( len([ s for s in srcsets if s.endswith( 'demo_image.png__345x115_q85_subsampling-2.jpg 345w') ]), 1) self.assertEqual( len([ s for s in srcsets if s.endswith( 'demo_image.png__262x87_q85_subsampling-2.jpg 262w') ]), 1) self.assertTrue(soup.img['src'].endswith( 'demo_image.png__720x240_q85_subsampling-2.jpg'))
def test_jumbotron_plugin(self): # create container container_model = add_plugin(self.placeholder, BootstrapContainerPlugin, 'en', glossary={'breakpoints': BS3_BREAKPOINT_KEYS}) container_plugin = container_model.get_plugin_class_instance(self.admin_site) self.assertIsInstance(container_plugin, BootstrapContainerPlugin) # add one row row_model = add_plugin(self.placeholder, BootstrapRowPlugin, 'en', target=container_model, glossary={}) row_plugin = row_model.get_plugin_class_instance() self.assertIsInstance(row_plugin, BootstrapRowPlugin) # add one column column_model = add_plugin(self.placeholder, BootstrapColumnPlugin, 'en', target=row_model, glossary={'xs-column-width': 'col-xs-12', 'sm-column-width': 'col-sm-6', 'md-column-width': 'col-md-4', 'lg-column-width': 'col-lg-3'}) column_plugin = column_model.get_plugin_class_instance() self.assertIsInstance(column_plugin, BootstrapColumnPlugin) # add Jumbotron plugin jumbotron_model = add_plugin(self.placeholder, BootstrapJumbotronPlugin, 'en', target=column_model) self.assertIsInstance(jumbotron_model, ImagePropertyMixin) self.assertIsInstance(jumbotron_model, ImageBackgroundMixin) jumbotron_plugin = jumbotron_model.get_plugin_class_instance(self.admin_site) self.assertIsInstance(jumbotron_plugin, BootstrapJumbotronPlugin) jumbotron_plugin.cms_plugin_instance = jumbotron_model.cmsplugin_ptr # edit jumbotron model post_data = QueryDict('', mutable=True) post_data.update({ 'background_size': 'auto', 'background_repeat': 'no-repeat', 'background_width-height-width': '', 'background_attachment': 'fixed', 'background_color_color': '#aabbcc', 'background_color_disabled': '', 'background_vertical_position': 'center', 'background_horizontal_position': 'center', 'breakpoints': ['xs', 'sm', 'md', 'lg'], 'extra_inline_styles:Paddings-padding-bottom': '', 'background-width-height-height': '', 'container_max_heights-xs': '100%', 'container_max_heights-sm': '100%', 'container_max_heights-md': '100%', 'container_max_heights-lg': '100%', 'extra_inline_styles:Paddings-padding-top': '200px', 'resize_options': ['crop', 'subject_location', 'high_resolution'], 'image_file': str(self.image.pk), }) ModelForm = jumbotron_plugin.get_form(self.request, jumbotron_model) form = ModelForm(post_data, None, instance=jumbotron_model) self.assertTrue(form.is_valid()) jumbotron_plugin.save_model(self.request, jumbotron_model, form, False) del jumbotron_model._image_model # invalidate cache self.assertEqual(jumbotron_plugin.get_identifier(jumbotron_model), 'Demo Image') # render the plugins plugin_list = [container_model, row_model, column_model, jumbotron_model] build_plugin_tree(plugin_list) html = self.get_html(container_model, self.get_request_context()) # print(html) self.assertHTMLEqual(""" <div class="container"><div class="row"><div class="col-xs-12 col-sm-6 col-md-4 col-lg-3"> <div id="cascadeelement_id-{}" class="jumbotron"></div> </div></div></div>""".format(jumbotron_model.pk), html) self.assertEqual('background-color: #aabbcc;', jumbotron_model.background_color) self.assertEqual('background-position: center center;', jumbotron_model.background_position) self.assertEqual('background-repeat: no-repeat;', jumbotron_model.background_repeat) self.assertEqual('background-attachment: fixed;', jumbotron_model.background_attachment) self.assertEqual('background-size: auto;', jumbotron_model.background_size)
def test_add_font(self): with self.login_user_context(self.admin_user): # upload the zipfile into the filer's clipboard filename = os.path.join(os.path.dirname(__file__), 'assets/fontello-b504201f.zip') with open(filename, 'rb') as zipfile: uploaded_file = SimpleUploadedFile('fontello-b504201f.zip', zipfile.read(), content_type='application/zip') request = self.get_request(reverse('admin:filer-ajax_upload')) self.assertTrue(request.user.is_staff, "User is not a staff user") request.FILES.update(file=uploaded_file) response = ajax_upload(request) self.assertEqual(response.status_code, 200) content = json.loads(response.content.decode('utf-8')) self.assertDictContainsSubset({'label': 'fontello-b504201f.zip'}, content) # save the form and submit the remaining fields add_iconfont_url = reverse('admin:cmsplugin_cascade_iconfont_add') data = { 'identifier': "Fontellico", 'zip_file': content['file_id'], '_continue': "Save and continue editing", } response = self.client.post(add_iconfont_url, data) self.assertEqual(response.status_code, 302) resolver_match = resolve(response.url) self.assertEqual(resolver_match.url_name, 'cmsplugin_cascade_iconfont_change') # check the content of the uploaded file icon_font = IconFont.objects.get(pk=resolver_match.args[0]) self.assertEqual(icon_font.identifier, "Fontellico") self.assertEqual(icon_font.config_data['name'], 'fontelico') self.assertEqual(len(icon_font.config_data['glyphs']), 34) # check if the uploaded fonts are rendered inside Preview Icons response = self.client.get(response.url) self.assertEqual(response.status_code, 200) soup = BeautifulSoup(response.content, 'lxml') preview_iconfont = soup.find('div', class_="preview-iconfont") icon_items = preview_iconfont.ul.find_all('li') self.assertEqual(len(icon_items), 34) self.assertListEqual(icon_items[0].i.attrs['class'], ['icon-emo-happy']) self.assertListEqual(icon_items[33].i.attrs['class'], ['icon-marquee']) # select icon font from toolbar self.placeholder.page.cascadepage.icon_font = icon_font self.placeholder.page.cascadepage.save() # create container container_model = add_plugin(self.placeholder, BootstrapContainerPlugin, 'en', glossary={'breakpoints': BS3_BREAKPOINT_KEYS}) container_plugin = container_model.get_plugin_class_instance() self.assertIsInstance(container_plugin, BootstrapContainerPlugin) # add icon as child to this container glossary = {"font_size": "10em", "color": ["","#88258e"], "background_color": ["on","#c8ffcd"], "symbol": "emo-wink", "icon_font": icon_font.pk, "border_radius":"50%","border":["","solid","#000000"]} icon_model = add_plugin(self.placeholder, FramedIconPlugin, 'en', target=container_model, glossary=glossary) icon_plugin = icon_model.get_plugin_class_instance() self.assertIsInstance(icon_plugin, FramedIconPlugin) # render the plugins plugin_list = [container_model, icon_model] build_plugin_tree(plugin_list) html = self.get_html(container_model, self.get_request_context()) soup = BeautifulSoup(html, 'lxml') # look for the icon symbol style = soup.find('span', class_='icon-emo-wink').attrs['style'].split(';') self.assertIn('color:#88258e', style) self.assertIn('display:inline-block', style) # look for the CSS file response = self.client.get(container_model.placeholder.page.get_absolute_url() + '?edit') self.assertEqual(response.status_code, 200) soup = BeautifulSoup(response.content, 'lxml') links = soup.head.find_all('link') for link in links: if link.attrs['href'].endswith('fontelico.css'): break else: self.fail("No CSS file with font definition found")
def test_container_context(self): # add a Bootstrap Container Plugin container_model = add_plugin( self.placeholder, BootstrapContainerPlugin, 'en', glossary={'breakpoints': BS3_BREAKPOINT_KEYS}) self.assertIsInstance(container_model, CascadeElement) container_plugin = container_model.get_plugin_class_instance( self.admin_site) self.assertIsInstance(container_plugin, BootstrapContainerPlugin) ModelForm = container_plugin.get_form(self.request, container_model) post_data = QueryDict('', mutable=True) post_data.setlist('breakpoints', ['sm', 'md']) form = ModelForm(post_data, None, instance=container_model) html = form.as_p() self.assertInHTML( '<input id="id_glossary_breakpoints_0" name="breakpoints" type="checkbox" value="xs" />', html) self.assertInHTML( '<input checked="checked" id="id_glossary_breakpoints_2" name="breakpoints" type="checkbox" value="md" />', html) self.assertInHTML( '<input id="id_glossary_fluid" name="fluid" type="checkbox" />', html) container_plugin.save_model(self.request, container_model, form, False) self.assertListEqual(container_model.glossary['breakpoints'], ['sm', 'md']) self.assertTrue('fluid' in container_model.glossary) self.assertEqual(str(container_model), 'for tablets, laptops') # add a RowPlugin with 3 Columns row_model = add_plugin(self.placeholder, BootstrapRowPlugin, 'en', target=container_model) row_plugin = row_model.get_plugin_class_instance() row_change_form = BootstrapRowForm({'num_children': 3}) row_change_form.full_clean() row_plugin.save_model(self.request, row_model, row_change_form, False) self.assertDictEqual(row_model.glossary, {}) self.assertIsInstance(row_model, CascadeElement) self.assertEqual(str(row_model), 'with 3 columns') plugin_list = [container_model, row_model] columns_qs = CascadeElement.objects.filter(parent_id=row_model.id) self.assertEqual(columns_qs.count(), 3) for column_model in columns_qs: self.assertIsInstance(column_model, CascadeElement) column_plugin = column_model.get_plugin_class_instance() self.assertIsInstance(column_plugin, BootstrapColumnPlugin) self.assertEqual(column_model.parent.id, row_model.id) self.assertEqual(str(column_model), 'default width: 4 units') plugin_list.append(column_model) # Render the Container Plugin with all of its children build_plugin_tree(plugin_list) context = get_request_context(self.request) html = container_model.render_plugin(context) self.assertHTMLEqual( html, '<div class="container"><div class="row">' + '<div class="col-sm-4"></div><div class="col-sm-4"></div><div class="col-sm-4"></div>' + '</div></div>') # change data inside the first column column_model = columns_qs[0] delattr(column_model, '_inst') column_plugin = column_model.get_plugin_class_instance(self.admin_site) column_plugin.cms_plugin_instance = column_model post_data = QueryDict('', mutable=True) post_data.update({ 'sm-column-offset': 'col-sm-offset-1', 'sm-column-width': 'col-sm-3' }) ModelForm = column_plugin.get_form(self.request, column_model) form = ModelForm(post_data, None, instance=column_model) self.assertTrue(form.is_valid()) column_plugin.save_model(self.request, column_model, form, True) # change data inside the second column column_model = columns_qs[1] delattr(column_model, '_inst') column_plugin = column_model.get_plugin_class_instance(self.admin_site) column_plugin.cms_plugin_instance = column_model post_data = QueryDict('', mutable=True) post_data.update({ 'sm-responsive-utils': 'hidden-sm', 'sm-column-width': 'col-sm-4' }) ModelForm = column_plugin.get_form(self.request, column_model) form = ModelForm(post_data, None, instance=column_model) self.assertTrue(form.is_valid()) column_plugin.save_model(self.request, column_model, form, False) html = container_model.render_plugin(context) self.assertHTMLEqual( html, '<div class="container"><div class="row">' + '<div class="col-sm-3 col-sm-offset-1"></div><div class="col-sm-4 hidden-sm"></div><div class="col-sm-4"></div>' + '</div></div>')
def test_plugin_context(self): # create container container_model = add_plugin(self.placeholder, BootstrapContainerPlugin, 'en', glossary={'breakpoints': CASCADE_BREAKPOINTS_LIST}) container_plugin = container_model.get_plugin_class_instance(self.admin_site) self.assertIsInstance(container_plugin, BootstrapContainerPlugin) # add one row row_model = add_plugin(self.placeholder, BootstrapRowPlugin, 'en', target=container_model, glossary={}) row_plugin = row_model.get_plugin_class_instance() self.assertIsInstance(row_plugin, BootstrapRowPlugin) # add one column column_model = add_plugin(self.placeholder, BootstrapColumnPlugin, 'en', target=row_model, glossary={'xs-column-width': 'col-xs-12', 'sm-column-width': 'col-sm-6', 'md-column-width': 'col-md-4', 'lg-column-width': 'col-lg-3'}) column_plugin = column_model.get_plugin_class_instance() self.assertIsInstance(column_plugin, BootstrapColumnPlugin) # add an image image_model = add_plugin(self.placeholder, BootstrapImagePlugin, 'en', target=column_model) self.assertIsInstance(image_model, SharableCascadeElement) image_plugin = image_model.get_plugin_class_instance(self.admin_site) self.assertIsInstance(image_plugin, BootstrapImagePlugin) image_plugin.cms_plugin_instance = image_model.cmsplugin_ptr # upload an image and change the form ModelForm = image_plugin.get_form(self.request, image_model) image = self.upload_demo_image() post_data = QueryDict('', mutable=True) post_data.update({'image_file': image.pk, 'link_type': 'none', 'image-width-fixed': '300px'}) image_model._image_model = image form = ModelForm(post_data, None, instance=image_model) self.assertTrue(form.is_valid()) image_plugin.save_model(self.request, image_model, form, False) # render the plugins plugin_list = [container_model, row_model, column_model, image_model] build_plugin_tree(plugin_list) context = get_request_context(self.request) html = container_model.render_plugin(context) soup = BeautifulSoup(html) self.assertEqual(soup.img['height'], '100') self.assertEqual(soup.img['width'], '300') self.assertTrue('demo_image.png__300x100_q85_subsampling-2' in str(soup.img)) # use a responsive image post_data.setlist('image-shapes', ['img-responsive']) form = ModelForm(post_data, None, instance=image_model) self.assertTrue(form.is_valid()) image_plugin.save_model(self.request, image_model, form, False) html = container_model.render_plugin(context) soup = BeautifulSoup(html) self.assertTrue('img-responsive' in soup.img['class']) sizes = [s.strip() for s in soup.img['sizes'].split(',')] self.assertTrue('(max-width: 768px) 720px' in sizes) self.assertTrue('(min-width: 768px) and (max-width: 992px) 345px' in sizes) self.assertTrue('(min-width: 992px) and (max-width: 1200px) 293px' in sizes) self.assertTrue('(min-width: 1200px) 262px' in sizes) srcsets = [s.strip() for s in soup.img['srcset'].split(',')] self.assertEqual(len([s for s in srcsets if s.endswith('demo_image.png__293x98_q85_subsampling-2.jpg 293w')]), 1) self.assertEqual(len([s for s in srcsets if s.endswith('demo_image.png__720x240_q85_subsampling-2.jpg 720w')]), 1) self.assertEqual(len([s for s in srcsets if s.endswith('demo_image.png__345x115_q85_subsampling-2.jpg 345w')]), 1) self.assertEqual(len([s for s in srcsets if s.endswith('demo_image.png__262x87_q85_subsampling-2.jpg 262w')]), 1) self.assertTrue(soup.img['src'].endswith('demo_image.png__720x240_q85_subsampling-2.jpg'))
def test_plugin_context(self): # create container container_model = add_plugin( self.placeholder, BootstrapContainerPlugin, 'en', glossary={'breakpoints': BS3_BREAKPOINT_KEYS}) container_plugin = container_model.get_plugin_class_instance( self.admin_site) self.assertIsInstance(container_plugin, BootstrapContainerPlugin) # add one row row_model = add_plugin(self.placeholder, BootstrapRowPlugin, 'en', target=container_model, glossary={}) row_plugin = row_model.get_plugin_class_instance() self.assertIsInstance(row_plugin, BootstrapRowPlugin) # add one column column_model = add_plugin(self.placeholder, BootstrapColumnPlugin, 'en', target=row_model, glossary={ 'xs-column-width': 'col-xs-12', 'sm-column-width': 'col-sm-6', 'md-column-width': 'col-md-4', 'lg-column-width': 'col-lg-3' }) column_plugin = column_model.get_plugin_class_instance() self.assertIsInstance(column_plugin, BootstrapColumnPlugin) # add a picture picture_model = add_plugin(self.placeholder, BootstrapPicturePlugin, 'en', target=column_model) self.assertIsInstance(picture_model, SharableCascadeElement) picture_plugin = picture_model.get_plugin_class_instance( self.admin_site) self.assertIsInstance(picture_plugin, BootstrapPicturePlugin) picture_plugin.cms_plugin_instance = picture_model.cmsplugin_ptr # upload an image and change the form ModelForm = picture_plugin.get_form(self.request, picture_model) image = self.upload_demo_image() post_data = QueryDict('', mutable=True) post_data.update({ 'image_file': image.pk, 'link_type': 'none', 'responsive_heights-xs': '50%', 'responsive_heights-sm': '66%', 'responsive_heights-md': '75%', 'responsive_heights-lg': '100%', 'responsive_zoom-lg': '40%', 'responsive_zoom-lg': '25%', 'responsive_zoom-lg': '15%', 'responsive_zoom-lg': '0%' }) post_data.setlist('resize_options', ['crop']) picture_model._image_model = image form = ModelForm(post_data, None, instance=picture_model) self.assertTrue(form.is_valid()) picture_plugin.save_model(self.request, picture_model, form, False) # render the plugins plugin_list = [container_model, row_model, column_model, picture_model] build_plugin_tree(plugin_list) soup = BeautifulSoup( self.get_html(container_model, self.get_request_context())) self.assertEqual(soup.img['height'], '240') self.assertEqual(soup.img['width'], '720') self.assertTrue('demo_image.png__720x240_q85_crop_subsampling-2.jpg' in str(soup.img)) sources = dict( (s['media'], s['srcset']) for s in soup.picture.find_all('source')) self.assertTrue('demo_image.png__720x120_q85_crop_subsampling-2.jpg' in sources['(max-width: 768px)']) self.assertTrue('demo_image.png__345x76_q85_crop_subsampling-2.jpg' in sources['(min-width: 768px) and (max-width: 992px)']) self.assertTrue('demo_image.png__293x73_q85_crop_subsampling-2.jpg' in sources['(min-width: 992px) and (max-width: 1200px)']) # Due to an different round implimentation in python3 height can vary by 1 to 2 pixels self.assertTrue( bool( re.search( r'demo_image.png__262x8\d_q85_crop_subsampling-2.jpg$', sources['(min-width: 1200px)']))) # with Retina images post_data.setlist('resize_options', ['crop', 'high_resolution']) form = ModelForm(post_data, None, instance=picture_model) self.assertTrue(form.is_valid()) picture_plugin.save_model(self.request, picture_model, form, False) soup = BeautifulSoup( self.get_html(container_model, self.get_request_context())) self.assertEqual(soup.img['height'], '240') self.assertEqual(soup.img['width'], '720') self.assertTrue('demo_image.png__720x240_q85_crop_subsampling-2.jpg' in soup.img['src']) sources = dict( (s['media'], s['srcset']) for s in soup.picture.find_all('source')) self.assertTrue( 'demo_image.png__720x120_q85_crop_subsampling-2.jpg' in sources[ '(max-width: 768px) and (max-resolution: 1.5dppx), (max-resolution: 144dpi), (-webkit-max-device-pixel-ratio: 1.5), (-o-max-device-pixel-ratio: 3)'] ) self.assertTrue( 'demo_image.png__1440x240_q85_crop_subsampling-2.jpg' in sources[ '(max-width: 768px) and (min-resolution: 1.5dppx), (min-resolution: 144dpi), (-webkit-min-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3)'] ) self.assertTrue( 'demo_image.png__345x76_q85_crop_subsampling-2.jpg' in sources[ '(min-width: 768px) and (max-width: 992px) and (max-resolution: 1.5dppx), (max-resolution: 144dpi), (-webkit-max-device-pixel-ratio: 1.5), (-o-max-device-pixel-ratio: 3)'] ) self.assertTrue( 'demo_image.png__690x152_q85_crop_subsampling-2.jpg' in sources[ '(min-width: 768px) and (max-width: 992px) and (min-resolution: 1.5dppx), (min-resolution: 144dpi), (-webkit-min-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3)'] ) self.assertTrue( 'demo_image.png__293x73_q85_crop_subsampling-2.jpg' in sources[ '(min-width: 992px) and (max-width: 1200px) and (max-resolution: 1.5dppx), (max-resolution: 144dpi), (-webkit-max-device-pixel-ratio: 1.5), (-o-max-device-pixel-ratio: 3)'] ) self.assertTrue( 'demo_image.png__586x146_q85_crop_subsampling-2.jpg' in sources[ '(min-width: 992px) and (max-width: 1200px) and (min-resolution: 1.5dppx), (min-resolution: 144dpi), (-webkit-min-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3)'] ) # Due to an different round implimentation in python3 height can vary by 1 to 2 pixels self.assertTrue( bool( re.search( r'demo_image.png__262x8\d_q85_crop_subsampling-2.jpg$', sources[ '(min-width: 1200px) and (max-resolution: 1.5dppx), (max-resolution: 144dpi), (-webkit-max-device-pixel-ratio: 1.5), (-o-max-device-pixel-ratio: 3)'] ))) self.assertTrue( bool( re.search( r'demo_image.png__524x17\d_q85_crop_subsampling-2.jpg$', sources[ '(min-width: 1200px) and (min-resolution: 1.5dppx), (min-resolution: 144dpi), (-webkit-min-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3)'] )))
def setUp(self): super(ClipboardPluginTest, self).setUp() UserModel = get_user_model() self.admin_user = UserModel.objects.get(username='******') # add a Bootstrap Container Plugin container_model = add_plugin( self.placeholder, BootstrapContainerPlugin, 'en', glossary={'breakpoints': BS3_BREAKPOINT_KEYS}) self.assertIsInstance(container_model, CascadeElement) container_plugin = container_model.get_plugin_class_instance( self.admin_site) self.assertIsInstance(container_plugin, BootstrapContainerPlugin) ModelForm = container_plugin.get_form(self.request, container_model) post_data = QueryDict('', mutable=True) post_data.setlist('breakpoints', ['sm', 'md']) form = ModelForm(post_data, None, instance=container_model) soup = BeautifulSoup(form.as_p(), features='lxml') input_element = soup.find(id="id_glossary_breakpoints_0") self.assertDictContainsSubset( { 'type': 'checkbox', 'name': 'breakpoints', 'value': 'xs' }, input_element.attrs) input_element = soup.find(id="id_glossary_breakpoints_2") self.assertDictContainsSubset( { 'type': 'checkbox', 'name': 'breakpoints', 'value': 'md', 'checked': '' }, input_element.attrs) input_element = soup.find(id="id_glossary_fluid") self.assertDictContainsSubset({ 'type': 'checkbox', 'name': 'fluid' }, input_element.attrs) container_plugin.save_model(self.request, container_model, form, False) self.assertListEqual(container_model.glossary['breakpoints'], ['sm', 'md']) self.assertTrue('fluid' in container_model.glossary) self.assertEqual(str(container_model), 'for tablets, laptops') # add a RowPlugin with 3 Columns row_model = add_plugin(self.placeholder, BootstrapRowPlugin, 'en', target=container_model) row_plugin = row_model.get_plugin_class_instance() row_change_form = BootstrapRowForm({'num_children': 3}) row_change_form.full_clean() row_plugin.save_model(self.request, row_model, row_change_form, False) self.assertDictEqual(row_model.glossary, {}) self.assertIsInstance(row_model, CascadeElement) self.assertEqual(str(row_model), 'with 3 columns') plugin_list = [container_model, row_model] columns_qs = CascadeElement.objects.filter(parent_id=row_model.id) self.assertEqual(columns_qs.count(), 3) row_data = [] for column_model in columns_qs: self.assertIsInstance(column_model, CascadeElement) column_plugin = column_model.get_plugin_class_instance() self.assertIsInstance(column_plugin, BootstrapColumnPlugin) self.assertEqual(column_model.parent.id, row_model.id) self.assertEqual(str(column_model), 'default width: 4 units') plugin_list.append(column_model) row_data.append([ 'BootstrapColumnPlugin', { 'glossary': column_model.glossary }, [] ]) # container_data = ['BootstrapRowPlugin', {'glossary': row_model.glossary}, row_data] # Render the Container Plugin with all of its children build_plugin_tree(plugin_list) html = self.get_html(container_model, self.get_request_context()) self.assertHTMLEqual( html, '<div class="container"><div class="row">' + '<div class="col-sm-4"></div><div class="col-sm-4"></div>' + '<div class="col-sm-4"></div>' + '</div></div>') # change data inside the first column column_model = columns_qs[0] delattr(column_model, '_inst') column_plugin = column_model.get_plugin_class_instance(self.admin_site) column_plugin.cms_plugin_instance = column_model post_data = QueryDict('', mutable=True) post_data.update({ 'sm-column-offset': 'col-sm-offset-1', 'sm-column-width': 'col-sm-3' }) ModelForm = column_plugin.get_form(self.request, column_model) form = ModelForm(post_data, None, instance=column_model) self.assertTrue(form.is_valid()) column_plugin.save_model(self.request, column_model, form, True) # change data inside the second column column_model = columns_qs[1] delattr(column_model, '_inst') column_plugin = column_model.get_plugin_class_instance(self.admin_site) column_plugin.cms_plugin_instance = column_model post_data = QueryDict('', mutable=True) post_data.update({ 'sm-responsive-utils': 'hidden-sm', 'sm-column-width': 'col-sm-4' }) ModelForm = column_plugin.get_form(self.request, column_model) form = ModelForm(post_data, None, instance=column_model) self.assertTrue(form.is_valid()) column_plugin.save_model(self.request, column_model, form, False) html = self.get_html(container_model, self.get_request_context()) self.assertHTMLEqual( html, '<div class="container"><div class="row">' + '<div class="col-sm-3 col-sm-offset-1"></div>' + '<div class="col-sm-4 hidden-sm"></div><div class="col-sm-4"></div>' + '</div></div>')
def test_plugin_context(self): # create container container_model = add_plugin(self.placeholder, BootstrapContainerPlugin, 'en', glossary={'breakpoints': BS3_BREAKPOINT_KEYS}) container_plugin = container_model.get_plugin_class_instance() self.assertIsInstance(container_plugin, BootstrapContainerPlugin) # add one row row_model = add_plugin(self.placeholder, BootstrapRowPlugin, 'en', target=container_model, glossary={}) row_plugin = row_model.get_plugin_class_instance() self.assertIsInstance(row_plugin, BootstrapRowPlugin) # add one column column_model = add_plugin(self.placeholder, BootstrapColumnPlugin, 'en', target=row_model, glossary={'xs-column-width': 'col-xs-12', 'sm-column-width': 'col-sm-6', 'md-column-width': 'col-md-4', 'lg-column-width': 'col-lg-3'}) column_plugin = column_model.get_plugin_class_instance() self.assertIsInstance(column_plugin, BootstrapColumnPlugin) # add a picture picture_model = add_plugin(self.placeholder, BootstrapPicturePlugin, 'en', target=column_model) self.assertIsInstance(picture_model, SharableCascadeElement) picture_plugin = picture_model.get_plugin_class_instance() self.assertIsInstance(picture_plugin, BootstrapPicturePlugin) picture_plugin.cms_plugin_instance = picture_model.cmsplugin_ptr # upload an image and change the form ModelForm = picture_plugin.get_form(self.request, picture_model) image = self.upload_demo_image() post_data = QueryDict('', mutable=True) post_data.update({'image_file': image.pk, 'link_type': 'none', 'responsive_heights-xs': '50%', 'responsive_heights-sm': '66%', 'responsive_heights-md': '75%', 'responsive_heights-lg': '100%', 'responsive_zoom-lg': '40%', 'responsive_zoom-lg': '25%', 'responsive_zoom-lg': '15%', 'responsive_zoom-lg': '0%'}) post_data.setlist('resize_options', ['crop']) picture_model._image_model = image form = ModelForm(post_data, None, instance=picture_model) self.assertTrue(form.is_valid()) picture_plugin.save_model(self.request, picture_model, form, False) # render the plugins plugin_list = [container_model, row_model, column_model, picture_model] build_plugin_tree(plugin_list) soup = BeautifulSoup(self.get_html(container_model, self.get_request_context()), features="lxml") self.assertEqual(soup.img['height'], '240') self.assertEqual(soup.img['width'], '720') self.assertTrue('demo_image.png__720x240_q85_crop_subsampling-2.jpg' in str(soup.img)) sources = dict((s['media'], s['srcset']) for s in soup.picture.find_all('source')) self.assertTrue('demo_image.png__720x120_q85_crop_subsampling-2.jpg' in sources['(max-width: 768px)']) self.assertTrue('demo_image.png__345x76_q85_crop_subsampling-2.jpg' in sources['(min-width: 768px) and (max-width: 992px)']) self.assertTrue('demo_image.png__293x73_q85_crop_subsampling-2.jpg' in sources['(min-width: 992px) and (max-width: 1200px)']) # Due to an different round implimentation in python3 height can vary by 1 to 2 pixels self.assertTrue(bool(re.search(r'demo_image.png__262x8\d_q85_crop_subsampling-2.jpg$', sources['(min-width: 1200px)']))) # with Retina images post_data.setlist('resize_options', ['crop', 'high_resolution']) form = ModelForm(post_data, None, instance=picture_model) self.assertTrue(form.is_valid()) picture_plugin.save_model(self.request, picture_model, form, False) soup = BeautifulSoup(self.get_html(container_model, self.get_request_context()), features="lxml") self.assertEqual(soup.img['height'], '240') self.assertEqual(soup.img['width'], '720') self.assertTrue('demo_image.png__720x240_q85_crop_subsampling-2.jpg' in soup.img['src']) sources = dict((s['media'], s['srcset']) for s in soup.picture.find_all('source')) self.assertTrue('demo_image.png__720x120_q85_crop_subsampling-2.jpg 1x' in sources['(max-width: 768px)']) self.assertTrue('demo_image.png__1440x240_q85_crop_subsampling-2.jpg 2x' in sources['(max-width: 768px)']) self.assertTrue('demo_image.png__345x76_q85_crop_subsampling-2.jpg 1x' in sources['(min-width: 768px) and (max-width: 992px)']) self.assertTrue('demo_image.png__690x152_q85_crop_subsampling-2.jpg 2x' in sources['(min-width: 768px) and (max-width: 992px)']) self.assertTrue('demo_image.png__293x73_q85_crop_subsampling-2.jpg 1x' in sources['(min-width: 992px) and (max-width: 1200px)']) self.assertTrue('demo_image.png__586x146_q85_crop_subsampling-2.jpg 2x' in sources['(min-width: 992px) and (max-width: 1200px)']) # Due to an different round implimentation in python3 height can vary by 1 to 2 pixels self.assertTrue(bool(re.search(r'demo_image.png__262x8\d_q85_crop_subsampling-2.jpg\s1x', sources['(min-width: 1200px)']))) self.assertTrue(bool(re.search(r'demo_image.png__524x17\d_q85_crop_subsampling-2.jpg\s2x', sources['(min-width: 1200px)'])))
def test_add_font(self): with self.login_user_context(self.admin_user): # upload the zipfile into the filer's clipboard filename = os.path.join(os.path.dirname(__file__), 'assets/fontello-b504201f.zip') with open(filename, 'rb') as zipfile: uploaded_file = SimpleUploadedFile( 'fontello-b504201f.zip', zipfile.read(), content_type='application/zip') request = self.get_request(reverse('admin:filer-ajax_upload')) self.assertTrue(request.user.is_staff, "User is not a staff user") request.FILES.update(file=uploaded_file) response = ajax_upload(request) self.assertEqual(response.status_code, 200) content = json.loads(response.content.decode('utf-8')) self.assertDictContainsSubset({'label': 'fontello-b504201f.zip'}, content) # save the form and submit the remaining fields add_iconfont_url = reverse('admin:cmsplugin_cascade_iconfont_add') data = { 'identifier': "Fontellico", 'zip_file': content['file_id'], '_continue': "Save and continue editing", } response = self.client.post(add_iconfont_url, data) self.assertEqual(response.status_code, 302) resolver_match = resolve(response.url) self.assertEqual(resolver_match.url_name, 'cmsplugin_cascade_iconfont_change') # check the content of the uploaded file icon_font = IconFont.objects.get(pk=resolver_match.args[0]) self.assertEqual(icon_font.identifier, "Fontellico") self.assertEqual(icon_font.config_data['name'], 'fontelico') self.assertEqual(len(icon_font.config_data['glyphs']), 34) # check if the uploaded fonts are rendered inside Preview Icons response = self.client.get(response.url) self.assertEqual(response.status_code, 200) soup = BeautifulSoup(response.content, 'lxml') preview_iconfont = soup.find('div', class_="preview-iconfont") icon_items = preview_iconfont.ul.find_all('li') self.assertEqual(len(icon_items), 34) self.assertListEqual(icon_items[0].i.attrs['class'], ['icon-emo-happy']) self.assertListEqual(icon_items[33].i.attrs['class'], ['icon-marquee']) # create container container_model = add_plugin( self.placeholder, BootstrapContainerPlugin, 'en', glossary={'breakpoints': BS3_BREAKPOINT_KEYS}) container_plugin = container_model.get_plugin_class_instance() self.assertIsInstance(container_plugin, BootstrapContainerPlugin) # add icon as child to this container glossary = { "font_size": "10em", "color": ["", "#88258e"], "background_color": ["on", "#c8ffcd"], "symbol": "emo-wink", "icon_font": icon_font.pk, "border_radius": "50%", "border": ["", "solid", "#000000"] } icon_model = add_plugin(self.placeholder, FramedIconPlugin, 'en', target=container_model, glossary=glossary) icon_plugin = icon_model.get_plugin_class_instance() self.assertIsInstance(icon_plugin, FramedIconPlugin) # render the plugins plugin_list = [container_model, icon_model] build_plugin_tree(plugin_list) html = self.get_html(container_model, self.get_request_context()) soup = BeautifulSoup(html, 'lxml') # look for the icon symbol style = soup.find('span', class_='icon-emo-wink').attrs['style'].split(';') self.assertIn('color:#88258e', style) self.assertIn('display:inline-block', style) # look for the CSS file response = self.client.get( container_model.placeholder.page.get_absolute_url() + '?edit') self.assertEqual(response.status_code, 200) soup = BeautifulSoup(response.content, 'lxml') links = soup.head.find_all('link') for link in links: if link.attrs['href'].endswith('fontelico.css'): break else: self.fail("No CSS file with font definition found")
def test_plugin_context(self): # create container container_model = add_plugin( self.placeholder, BootstrapContainerPlugin, 'en', glossary={'breakpoints': CASCADE_BREAKPOINTS_LIST}) container_plugin = container_model.get_plugin_class_instance( self.admin_site) self.assertIsInstance(container_plugin, BootstrapContainerPlugin) # add one row row_model = add_plugin(self.placeholder, BootstrapRowPlugin, 'en', target=container_model, glossary={}) row_plugin = row_model.get_plugin_class_instance() self.assertIsInstance(row_plugin, BootstrapRowPlugin) # add one column column_model = add_plugin(self.placeholder, BootstrapColumnPlugin, 'en', target=row_model, glossary={ 'xs-column-width': 'col-xs-12', 'sm-column-width': 'col-sm-6', 'md-column-width': 'col-md-4', 'lg-column-width': 'col-lg-3' }) column_plugin = column_model.get_plugin_class_instance() self.assertIsInstance(column_plugin, BootstrapColumnPlugin) # add a picture picture_model = add_plugin(self.placeholder, BootstrapPicturePlugin, 'en', target=column_model) self.assertIsInstance(picture_model, SharableCascadeElement) picture_plugin = picture_model.get_plugin_class_instance( self.admin_site) self.assertIsInstance(picture_plugin, BootstrapPicturePlugin) picture_plugin.cms_plugin_instance = picture_model.cmsplugin_ptr # upload an image and change the form ModelForm = picture_plugin.get_form(self.request, picture_model) image = self.upload_demo_image() post_data = QueryDict('', mutable=True) post_data.update({ 'image_file': image.pk, 'link_type': 'none', 'responsive-heights-xs': '50%', 'responsive-heights-sm': '66%', 'responsive-heights-md': '75%', 'responsive-heights-lg': '100%', 'responsive-zoom-lg': '40%', 'responsive-zoom-lg': '25%', 'responsive-zoom-lg': '15%', 'responsive-zoom-lg': '0%' }) post_data.setlist('resize-options', ['crop']) form = ModelForm(post_data, None, instance=picture_model) self.assertTrue(form.is_valid()) picture_plugin.save_model(self.request, picture_model, form, False) # render the plugins plugin_list = [container_model, row_model, column_model, picture_model] build_plugin_tree(plugin_list) context = RequestContext(self.request, {}) html = container_model.render_plugin(context) soup = BeautifulSoup(html) self.assertEqual(soup.img['height'], '240') self.assertEqual(soup.img['width'], '720') self.assertTrue(soup.img['src'].endswith( 'demo_image.png__720x240_q85_crop_subsampling-2.png')) sources = dict( (s['media'], s['srcset']) for s in soup.picture.find_all('source')) self.assertTrue(sources['(max-width: 768px)'].endswith( 'demo_image.png__720x120_q85_crop_subsampling-2.png')) self.assertTrue( sources['(min-width: 768px) and (max-width: 992px)'].endswith( 'demo_image.png__345x76_q85_crop_subsampling-2.png')) self.assertTrue( sources['(min-width: 992px) and (max-width: 1200px)'].endswith( 'demo_image.png__293x73_q85_crop_subsampling-2.png')) self.assertTrue(sources['(min-width: 1200px)'].endswith( 'demo_image.png__262x87_q85_crop_subsampling-2.png')) # with Retina images post_data.setlist('resize-options', ['crop', 'high_resolution']) form = ModelForm(post_data, None, instance=picture_model) self.assertTrue(form.is_valid()) picture_plugin.save_model(self.request, picture_model, form, False) html = container_model.render_plugin(context) soup = BeautifulSoup(html) self.assertEqual(soup.img['height'], '240') self.assertEqual(soup.img['width'], '720') self.assertTrue(soup.img['src'].endswith( 'demo_image.png__720x240_q85_crop_subsampling-2.png')) sources = dict( (s['media'], s['srcset']) for s in soup.picture.find_all('source')) self.assertTrue( sources['(max-width: 768px) and (max-resolution: 1.5dppx)']. endswith('demo_image.png__720x120_q85_crop_subsampling-2.png')) self.assertTrue( sources['(max-width: 768px) and (min-resolution: 1.5dppx)']. endswith('demo_image.png__1440x240_q85_crop_subsampling-2.png')) self.assertTrue(sources[ '(min-width: 768px) and (max-width: 992px) and (max-resolution: 1.5dppx)'] .endswith( 'demo_image.png__345x76_q85_crop_subsampling-2.png' )) self.assertTrue(sources[ '(min-width: 768px) and (max-width: 992px) and (min-resolution: 1.5dppx)'] .endswith( 'demo_image.png__690x152_q85_crop_subsampling-2.png' )) self.assertTrue(sources[ '(min-width: 992px) and (max-width: 1200px) and (max-resolution: 1.5dppx)'] .endswith( 'demo_image.png__293x73_q85_crop_subsampling-2.png' )) self.assertTrue(sources[ '(min-width: 992px) and (max-width: 1200px) and (min-resolution: 1.5dppx)'] .endswith( 'demo_image.png__586x146_q85_crop_subsampling-2.png' )) self.assertTrue( sources['(min-width: 1200px) and (max-resolution: 1.5dppx)']. endswith('demo_image.png__262x87_q85_crop_subsampling-2.png')) self.assertTrue( sources['(min-width: 1200px) and (min-resolution: 1.5dppx)']. endswith('demo_image.png__524x174_q85_crop_subsampling-2.png'))
def test_container_context(self): # add a Bootstrap Container Plugin container_model = add_plugin(self.placeholder, BootstrapContainerPlugin, 'en', glossary={'breakpoints': BS3_BREAKPOINT_KEYS}) self.assertIsInstance(container_model, CascadeElement) container_plugin = container_model.get_plugin_class_instance(self.admin_site) self.assertIsInstance(container_plugin, BootstrapContainerPlugin) ModelForm = container_plugin.get_form(self.request, container_model) post_data = QueryDict('', mutable=True) post_data.setlist('breakpoints', ['sm', 'md']) form = ModelForm(post_data, None, instance=container_model) html = form.as_p() self.assertInHTML('<input id="id_glossary_breakpoints_0" name="breakpoints" type="checkbox" value="xs" />', html) self.assertInHTML('<input checked="checked" id="id_glossary_breakpoints_2" name="breakpoints" type="checkbox" value="md" />', html) self.assertInHTML('<input id="id_glossary_fluid" name="fluid" type="checkbox" />', html) container_plugin.save_model(self.request, container_model, form, False) self.assertListEqual(container_model.glossary['breakpoints'], ['sm', 'md']) self.assertTrue('fluid' in container_model.glossary) self.assertEqual(str(container_model), 'for tablets, laptops') # add a RowPlugin with 3 Columns row_model = add_plugin(self.placeholder, BootstrapRowPlugin, 'en', target=container_model) row_plugin = row_model.get_plugin_class_instance() row_change_form = BootstrapRowForm({'num_children': 3}) row_change_form.full_clean() row_plugin.save_model(self.request, row_model, row_change_form, False) self.assertDictEqual(row_model.glossary, {}) self.assertIsInstance(row_model, CascadeElement) self.assertEqual(str(row_model), 'with 3 columns') plugin_list = [container_model, row_model] columns_qs = CascadeElement.objects.filter(parent_id=row_model.id) self.assertEqual(columns_qs.count(), 3) for column_model in columns_qs: self.assertIsInstance(column_model, CascadeElement) column_plugin = column_model.get_plugin_class_instance() self.assertIsInstance(column_plugin, BootstrapColumnPlugin) self.assertEqual(column_model.parent.id, row_model.id) self.assertEqual(str(column_model), 'default width: 4 units') plugin_list.append(column_model) # Render the Container Plugin with all of its children build_plugin_tree(plugin_list) html = self.get_html(container_model, self.get_request_context()) self.assertHTMLEqual(html, '<div class="container"><div class="row">' + '<div class="col-sm-4"></div><div class="col-sm-4"></div><div class="col-sm-4"></div>' + '</div></div>') # change data inside the first column column_model = columns_qs[0] delattr(column_model, '_inst') column_plugin = column_model.get_plugin_class_instance(self.admin_site) column_plugin.cms_plugin_instance = column_model post_data = QueryDict('', mutable=True) post_data.update({'sm-column-offset': 'col-sm-offset-1', 'sm-column-width': 'col-sm-3'}) ModelForm = column_plugin.get_form(self.request, column_model) form = ModelForm(post_data, None, instance=column_model) self.assertTrue(form.is_valid()) column_plugin.save_model(self.request, column_model, form, True) # change data inside the second column column_model = columns_qs[1] delattr(column_model, '_inst') column_plugin = column_model.get_plugin_class_instance(self.admin_site) column_plugin.cms_plugin_instance = column_model post_data = QueryDict('', mutable=True) post_data.update({'sm-responsive-utils': 'hidden-sm', 'sm-column-width': 'col-sm-4'}) ModelForm = column_plugin.get_form(self.request, column_model) form = ModelForm(post_data, None, instance=column_model) self.assertTrue(form.is_valid()) column_plugin.save_model(self.request, column_model, form, False) html = self.get_html(container_model, self.get_request_context()) self.assertHTMLEqual(html, '<div class="container"><div class="row">' + '<div class="col-sm-3 col-sm-offset-1"></div><div class="col-sm-4 hidden-sm"></div><div class="col-sm-4"></div>' + '</div></div>')
def setUp(self): super(ClipboardPluginTest, self).setUp() UserModel = get_user_model() self.admin_user = UserModel.objects.get(username='******') # add a Bootstrap Container Plugin container_model = add_plugin(self.placeholder, BootstrapContainerPlugin, 'en', glossary={'breakpoints': BS3_BREAKPOINT_KEYS}) self.assertIsInstance(container_model, CascadeElement) container_plugin = container_model.get_plugin_class_instance(self.admin_site) self.assertIsInstance(container_plugin, BootstrapContainerPlugin) ModelForm = container_plugin.get_form(self.request, container_model) post_data = QueryDict('', mutable=True) post_data.setlist('breakpoints', ['sm', 'md']) form = ModelForm(post_data, None, instance=container_model) soup = BeautifulSoup(form.as_p(), features='lxml') input_element = soup.find(id="id_glossary_breakpoints_0") self.assertDictContainsSubset({'type': 'checkbox', 'name': 'breakpoints', 'value': 'xs'}, input_element.attrs) input_element = soup.find(id="id_glossary_breakpoints_2") self.assertDictContainsSubset({'type': 'checkbox', 'name': 'breakpoints', 'value': 'md', 'checked': ''}, input_element.attrs) input_element = soup.find(id="id_glossary_fluid") self.assertDictContainsSubset({'type': 'checkbox', 'name': 'fluid'}, input_element.attrs) container_plugin.save_model(self.request, container_model, form, False) self.assertListEqual(container_model.glossary['breakpoints'], ['sm', 'md']) self.assertTrue('fluid' in container_model.glossary) self.assertEqual(str(container_model), 'for tablets, laptops') # add a RowPlugin with 3 Columns row_model = add_plugin(self.placeholder, BootstrapRowPlugin, 'en', target=container_model) row_plugin = row_model.get_plugin_class_instance() row_change_form = BootstrapRowForm({'num_children': 3}) row_change_form.full_clean() row_plugin.save_model(self.request, row_model, row_change_form, False) self.assertDictEqual(row_model.glossary, {}) self.assertIsInstance(row_model, CascadeElement) self.assertEqual(str(row_model), 'with 3 columns') plugin_list = [container_model, row_model] columns_qs = CascadeElement.objects.filter(parent_id=row_model.id) self.assertEqual(columns_qs.count(), 3) row_data = [] for column_model in columns_qs: self.assertIsInstance(column_model, CascadeElement) column_plugin = column_model.get_plugin_class_instance() self.assertIsInstance(column_plugin, BootstrapColumnPlugin) self.assertEqual(column_model.parent.id, row_model.id) self.assertEqual(str(column_model), 'default width: 4 units') plugin_list.append(column_model) row_data.append(['BootstrapColumnPlugin', {'glossary': column_model.glossary}, []]) # container_data = ['BootstrapRowPlugin', {'glossary': row_model.glossary}, row_data] # Render the Container Plugin with all of its children build_plugin_tree(plugin_list) html = self.get_html(container_model, self.get_request_context()) self.assertHTMLEqual(html, '<div class="container"><div class="row">' + '<div class="col-sm-4"></div><div class="col-sm-4"></div>' + '<div class="col-sm-4"></div>' + '</div></div>') # change data inside the first column column_model = columns_qs[0] delattr(column_model, '_inst') column_plugin = column_model.get_plugin_class_instance(self.admin_site) column_plugin.cms_plugin_instance = column_model post_data = QueryDict('', mutable=True) post_data.update({'sm-column-offset': 'col-sm-offset-1', 'sm-column-width': 'col-sm-3'}) ModelForm = column_plugin.get_form(self.request, column_model) form = ModelForm(post_data, None, instance=column_model) self.assertTrue(form.is_valid()) column_plugin.save_model(self.request, column_model, form, True) # change data inside the second column column_model = columns_qs[1] delattr(column_model, '_inst') column_plugin = column_model.get_plugin_class_instance(self.admin_site) column_plugin.cms_plugin_instance = column_model post_data = QueryDict('', mutable=True) post_data.update({'sm-responsive-utils': 'hidden-sm', 'sm-column-width': 'col-sm-4'}) ModelForm = column_plugin.get_form(self.request, column_model) form = ModelForm(post_data, None, instance=column_model) self.assertTrue(form.is_valid()) column_plugin.save_model(self.request, column_model, form, False) html = self.get_html(container_model, self.get_request_context()) self.assertHTMLEqual(html, '<div class="container"><div class="row">' + '<div class="col-sm-3 col-sm-offset-1"></div>' + '<div class="col-sm-4 hidden-sm"></div><div class="col-sm-4"></div>' + '</div></div>')