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())
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)
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)
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)
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)
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()
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())
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
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())
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())