def test_setting_and_loading_config(self):
        config = IPageConfiguration(create(Builder("sample container")))
        config.store({"default": [{"cols": [{"blocks": [{"uid": "foo"}]}]}]})
        self.assertEquals({"default": [{"cols": [{"blocks": [{"uid": "foo"}]}]}]}, config.load())

        config.store({"default": [{"cols": [{"blocks": [{"uid": "bar"}]}]}]})
        self.assertEquals({"default": [{"cols": [{"blocks": [{"uid": "bar"}]}]}]}, config.load())
    def test_loaded_config_mutations_are_not_stored(self):
        config = IPageConfiguration(create(Builder("sample container")))
        config.store({"default": [{"cols": [{"blocks": [{"uid": "foo"}]}]}]})

        config.load()["default"][0]["cols"][0]["blocks"].append({"uid": "bar"})

        self.assertEquals({"default": [{"cols": [{"blocks": [{"uid": "foo"}]}]}]}, config.load())
 def _get_uids(self):
     page_conf = IPageConfiguration(self.context)
     # look for blocks in default slot first ...
     state_string = json.dumps(unwrap_persistence(
         page_conf.load().get('default', {})))
     # ... then look in all slots.
     state_string += json.dumps(unwrap_persistence(
         page_conf.load()))
     return re.findall(r'\"uid\"\: \"(.+?)\"', state_string)
    def test_loaded_config_mutations_are_not_stored(self):
        config = IPageConfiguration(create(Builder('sample container')))
        config.store(
            {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]}]}
        )

        config.load()['default'][0]['cols'][0]['blocks'].append(
            {'uid': 'bar'})

        self.assertEquals(
            {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]}]},
            config.load())
    def test_setting_and_loading_config(self):
        config = IPageConfiguration(create(Builder('sample container')))
        config.store(
            {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]}]}
        )
        self.assertEquals(
            {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]}]},
            config.load())

        config.store(
            {'default': [{'cols': [{'blocks': [{'uid': 'bar'}]}]}]}
        )
        self.assertEquals(
            {'default': [{'cols': [{'blocks': [{'uid': 'bar'}]}]}]},
            config.load())
    def test_store_partial_updates(self):
        page = create(Builder("sample container"))
        config = IPageConfiguration(page)

        state = {
            "default": [
                {"cols": [{"blocks": [{"uid": "foo"}]}]},
                {"cols": [{"blocks": [{"uid": "bar"}]}, {"blocks": []}]},
            ],
            "sidebar": [{"cols": [{"blocks": [{"uid": "baz"}, {"uid": "foobar"}]}]}],
        }
        config.store(state)

        partial_state = {"sidebar": [{"cols": [{"blocks": [{"uid": "baz"}]}]}]}
        config.store(partial_state)

        # Remove block "foobar" from "sidebar" slot
        new_state = {
            "default": [
                {"cols": [{"blocks": [{"uid": "foo"}]}]},
                {"cols": [{"blocks": [{"uid": "bar"}]}, {"blocks": []}]},
            ],
            "sidebar": [{"cols": [{"blocks": [{"uid": "baz"}]}]}],
        }

        self.assertEquals(new_state, config.load())
Beispiel #7
0
def update_page_state_on_block_remove(block, event):

    if event.newParent is None:
        # Be sure it's not cut/paste
        block_uid = IUUID(block)
        parent = aq_parent(aq_inner(block))

        # Do nothing if the event wasn't fired by the block's parent.
        # This happens when an ancestor is deleted, e.g. the Plone site itself.
        if parent is not event.oldParent:
            return

        config = IPageConfiguration(parent)
        page_state = config.load()

        for container in page_state.values():
            for layout in container:
                for column in layout['cols']:
                    cache_amound_blocks = len(column['blocks'])
                    column['blocks'] = [item for item in column['blocks']
                                        if item['uid'] != block_uid]
                    if cache_amound_blocks != len(column['blocks']):
                        # Block has been removed
                        break
        config.store(page_state)
Beispiel #8
0
def update_page_state_on_copy_paste_block(block, event):
    """Update the uid of the new created block in the page state.
    block: new block
    event.original: origin of the copy event - usually the simplelayout page"""

    # Only update page state, if the original object is a Simplelayout page.
    if not ISimplelayout.providedBy(event.original):
        return

    # The event is triggered recursively - we need to check if the block is
    # actually part of the original page
    if event.original.get(block.id) is None:
        return

    origin_block_uid = IUUID(event.original.get(block.id))
    page_config = IPageConfiguration(block.aq_parent)
    page_state = unwrap_persistence(page_config.load())

    new_block_uid = IUUID(block)
    new_page_state = json.loads(
        json.dumps(page_state).replace(origin_block_uid,
                                       new_block_uid))

    # We should not update object positions here, because:
    # 1. "Ordered folder" makes sure that the order is the same as before
    #    when copy / pasting.
    # 2. Updating positions does not work here, because our objects are not
    #    acquisition wrappable yet (since not yet pasted) and the updating
    #    mechanism will trigger events (such as plone.app.referenceablebehavior),
    #    which require acquisition.
    page_config.store(new_page_state, update_positions=False)
    def test_restore_slot_default_when_removing_last_layout(self):
        """If the last layout was removed from a state, the slot default
        should be restored.
        """

        class ConfigAdapter(object):
            def __init__(self, context, request):
                pass

            def __call__(self, settings):
                pass

            def default_page_layout(self):
                return {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]}]}

        adapter_registration_kwargs = {
            'factory': ConfigAdapter,
            'required': (ISampleSimplelayoutContainer, Interface),
            'provided': ISimplelayoutContainerConfig}

        container = create(Builder('sample container'))

        gsm = getGlobalSiteManager()
        gsm.registerAdapter(**adapter_registration_kwargs)
        try:
            config = IPageConfiguration(container)
            config.store(config.load())
            self.assertEquals(
                {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]}]},
                config.load())

            config.store({'default': [{'cols': [{'blocks': []}]}],
                          'portlet': [{'cols': [{'blocks': [{'uid': 'bar'}]}]}]})
            self.assertEquals(
                {'default': [{'cols': [{'blocks': []}]}],
                 'portlet': [{'cols': [{'blocks': [{'uid': 'bar'}]}]}]},
                config.load())

            config.store({'default': []})
            self.assertEquals(
                {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]}],
                 'portlet': [{'cols': [{'blocks': [{'uid': 'bar'}]}]}]},
                config.load())

        finally:
            gsm.unregisterAdapter(**adapter_registration_kwargs)
Beispiel #10
0
def move_sl_block_into_slot(old_page, new_page, block, slot_name):
    page_configuration = IPageConfiguration(new_page)
    page_state = page_configuration.load()

    # initiate layout if it is in its initial state
    if slot_name == 'default' and page_state == page_configuration._default_page_config():

        # setup different layouts
        if ISimplelayoutTwoColumnView.providedBy(old_page):
            # two columns
            page_state[slot_name] = [
                {'cols': [ {'blocks': []}, {'blocks': []} ]}
            ]

        elif ISimplelayoutTwoColumnOneOnTopView.providedBy(old_page):
            # two columns and a top row
            page_state[slot_name] = [
                {'cols': [{'blocks': []}]},
                {'cols': [ {'blocks': []}, {'blocks': []} ]}
            ]

    if slot_name not in page_state:
        # normal single column layout
        page_state[slot_name] = [{'cols': [{'blocks': []}]}]

    if slot_name == 'default':
        slot = page_state['default']

        # two column layout
        if ISimplelayoutTwoColumnView.providedBy(old_page):
            if ISlotA.providedBy(block):  # left column
                slot[0]['cols'][0]['blocks'].append({'uid': IUUID(block)})
            elif ISlotB.providedBy(block):  # right column
                slot[0]['cols'][1]['blocks'].append({'uid': IUUID(block)})
            else:
                raise ValueError('Block has unused slot in layout.')

        # two columns and a top row layout
        elif ISimplelayoutTwoColumnOneOnTopView.providedBy(old_page):
            if ISlotA.providedBy(block):  # top row
                slot[0]['cols'][0]['blocks'].append({'uid': IUUID(block)})
            elif ISlotB.providedBy(block):  # bottom row, left column
                slot[1]['cols'][0]['blocks'].append({'uid': IUUID(block)})
            elif ISlotC.providedBy(block):  # bottom row, right column
                slot[1]['cols'][1]['blocks'].append({'uid': IUUID(block)})
            else:
                raise ValueError('Block has unused slot in layout.')

        else:
            slot[0]['cols'][0]['blocks'].append({'uid': IUUID(block)})

    else:
        page_state[slot_name][0]['cols'][0]['blocks'].append({
            'uid': IUUID(block)})

    page_configuration.store(page_state)
    def create_block(self, portlet, manager, type_):

        config = IPageConfiguration(self.new)
        normalizer = getUtility(IFileNameNormalizer).normalize
        if type_ == 'teaser':
            block = create(Builder('sl textblock')
                           .within(self.new)
                           .titled(portlet.teasertitle)
                           .having(text=RichTextValue(portlet.teaserdesc),
                                   image=NamedBlobImage(
                                       filename=normalizer(
                                           portlet.image.filename).decode('utf-8'),
                                       data=portlet.image.data)))

            blockconfig = IBlockConfiguration(block)
            blockconfigdata = blockconfig.load()
            blockconfigdata['scale'] = 'large'
            blockconfigdata['imagefloat'] = 'no-float'
            blockconfig.store(blockconfigdata)

            if portlet.internal_target:
                teaser = ITeaser(block)
                target = uuidToObject(portlet.internal_target)
                if target:
                    intids = getUtility(IIntIds)
                    teaser.internal_link = RelationValue(intids.getId(target))

        elif type_ == 'static':
            block = create(Builder('sl textblock')
                           .within(self.new)
                           .titled(portlet.header)
                           .having(text=RichTextValue(portlet.text)))
        else:
            return

        uid = IUUID(block)

        page_state = config.load()
        if manager == 'ftw.subsite.front1':
            page_state['default'][0]['cols'][0]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front2':
            page_state['default'][0]['cols'][1]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front3':
            page_state['default'][0]['cols'][2]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front4':
            page_state['default'][0]['cols'][3]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front5':
            page_state['default'][1]['cols'][0]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front6':
            page_state['default'][1]['cols'][1]['blocks'].append({'uid': uid})
        # Don't know where manager 7 belongs
        elif manager == 'ftw.subsite.front7':
            page_state['default'][1]['cols'][0]['blocks'].append({'uid': uid})

        config.store(page_state)
Beispiel #12
0
    def create_block(self, portlet, manager, type_):

        config = IPageConfiguration(self.new)
        normalizer = getUtility(IFileNameNormalizer).normalize
        if type_ == 'teaser':
            block = create(
                Builder('sl textblock').within(self.new).titled(
                    portlet.teasertitle).having(
                        text=RichTextValue(portlet.teaserdesc),
                        image=NamedBlobImage(filename=normalizer(
                            portlet.image.filename).decode('utf-8'),
                                             data=portlet.image.data)))

            blockconfig = IBlockConfiguration(block)
            blockconfigdata = blockconfig.load()
            blockconfigdata['scale'] = 'large'
            blockconfigdata['imagefloat'] = 'no-float'
            blockconfig.store(blockconfigdata)

            if portlet.internal_target:
                teaser = ITeaser(block)
                target = uuidToObject(portlet.internal_target)
                if target:
                    intids = getUtility(IIntIds)
                    teaser.internal_link = RelationValue(intids.getId(target))

        elif type_ == 'static':
            block = create(
                Builder('sl textblock').within(self.new).titled(
                    portlet.header).having(text=RichTextValue(portlet.text)))
        else:
            return

        uid = IUUID(block)

        page_state = config.load()
        if manager == 'ftw.subsite.front1':
            page_state['default'][0]['cols'][0]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front2':
            page_state['default'][0]['cols'][1]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front3':
            page_state['default'][0]['cols'][2]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front4':
            page_state['default'][0]['cols'][3]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front5':
            page_state['default'][1]['cols'][0]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front6':
            page_state['default'][1]['cols'][1]['blocks'].append({'uid': uid})
        # Don't know where manager 7 belongs
        elif manager == 'ftw.subsite.front7':
            page_state['default'][1]['cols'][0]['blocks'].append({'uid': uid})

        config.store(page_state)
Beispiel #13
0
    def structure(self):
        """ Render a simplelayout slot by name.
        Name is given by the simplelayout expression.
        """
        page_conf = IPageConfiguration(self.context)
        storage = page_conf.load()
        sl_renderer = SimplelayoutRenderer(self.context,
                                           storage,
                                           self.name,
                                           view=self.view)

        return sl_renderer.render_slot()
Beispiel #14
0
    def _blocks_without_state(self):
        page_conf = IPageConfiguration(self.context)
        saved_blocks = []

        for container in page_conf.load().values():
            for row in container:
                for col in row['cols']:
                    for block in col['blocks']:
                        if 'uid' in block:
                            saved_blocks.append(block['uid'])

        return filter(lambda x: x[0] not in saved_blocks,
                      self._blocks().items())
Beispiel #15
0
    def has_blocks(self):
        config = IPageConfiguration(self.context)
        data = config.load()

        if self.manager.__name__ == 'plone.rightcolumn':
            portlet_container = data.get('portletright', [])
        elif self.manager.__name__ == 'plone.leftcolumn':
            portlet_container = data.get('portletleft', [])

        for layout in portlet_container:
            for columns in layout.values():
                for column in columns:
                    if len(column['blocks']):
                        return True
                    else:
                        continue
        return False
Beispiel #16
0
    def rows(self):
        """ Return datastructure for rendering blocks.
        """
        page_conf = IPageConfiguration(self.context)
        blocks = self._blocks()

        rows = page_conf.load().get(self.name, self.one_layout_one_column)

        user_can_edit = self.user_can_edit()

        for row in rows:
            row['class'] = 'sl-layout'
            for col in row['cols']:
                col['class'] = 'sl-column sl-col-{}'.format(len(row['cols']))
                col['blocks'] = filter(
                    lambda block: block.get('uid', '') in blocks,
                    col['blocks'])

                for block in col['blocks']:
                    obj = blocks[block['uid']]
                    self.create_or_update_block(obj, block)

                # Remove hidden blocks for users not having the permission
                # to edit content.
                col['blocks'] = [
                    block for block in col['blocks']
                    if not block['is_hidden'] or block['is_hidden'] and user_can_edit
                ]

        # Append blocks, which are not in the simplelayout configuration into
        # the last column.

        if self.name == 'default':
            for uid, obj in self._blocks_without_state():
                block = self.create_or_update_block(obj, uid=uid)

                # Skip hidden blocks for users not having the permission
                # to edit content.
                if block['is_hidden'] and not user_can_edit:
                    continue

                rows[-1]['cols'][-1]['blocks'].append(block)

        return rows
    def test_store_partial_updates(self):
        page = create(Builder('sample container'))
        config = IPageConfiguration(page)

        state = {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]},
                             {'cols': [{'blocks': [{'uid': 'bar'}]},
                                       {'blocks': []}]}],
                 'sidebar': [{'cols': [{'blocks': [{'uid': 'baz'},
                                                   {'uid': 'foobar'}]}]}]}
        config.store(state)

        partial_state = {'sidebar': [{'cols': [
            {'blocks': [{'uid': 'baz'}]}]}]}
        config.store(partial_state)

        # Remove block "foobar" from "sidebar" slot
        new_state = {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]},
                                 {'cols': [{'blocks': [{'uid': 'bar'}]},
                                           {'blocks': []}]}],
                     'sidebar': [{'cols': [{'blocks': [{'uid': 'baz'}]}]}]}

        self.assertEquals(new_state, config.load())
Beispiel #18
0
def update_page_state_on_copy_paste_block(block, event):
    """Update the uid of the new created block in the page state.
    block: new block
    event.original: origin of the copy event - usually the simplelayout page"""

    # Only update page state, if the original object is a Simplelayout page.
    if not ISimplelayout.providedBy(event.original):
        return

    # The event is triggered recursively - we need to check if the block is
    # actually part of the original page
    if event.original.get(block.id) is None:
        return

    origin_block_uid = IUUID(event.original.get(block.id))
    page_config = IPageConfiguration(block.aq_parent)
    page_state = unwrap_persistence(page_config.load())

    new_block_uid = IUUID(block)
    new_page_state = json.loads(
        json.dumps(page_state).replace(origin_block_uid,
                                       new_block_uid))

    page_config.store(new_page_state)
class TestSimplelayoutView(SimplelayoutTestCase):

    layer = FTW_SIMPLELAYOUT_FUNCTIONAL_TESTING

    def setUp(self):
        super(TestSimplelayoutView, self).setUp()
        self.setup_sample_ftis(self.layer['portal'])
        self.setup_block_views()
        self.container = create(Builder('sample container'))
        self.page_config = IPageConfiguration(self.container)
        self.url = self.container.absolute_url() + '/@@simplelayout-view'

        self.payload = {
            "default": [
                {
                    "cols": [
                        {
                            "blocks": [
                                {
                                    "uid": "c774b0ca2a5544bf9bb46d865b11bff9"
                                }
                            ]
                        }
                    ]
                },
                {
                    "cols": [
                        {
                            "blocks": [
                                {
                                    "uid": "413fb945952d4403a58ab1958c38f1d2"
                                }
                            ]
                        }
                    ]
                }
            ]
        }

    @browsing
    def test_render_blocks_not_in_page_configuration(self, browser):
        # Fallback for not saved blocks thru the simplelayout JS lib.
        create(Builder('sample block')
               .titled('TextBlock title')
               .within(self.container)
               .having(text=RichTextValue('The text'))
               )

        browser.login().visit(self.container, view='@@simplelayout-view')

        self.assertEqual(browser.url, self.url)
        self.assertEquals('OK',
                          browser.css('.sl-block').first.text)

    @browsing
    def test_invalid_simplelayout_save_state_request(self, browser):
        with browser.expect_http_error(reason='Bad Request'):
            browser.login().visit(self.container,
                                  view='sl-ajax-save-state-view',
                                  data={})

    @browsing
    def test_store_save_simplelayout_state_thru_view(self, browser):
        payload = {"data": json.dumps(self.payload)}

        if IS_PLONE_5:
            from plone.protect.authenticator import createToken
            payload["_authenticator"] = createToken()

        browser.login().visit(self.container,
                              view='sl-ajax-save-state-view',
                              data=payload)

        browser.visit(self.container)
        self.assertEquals(self.payload, self.page_config.load())

    @browsing
    def test_render_blocks_in_different_layouts(self, browser):
        block1 = create(Builder('sample block')
                        .titled('Block 1')
                        .within(self.container))
        block2 = create(Builder('sample block')
                        .titled('Block 1')
                        .within(self.container))

        self.payload['default'][0]['cols'][0][
            'blocks'][0]['uid'] = IUUID(block1)
        self.payload['default'][1]['cols'][0][
            'blocks'][0]['uid'] = IUUID(block2)
        self.page_config.store(self.payload)
        transaction.commit()

        browser.login().visit(self.container)
        self.assertEquals(2,
                          len(browser.css('.sl-layout')),
                          'Expect 2 layouts')

        self.assertEquals(2,
                          len(browser.css('.sl-column.sl-col-1')),
                          'Expect two, one column layouts')

    @browsing
    def test_render_blocks_in_different_columns(self, browser):
        block1 = create(Builder('sample block')
                        .titled('Block 1')
                        .within(self.container))
        block2 = create(Builder('sample block')
                        .titled('Block 1')
                        .within(self.container))

        self.payload['default'][0]['cols'][0][
            'blocks'][0]['uid'] = IUUID(block1)
        self.payload['default'][1]['cols'][0][
            'blocks'][0]['uid'] = IUUID(block2)

        # Move Block into layout 1, column 2
        data_colmn = self.payload['default'][1]['cols'][0]
        self.payload['default'].pop()

        self.payload['default'][0]['cols'].append(data_colmn)
        self.page_config.store(self.payload)
        transaction.commit()

        browser.login().visit(self.container)
        self.assertEquals(2,
                          len(browser.css('.sl-column.sl-col-2')),
                          'Expect 2 columns')

    @browsing
    def test_skips_unavailable_blocks(self, browser):
        # The block may no longer exist or may not be visible for
        # the current user.

        block1 = create(Builder('sample block')
                        .titled('Block 1')
                        .within(self.container))

        self.payload['default'][0]['cols'][0][
            'blocks'][0]['uid'] = IUUID(block1)
        self.payload['default'][1]['cols'][0][
            'blocks'][0]['uid'] = '123xNONxEXISTINGxUIDx123'
        self.page_config.store(self.payload)
        transaction.commit()

        browser.login().visit(self.container)
        self.assertEquals(
            ['http://nohost/plone/samplecontainer/block-1'],
            map(lambda node: node.attrib.get('data-url'),
                browser.css('.sl-block')))

    @browsing
    def test_empty_block_state_does_not_break_the_view(self, browser):
        self.payload['default'][0]['cols'][0]['blocks'].append({})
        self.page_config.store(self.payload)
        transaction.commit()

        browser.login().visit(self.container)
        self.assertTrue(
            browser.css('body.template-simplelayout-view'),
            'Expect to be on the simplelayout template, not the error page.')

    @browsing
    def test_simplelayout_default_config_from_control_panel(self, browser):
        browser.login().visit(self.container, view='@@simplelayout-view')

        registry = getUtility(IRegistry)
        settings = registry.forInterface(ISimplelayoutDefaultSettings)
        settings.slconfig = u'{"layouts": [1, 2]}'
        transaction.commit()

        browser.login().visit(self.container, view='@@simplelayout-view')
        data_attr_value = json.loads(browser.css(
            '[data-sl-settings]').first.attrib['data-sl-settings'])

        self.assertEquals([1, 2],
                          data_attr_value['layouts'],
                          'Expect the layout setting in default config.')

    @browsing
    def test_simplelayout_config_updated_by_permissions(self, browser):

        browser.login().visit(self.container, view='@@simplelayout-view')
        data_attr_value = json.loads(browser.css(
            '[data-sl-settings]').first.attrib['data-sl-settings'])

        self.assertTrue(data_attr_value['canChangeLayout'],
                        'Should have the Change layouts permission.')

        self.container.manage_permission('ftw.simplelayout: Change Layouts',
                                         roles=[],
                                         acquire=0)
        transaction.commit()

        browser.visit(self.container, view='@@simplelayout-view')
        data_attr_value = json.loads(browser.css(
            '[data-sl-settings]').first.attrib['data-sl-settings'])

        self.assertFalse(data_attr_value['canChangeLayout'],
                         'Should NOT have the Change layouts permission.')

    @browsing
    def test_prevent_layout_changes_if_not_allowed(self, browser):

        self.container.manage_permission('ftw.simplelayout: Change Layouts',
                                         roles=[],
                                         acquire=0)
        transaction.commit()

        self.payload['default'].append({'cols': [{}]})
        payload = {"data": json.dumps(self.payload)}
        with browser.expect_unauthorized():
            browser.login().visit(self.container,
                                  view='sl-ajax-save-state-view',
                                  data=payload)

    @browsing
    def test_simplelayout_config_updated_by_adapter(self, browser):

        class ContainerConfigAdapter(object):
            implements(ISimplelayoutContainerConfig)

            def __init__(self, context, request):
                pass

            def __call__(self, settings):
                settings['layouts'] = [1]

            def default_page_layout(self):
                return None

        provideAdapter(ContainerConfigAdapter,
                       adapts=(ISampleSimplelayoutContainer, Interface))
        transaction.commit()

        try:
            browser.login().visit(self.container, view='@@simplelayout-view')
            data_attr_value = json.loads(browser.css(
                '[data-sl-settings]').first.attrib['data-sl-settings'])
            self.assertEquals([1], data_attr_value['layouts'])

        finally:
            # Unregister adapter - since the component registry is not isolatet
            # per test
            sm = getGlobalSiteManager()
            sm.unregisterAdapter(ContainerConfigAdapter,
                                 required=(
                                     ISampleSimplelayoutContainer, Interface),
                                 provided=ISimplelayoutContainerConfig)

    @browsing
    def test_simplelayout_default_page_layouts_by_adapter(self, browser):

        class ContainerConfigAdapter(object):
            implements(ISimplelayoutContainerConfig)

            def __init__(self, context, request):
                pass

            def __call__(self, settings):
                pass

            def default_page_layout(self):
                return {
                    "default": [
                        {"cols": [{"blocks": []},
                                  {"blocks": []}]}
                    ]
                }

        provideAdapter(ContainerConfigAdapter,
                       adapts=(ISampleSimplelayoutContainer, Interface))
        transaction.commit()

        try:
            browser.login().visit(self.container, view='@@simplelayout-view')
            # This should result in one layout with two columns
            self.assertEquals(1, len(browser.css('.sl-layout')))
            self.assertEquals(2, len(browser.css('.sl-column.sl-col-2')))

        finally:
            # Unregister adapter - since the component registry is not isolatet
            # per test
            sm = getGlobalSiteManager()
            sm.unregisterAdapter(ContainerConfigAdapter,
                                 required=(
                                     ISampleSimplelayoutContainer, Interface),
                                 provided=ISimplelayoutContainerConfig)

    @browsing
    def test_simplelayout_config_updated_view(self, browser):

        class CustomSimplelayoutView(SimplelayoutView):
            def update_simplelayout_settings(self, settings):
                settings['layouts'] = [1, 4]

        provideAdapter(CustomSimplelayoutView,
                       adapts=(Interface, Interface),
                       provides=IBrowserView,
                       name='customview')

        browser.login().visit(self.container, view='@@customview')
        data_attr_value = json.loads(browser.css(
            '[data-sl-settings]').first.attrib['data-sl-settings'])
        self.assertEquals([1, 4], data_attr_value['layouts'])

    @browsing
    def test_show_fallback_view_on_block_render_problems(self, browser):
        block = create(Builder('sample block')
                       .titled('TextBlock title')
                       .within(self.container))

        properties = getMultiAdapter((block, block.REQUEST),
                                     IBlockProperties)
        properties.set_view('block_view_broken')

        transaction.commit()

        browser.login().visit(self.container)
        self.assertEquals(
            'The block could not be rendered. Please check the log for '
            'details.',
            browser.css('.sl-block').first.text)

    @browsing
    def test_empty_sl_page_renders_at_least_one_layout(self, browser):
        browser.login().visit(self.container)

        # By default it's a one column layout.
        self.assertEquals(1,
                          len(browser.css('.sl-column.sl-col-1')),
                          'There should be at least a empty one column layout')

    @browsing
    def test_normalized_portal_type_as_css_klass_on_block(self, browser):
        create(Builder('sample block')
               .titled('TextBlock title')
               .within(self.container))
        browser.login().visit(self.container)
        self.assertEquals('sl-block sampleblock',
                          browser.css('.sl-block').first.attrib['class'],
                          'Expect "sample" as css klass on block structure.')

    @browsing
    def test_block_has_anchor(self, browser):
        create(Builder('sample block')
               .titled('Block 1')
               .within(self.container))

        browser.login().open(self.container)
        self.assertEqual(
            'block-1',
            browser.css('.sl-layout a').first.attrib['name']
        )

    @browsing
    def test_canEdit_is_false_if_border_disabled(self, browser):
        browser.login().visit(self.container, data={'disable_border': 1})
        data_attr_value = json.loads(browser.css(
            '[data-sl-settings]').first.attrib['data-sl-settings'])

        self.assertFalse(data_attr_value['canEdit'],
                         'Edit should be disabled if disable_border is there.')

    @browsing
    def test_sl_container_has_sl_edit_css_class(self, browser):
        browser.login().visit(self.container)
        self.assertTrue(len(browser.css('.sl-can-edit')),
                        'Expect the sl-can-edit class on sl-simplelayout.')

    @browsing
    def test_sl_container_no_sl_edi_css_class(self, browser):
        browser.login().visit(self.container, data={'disable_border': 1})
        self.assertFalse(len(browser.css('.sl-can-edit')),
                         'no sl-can-edit class expected.')

    @browsing
    def test_simplelayout_renderer_only_one_layout_of_storage(self, browser):
        storage = self.payload.copy()
        sl_renderer = SimplelayoutRenderer(self.container, storage, 'default')

        browser.parse(sl_renderer.render_layout(index=1))
        self.assertEquals(1, len(browser.css('.sl-layout')),
                          'Expect only one layout')

        browser.parse(sl_renderer.render_layout(index=0))
        self.assertEquals(1, len(browser.css('.sl-layout')),
                          'Expect only one layout')

        browser.parse(sl_renderer.render_layout())
        self.assertEquals(2, len(browser.css('.sl-layout')),
                          'Expect both layouts')

    @browsing
    def test_simplelayout_renderer_raises_ValueError(self, browser):
        storage = self.payload.copy()
        sl_renderer = SimplelayoutRenderer(self.container, storage, 'default')

        with self.assertRaises(ValueError):
            sl_renderer.render_layout(index=4)

    @browsing
    def test_simplelayout_renderer_can_omit_sl_layout_class(self, browser):
        storage = self.payload.copy()
        sl_renderer = SimplelayoutRenderer(self.container, storage, 'default')

        browser.open_html(sl_renderer.render_layout(index=0, is_update=True))
        self.assertEquals(0, len(browser.css('.sl-layout')),
                          'Expect no sl-layout wrapper')
 def test_default_config_is_recursive_persistent(self):
     config = IPageConfiguration(create(Builder('sample container')))
     self.assert_recursive_persistence(config.load())
 def test_config_is_recursive_persistent(self):
     config = IPageConfiguration(create(Builder('sample container')))
     config.store(
         {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]}]}
     )
     self.assert_recursive_persistence(config.load())
 def test_config_is_recursive_persistent(self):
     config = IPageConfiguration(create(Builder("sample container")))
     config.store({"default": [{"cols": [{"blocks": [{"uid": "foo"}]}]}]})
     self.assert_recursive_persistence(config.load())