def navtree(self): root = self.navtreeitem(None, None, None, '', None) model = self.navroot # XXX: default child path = node_path(self.model)[len(node_path(model)):] self.fillchildren(model, path, root) return root
def fillchildren(self, model, path, tree): """XXX: consider cone.app.interfaces.INavigationLeaf """ curpath = None if path: curpath = path[0] default_child = None if model.properties.default_child: if not curpath or curpath == model.properties.default_child: default_child = model[model.properties.default_child] if default_child and default_child.properties.hide_if_default: model = default_child default_child = None if path: path = path[1:] if path: curpath = path[0] if default_child: if not curpath: curpath = model.properties.default_child for key in model: node = model[key] if not self.request.has_permission('view', node): continue if not node.properties.get('in_navtree'): continue title = node.metadata.title if title: title = safe_decode(title) url = make_url(self.request, node=node) query = make_query( contenttile=node.properties.default_content_tile) target = make_url(self.request, node=node, query=query) curnode = curpath == safe_decode(key) icon = node_icon(node) css = '' if IWorkflowState.providedBy(node): css = 'state-%s' % node.state child = self.navtreeitem(title, url, target, node_path(node), icon, css) child['showchildren'] = curnode if curnode: child['selected'] = True if default_child: self.fillchildren(default_child, path[1:], child) else: self.fillchildren(node, path[1:], child) else: selected_path = node_path(self.model) if default_child: selected_path.append(default_child.name) selected = False # XXX: probably superfluous. keep as of cone.app 1.1 # if selected_path == node_path(node): # selected = True child['selected'] = selected tree['children'].append(child)
def fillchildren(self, model, path, tree): """XXX: consider cone.app.interfaces.INavigationLeaf """ curpath = None if path: curpath = path[0] default_child = None if model.properties.default_child: if not curpath or curpath == model.properties.default_child: default_child = model[model.properties.default_child] if default_child and default_child.properties.hide_if_default: model = default_child default_child = None if path: path = path[1:] if path: curpath = path[0] if default_child: if not curpath: curpath = model.properties.default_child for key in model: node = model[key] if not self.request.has_permission('view', node): continue if not node.properties.get('in_navtree'): continue title = node.metadata.title if title: title = safe_decode(title) url = make_url(self.request, node=node) query = make_query(contenttile=node.properties.default_content_tile) target = make_url(self.request, node=node, query=query) curnode = curpath == safe_decode(key) icon = node_icon(node) css = '' if IWorkflowState.providedBy(node): css = 'state-%s' % node.state child = self.navtreeitem( title, url, target, node_path(node), icon, css) child['showchildren'] = curnode if curnode: child['selected'] = True if default_child: self.fillchildren(default_child, path[1:], child) else: self.fillchildren(node, path[1:], child) else: selected_path = node_path(self.model) if default_child: selected_path.append(default_child.name) selected = False # XXX: probably superfluous. keep as of cone.app 1.1 # if selected_path == node_path(node): # selected = True child['selected'] = selected tree['children'].append(child)
def menuitems(self): ret = list() path = node_path(self.model) if path: curpath = path[0] else: curpath = '' # work with ``self.model.root.keys()``, ``values()`` propably not works # due to the use of factory node. root = self.model.root root_props = root.properties # check for default child id if no curpath if not curpath and root_props.default_child: curpath = root_props.default_child # check wether to render mainmenu item title empty_title = root_props.mainmenu_empty_title # XXX: icons for key in root.keys(): child = root[key] props = child.properties if self.ignore_node(child, props): continue selected = curpath == key item = self.create_item(child, props, empty_title, selected) if props.mainmenu_display_children: item['children'] = self.create_children(child, selected) else: item['children'] = None ret.append(item) return ret
def vocab(self): ret = list() path = node_path(self.model) count = self.table_tile.item_count slicesize = self.table_tile.slicesize pages = count / slicesize if count % slicesize != 0: pages += 1 current = self.request.params.get('b_page', '0') params = { 'sort': self.table_tile.sort_column, 'order': self.table_tile.sort_order, 'size': slicesize, 'term': self.table_tile.filter_term, } for term in self.table_tile.query_whitelist: params[term] = self.request.params.get(term, '') for i in range(pages): params['b_page'] = str(i) query = make_query(**params) url = make_url( self.request, path=path, #resource=self.related_view, query=query) ret.append({ 'page': '%i' % (i + 1), 'current': current == str(i), 'visible': True, 'url': url, }) return ret
def vocab(self): ret = list() path = node_path(self.model) count = self.table_tile.item_count slicesize = self.table_tile.slicesize pages = count // slicesize if count % slicesize != 0: pages += 1 current = self.request.params.get('b_page', '0') params = { 'sort': self.table_tile.sort_column, 'order': self.table_tile.sort_order, 'size': slicesize, 'term': self.table_tile.filter_term, } for term in self.table_tile.query_whitelist: params[term] = self.request.params.get(term, '') for i in range(pages): params['b_page'] = str(i) query = make_query(**params) url = make_url( self.request, path=path, # resource=self.related_view, query=query ) ret.append({ 'page': '%i' % (i + 1), 'current': current == str(i), 'visible': True, 'url': url, }) return ret
def vocab(self): ret = list() path = node_path(self.model) current = self.request.params.get('b_page', '0') for i in range(10): query = make_query(b_page=str(i)) url = make_url(self.request, path=path, query=query) ret.append({ 'page': '%i' % i, 'current': current == str(i), 'visible': True, 'url': url }) return ret
def create_children(self, node, selected): children = list() path = node_path(self.model) if path and len(path) > 1 and path[0] == node.name: curpath = path[1] else: curpath = '' for key in node.keys(): child = node[key] props = child.properties if self.ignore_node(child, props): continue selected = curpath == key item = self.create_item(child, props, False, selected) children.append(item) return children
def vocab(self): ret = list() path = node_path(self.model) current = self.request.params.get('b_page', '0') for i in range(10): query = make_query(b_page=str(i)) href = make_url(self.request, path=path, resource='someview', query=query) target = make_url(self.request, path=path, query=query) ret.append({ 'page': '%i' % i, 'current': current == str(i), 'visible': True, 'href': href, 'target': target, }) return ret
def vocab(self): ret = list() path = node_path(self.model) current = self.request.params.get('b_page', '0') for i in range(10): query = make_query(b_page=str(i)) href = make_url( self.request, path=path, resource='someview', query=query ) target = make_url(self.request, path=path, query=query) ret.append({ 'page': '%i' % i, 'current': current == str(i), 'visible': True, 'href': href, 'target': target, }) return ret
def vocab(self): """Batch vocabulary. """ ret = list() path = node_path(self.model) count = self.parent.item_count slice_size = self.parent.slice_size pages = count / slice_size if count % slice_size != 0: pages += 1 current = self.parent.current_page for i in range(pages): href = self.parent.make_page_url(path, str(i), include_view=True) target = self.parent.make_page_url(path, str(i)) ret.append({ 'page': '%i' % (i + 1), 'current': current == i, 'visible': True, 'href': href, 'target': target }) return ret
def vocab(self): """Batch vocabulary. """ ret = list() path = node_path(self.model) count = self.parent.item_count slice_size = self.parent.slice_size pages = count // slice_size if count % slice_size != 0: pages += 1 current = self.parent.current_page for i in range(pages): href = self.parent.make_page_url(path, str(i), include_view=True) target = self.parent.make_page_url(path, str(i)) ret.append({ 'page': '%i' % (i + 1), 'current': current == i, 'visible': True, 'href': href, 'target': target }) return ret
def next(self, request): """Read ``came_from`` parameter from request and compute next URL. If ``came_from`` not found on request, ``default_came_from`` property is used. If ``came_from`` is special value ``parent``, URL of model parent is computed. If ``came_from`` is set, it is considered as URL to use. The given URL must match the basic application URL, otherwise an error gets logged and URL of current model is computed. If ``came_from`` is set to empty value, URL of current model is computed. """ # read came_from from request came_from = request.get('came_from') # fall back to default_came_from if came_from not passed on request if came_from is None: came_from = self.default_came_from # use model URL and path if no came_from if not came_from: url = make_url(request.request, node=self.model) path = '/'.join(node_path(self.model)) # use model parent URL and path if came_from is 'parent' elif came_from == 'parent': url = make_url(request.request, node=self.model.parent) path = '/'.join(node_path(self.model.parent)) # consider came_from a URL else: url = compat.unquote(came_from) parsed = compat.urlparse.urlparse(url) app_loc = compat.urlparse.urlparse( self.request.application_url).netloc # behave as if no came_from given if application location not # matches came_from location if app_loc != parsed.netloc: logger.error( ('CameFromNext.next(): Application location "{}" does not ' 'match came_from location "{}". Use model for URL ' 'computing instead').format(app_loc, parsed.netloc)) url = make_url(request.request, node=self.model) path = '/'.join(node_path(self.model)) # include query to path elif parsed.query: path = '{}?{}'.format(parsed.path, parsed.query) # query without path else: path = '{}'.format(parsed.path) # ajax continuation definitions if ajax request if self.ajax_request: event = AjaxEvent(url, 'contextchanged', '#layout') # return continuation path and event if browser history should be # written if self.write_history_on_next: cpath = AjaxPath(path, target=url, event='contextchanged:#layout') return [cpath, event] # return event only if writing browser history should be skipped return [event] # regular redirection if no ajax request return HTTPFound(location=url)
def test_BatchedItems(self): # Concrete ``BatchedItems`` implementation. class MyBatchedItems(BatchedItems): slice_template = 'cone.app.testing:dummy_batched_items.pt' @property def item_count(self): return len(self.filtered_items) @property def slice_items(self): start, end = self.current_slice return self.filtered_items[start:end] @property def filtered_items(self): items = list() term = self.filter_term term = term.lower() if term else term for node in self.model.values(): if term and node.name.find(term) == -1: continue items.append(node) return items # Create model model = BaseNode(name='container') for i in range(35): model['child_{}'.format(i)] = BaseNode() # Create batched items with model batched_items = MyBatchedItems() batched_items.model = model batched_items.request = self.layer.new_request() # The helper function ``make_query`` considers ``query_whitelist`` and # is used for query creation within batched items implementation. self.assertEqual(batched_items.query_whitelist, []) batched_items.query_whitelist = ['a', 'b'] batched_items.request.params['a'] = 'a' self.assertEqual(batched_items.make_query({'c': 'c'}), '?a=a&b=&c=c') # A query parameter which already exists on request gets overwritten self.assertEqual(batched_items.make_query({'a': 'b'}), '?a=b&b=') # The helper function ``make_url`` uses ``make_query``, thus considers # ``query_whitelist`` as well and is used for URL creation within # batched items implementation. self.assertEqual( batched_items.make_url(dict(c='c')), u'http://example.com/container?a=a&b=&c=c' ) # It's also possible to pass a model path to ``make_url`` to avoid # multiple computing of model path path = node_path(model) self.assertEqual( batched_items.make_url(dict(c='c'), path=path), u'http://example.com/container?a=a&b=&c=c' ) # ``BatchedItems`` plumbs ``RelatedViewConsumer`` and considers # ``related_view`` if ``include_view`` passed to ``make_url`` request = batched_items.request = self.layer.new_request() set_related_view(request, 'someview') self.assertEqual( batched_items.make_url(dict(c='c')), u'http://example.com/container?a=&b=&c=c' ) self.assertEqual( batched_items.make_url(dict(c='c'), include_view=True), u'http://example.com/container/someview?a=&b=&c=c' ) self.assertEqual( batched_items.make_url(dict(c='c'), path=path), u'http://example.com/container?a=&b=&c=c' ) self.assertEqual( batched_items.make_url(dict(c='c'), path=path, include_view=True), u'http://example.com/container/someview?a=&b=&c=c' ) # Default slice size self.assertEqual(batched_items.default_slice_size, 15) # Current slice size self.assertEqual(batched_items.slice_size, 15) # Number of available slice slizes self.assertEqual(batched_items.num_slice_sizes, 4) # Available slice sizes for slice size selection self.assertEqual(batched_items.slice_sizes, [15, 30, 45, 60]) batched_items.default_slice_size = 10 batched_items.num_slice_sizes = 5 self.assertEqual(batched_items.slice_sizes, [10, 20, 30, 40, 50]) batched_items.default_slice_size = 15 batched_items.num_slice_sizes = 4 # Test ``slice_target`` self.assertEqual(batched_items.query_whitelist, ['a', 'b']) request = batched_items.request = self.layer.new_request() request.params['a'] = 'a' request.params['b'] = 'b' request.params['term'] = 'Hello' self.assertEqual(batched_items.filter_term, u'Hello') self.assertEqual( batched_items.slice_target, u'http://example.com/container?a=a&b=b&term=Hello' ) # Test ``filter_target`` self.assertEqual( batched_items.filter_target, u'http://example.com/container?a=a&b=b&size=15' ) request.params['size'] = '30' self.assertEqual( batched_items.filter_target, u'http://example.com/container?a=a&b=b&size=30' ) # Header template path self.assertEqual( batched_items.header_template, 'cone.app.browser:templates/batched_items_header.pt' ) # Rendered header self.checkOutput(""" ...<div class="panel-heading batched_items_header">... """, batched_items.rendered_header) # Header title. Taken from ``model.metadata`` by default self.assertEqual(batched_items.title, 'container') # Title can be skipped by setting ``show_title`` to False expected = '<span class="label label-primary">container</span>' self.assertTrue(batched_items.rendered_header.find(expected) > -1) batched_items.show_title = False self.assertFalse(batched_items.rendered_header.find(expected) > -1) batched_items.show_title = True # Slice size can be skipped by setting ``show_slice_size`` to False expected = '<select name="size"' self.assertTrue(batched_items.rendered_header.find(expected) > -1) batched_items.show_slice_size = False self.assertFalse(batched_items.rendered_header.find(expected) > -1) batched_items.show_slice_size = True # CSS class set on slice size selection wrapper expected = 'col-xs-4 col-sm3' self.assertTrue(batched_items.rendered_header.find(expected) > -1) batched_items.slice_size_css = 'col-xs-3 col-sm2' self.assertFalse(batched_items.rendered_header.find(expected) > -1) batched_items.slice_size_css = 'col-xs-4 col-sm3' # Flag whether to show search filter expected = '<input name="term"' self.assertTrue(batched_items.rendered_header.find(expected) > -1) batched_items.show_filter = False self.assertFalse(batched_items.rendered_header.find(expected) > -1) batched_items.show_filter = True # CSS class set on slice search filter expected = 'col-xs-3' self.assertTrue(batched_items.rendered_header.find(expected) > -1) batched_items.filter_css = 'col-xs-4' self.assertFalse(batched_items.rendered_header.find(expected) > -1) batched_items.filter_css = 'col-xs-3' # Additional markup displayed in header expected = '<div class="additional">Additional</div>' self.assertFalse(batched_items.rendered_header.find(expected) > -1) batched_items.head_additional = expected self.assertTrue(batched_items.rendered_header.find(expected) > -1) batched_items.head_additional = None # Batched items pagination. Pagination object is provided by # ``pagination`` property on ``BatchedItems`` request = self.layer.new_request() set_related_view(request, 'someview') batched_items = MyBatchedItems() batched_items.model = BaseNode(name='container') batched_items.request = request pagination = batched_items.pagination self.assertTrue(isinstance(pagination, BatchedItemsBatch)) pagination.model = batched_items.model pagination.request = batched_items.request # Pagination batch uses ``page_target`` on ``BatchedItems`` for target # URL computing. path = node_path(batched_items.model) page = '1' self.assertEqual( batched_items.page_target(path, page), u'http://example.com/container?b_page=1&size=15' ) # Pagination batch name is created from batched items ``items_id`` self.assertEqual(batched_items.items_id, 'batched_items') self.assertEqual(pagination.name, 'batched_itemsbatch') # Pagination batch only gets displayed if there are batched items. self.assertEqual(batched_items.item_count, 0) self.assertFalse(pagination.display) self.assertEqual(pagination.vocab, []) batched_items.model = pagination.model = model self.assertEqual(batched_items.item_count, 35) self.assertTrue(pagination.display) self.assertEqual(batched_items.current_page, 0) request.params['b_page'] = '1' self.assertEqual(batched_items.current_page, 1) vocab = pagination.vocab self.assertEqual(len(vocab), 3) self.assertEqual(sorted(vocab[0].items()), [ ('current', False), ('href', u'http://example.com/container/someview?b_page=0&size=15'), ('page', '1'), ('target', u'http://example.com/container?b_page=0&size=15'), ('visible', True) ]) self.assertEqual(sorted(vocab[1].items()), [ ('current', True), ('href', u'http://example.com/container/someview?b_page=1&size=15'), ('page', '2'), ('target', u'http://example.com/container?b_page=1&size=15'), ('visible', True) ]) self.assertEqual(sorted(vocab[2].items()), [ ('current', False), ('href', u'http://example.com/container/someview?b_page=2&size=15'), ('page', '3'), ('target', u'http://example.com/container?b_page=2&size=15'), ('visible', True) ]) # Rendered pagination self.checkOutput(""" ...<ul class="pagination pagination-sm">... """, batched_items.rendered_pagination) # Batched items footer batched_items = MyBatchedItems() batched_items.model = model batched_items.request = self.layer.new_request() # Default template path self.assertEqual( batched_items.footer_template, 'cone.app.browser:templates/batched_items_footer.pt' ) self.checkOutput(""" ...<div class="panel-footer batched_items_footer">... """, batched_items.rendered_footer) # Slice ID self.assertEqual(batched_items.slice_id, 'batched_items_slice') # Current slice to display as tuple self.assertEqual(batched_items.current_slice, (0, 15)) # Overall item count self.assertEqual(batched_items.item_count, 35) # Current slice items self.checkOutput(""" [<BaseNode object 'child_0' at ...>, ... <BaseNode object 'child_14' at ...>] """, str(batched_items.slice_items)) # Chage current page and check again request = batched_items.request = self.layer.new_request() request.params['b_page'] = '1' self.assertEqual(batched_items.current_slice, (15, 30)) self.checkOutput(""" [<BaseNode object 'child_15' at ...>, ... <BaseNode object 'child_29' at ...>] """, str(batched_items.slice_items)) # Change the slice size request = batched_items.request = self.layer.new_request() request.params['size'] = '10' self.assertEqual(batched_items.slice_size, 10) self.assertEqual(batched_items.current_slice, (0, 10)) self.checkOutput(""" [<BaseNode object 'child_0' at ...>, ... <BaseNode object 'child_9' at ...>] """, str(batched_items.slice_items)) # Change the filter term request = batched_items.request = self.layer.new_request() request.params['term'] = '1' request.params['size'] = '5' self.assertEqual(batched_items.filter_term, u'1') self.checkOutput(""" [<BaseNode object 'child_1' at ...>, <BaseNode object 'child_10' at ...>, <BaseNode object 'child_11' at ...>, <BaseNode object 'child_12' at ...>, <BaseNode object 'child_13' at ...>, <BaseNode object 'child_14' at ...>, <BaseNode object 'child_15' at ...>, <BaseNode object 'child_16' at ...>, <BaseNode object 'child_17' at ...>, <BaseNode object 'child_18' at ...>, <BaseNode object 'child_19' at ...>, <BaseNode object 'child_21' at ...>, <BaseNode object 'child_31' at ...>] """, str(batched_items.filtered_items)) self.assertEqual(batched_items.current_slice, (0, 5)) self.checkOutput(""" [<BaseNode object 'child_1' at ...>, <BaseNode object 'child_10' at ...>, <BaseNode object 'child_11' at ...>, <BaseNode object 'child_12' at ...>, <BaseNode object 'child_13' at ...>] """, str(batched_items.slice_items)) request.params['b_page'] = '1' self.assertEqual(batched_items.current_slice, (5, 10)) self.checkOutput(""" [<BaseNode object 'child_14' at ...>, <BaseNode object 'child_15' at ...>, <BaseNode object 'child_16' at ...>, <BaseNode object 'child_17' at ...>, <BaseNode object 'child_18' at ...>] """, str(batched_items.slice_items)) # Test ``rendered_slice`` request = batched_items.request = self.layer.new_request() self.checkOutput(""" <div id="batched_items_slice"> <div>child_0</div> ... <div>child_14</div> </div> """, batched_items.rendered_slice) # ``BatchItems`` rendering default template self.assertEqual( batched_items.path, 'cone.app.browser:templates/batched_items.pt' ) # Batched items DOM element ID. Used for bdajax binding. self.assertEqual(batched_items.items_id, 'batched_items') self.checkOutput(""" ...<div id="batched_items"... """, batched_items(model=model, request=self.layer.new_request())) batched_items.items_id = 'my_batched_items' self.checkOutput(""" ...<div id="my_batched_items"... """, batched_items(model=model, request=self.layer.new_request())) batched_items.items_id = 'batched_items' # Test ``items_css`` self.assertEqual( batched_items.items_css, 'batched_items panel panel-default' ) self.checkOutput(""" ...class="...batched_items ... """, batched_items(model=model, request=self.layer.new_request())) batched_items.items_css = ( 'my_batched_items batched_items panel panel-default' ) self.checkOutput(""" ...class="...my_batched_items batched_items ... """, batched_items(model=model, request=self.layer.new_request())) batched_items.items_css = 'batched_items panel panel-default' # Test ``bind_events`` self.assertEqual(batched_items.bind_events, 'batchclicked') self.checkOutput(""" ...ajax:bind="batchclicked"... """, batched_items(model=model, request=self.layer.new_request())) # Test ``bind_selectors`` self.assertEqual( batched_items.bind_selectors, 'batched_itemsbatchsensitiv' ) self.checkOutput(""" ...class="batched_itemsbatchsensitiv... """, batched_items(model=model, request=self.layer.new_request())) # Test ``display_header`` self.assertTrue(batched_items.display_header) expected = '<div class="panel-heading batched_items_header">' rendered = batched_items(model=model, request=self.layer.new_request()) self.assertTrue(rendered.find(expected) > -1) batched_items.display_header = False rendered = batched_items(model=model, request=self.layer.new_request()) self.assertFalse(rendered.find(expected) > -1) batched_items.display_header = True # Test ``display_footer`` self.assertTrue(batched_items.display_header) expected = '<div class="panel-footer batched_items_footer">' rendered = batched_items(model=model, request=self.layer.new_request()) self.assertTrue(rendered.find(expected) > -1) batched_items.display_footer = False rendered = batched_items(model=model, request=self.layer.new_request()) self.assertFalse(rendered.find(expected) > -1)
def next(self, request): """Read ``came_from`` parameter from request and compute next URL. If ``came_from`` not found on request, ``default_came_from`` property is used. If ``came_from`` is special value ``parent``, URL of model parent is computed. If ``came_from`` is set, it is considered as URL to use. The given URL must match the basic application URL, otherwise an error gets logged and URL of current model is computed. If ``came_from`` is set to empty value, URL of current model is computed. """ # read came_from from request came_from = request.get('came_from') # fall back to default_came_from if came_from not passed on request if came_from is None: came_from = self.default_came_from # use model URL and path if no came_from if not came_from: url = make_url(request.request, node=self.model) path = '/'.join(node_path(self.model)) # use model parent URL and path if came_from is 'parent' elif came_from == 'parent': url = make_url(request.request, node=self.model.parent) path = '/'.join(node_path(self.model.parent)) # consider came_from a URL else: url = compat.unquote(came_from) parsed = compat.urlparse.urlparse(url) app_loc = compat.urlparse.urlparse( self.request.application_url ).netloc # behave as if no came_from given if application location not # matches came_from location if app_loc != parsed.netloc: logger.error(( 'CameFromNext.next(): Application location "{}" does not ' 'match came_from location "{}". Use model for URL ' 'computing instead' ).format(app_loc, parsed.netloc)) url = make_url(request.request, node=self.model) path = '/'.join(node_path(self.model)) # include query to path elif parsed.query: path = '{}?{}'.format(parsed.path, parsed.query) # query without path else: path = '{}'.format(parsed.path) # ajax continuation definitions if ajax request if self.ajax_request: event = AjaxEvent(url, 'contextchanged', '#layout') # return continuation path and event if browser history should be # written if self.write_history_on_next: cpath = AjaxPath( path, target=url, event='contextchanged:#layout' ) return [cpath, event] # return event only if writing browser history should be skipped return [event] # regular redirection if no ajax request return HTTPFound(location=url)
def test_BatchedItems(self): # Concrete ``BatchedItems`` implementation. class MyBatchedItems(BatchedItems): slice_template = 'cone.app.testing:dummy_batched_items.pt' @property def item_count(self): return len(self.filtered_items) @property def slice_items(self): start, end = self.current_slice return self.filtered_items[start:end] @property def filtered_items(self): items = list() term = self.filter_term term = term.lower() if term else term for node in self.model.values(): if term and node.name.find(term) == -1: continue items.append(node) return items # Create model model = BaseNode(name='container') for i in range(35): model['child_{}'.format(i)] = BaseNode() # Create batched items with model batched_items = MyBatchedItems() batched_items.model = model batched_items.request = self.layer.new_request() # The helper function ``make_query`` considers ``query_whitelist`` and # is used for query creation within batched items implementation. self.assertEqual(batched_items.query_whitelist, []) batched_items.query_whitelist = ['a', 'b'] batched_items.request.params['a'] = 'a' self.assertEqual(batched_items.make_query({'c': 'c'}), '?a=a&b=&c=c') # A query parameter which already exists on request gets overwritten self.assertEqual(batched_items.make_query({'a': 'b'}), '?a=b&b=') # The helper function ``make_url`` uses ``make_query``, thus considers # ``query_whitelist`` as well and is used for URL creation within # batched items implementation. self.assertEqual(batched_items.make_url(dict(c='c')), u'http://example.com/container?a=a&b=&c=c') # It's also possible to pass a model path to ``make_url`` to avoid # multiple computing of model path path = node_path(model) self.assertEqual(batched_items.make_url(dict(c='c'), path=path), u'http://example.com/container?a=a&b=&c=c') # ``BatchedItems`` plumbs ``RelatedViewConsumer`` and considers # ``related_view`` if ``include_view`` passed to ``make_url`` request = batched_items.request = self.layer.new_request() set_related_view(request, 'someview') self.assertEqual(batched_items.make_url(dict(c='c')), u'http://example.com/container?a=&b=&c=c') self.assertEqual( batched_items.make_url(dict(c='c'), include_view=True), u'http://example.com/container/someview?a=&b=&c=c') self.assertEqual(batched_items.make_url(dict(c='c'), path=path), u'http://example.com/container?a=&b=&c=c') self.assertEqual( batched_items.make_url(dict(c='c'), path=path, include_view=True), u'http://example.com/container/someview?a=&b=&c=c') # Default slice size self.assertEqual(batched_items.default_slice_size, 15) # Current slice size self.assertEqual(batched_items.slice_size, 15) # Number of available slice slizes self.assertEqual(batched_items.num_slice_sizes, 4) # Available slice sizes for slice size selection self.assertEqual(batched_items.slice_sizes, [15, 30, 45, 60]) batched_items.default_slice_size = 10 batched_items.num_slice_sizes = 5 self.assertEqual(batched_items.slice_sizes, [10, 20, 30, 40, 50]) batched_items.default_slice_size = 15 batched_items.num_slice_sizes = 4 # Test ``slice_target`` self.assertEqual(batched_items.query_whitelist, ['a', 'b']) request = batched_items.request = self.layer.new_request() request.params['a'] = 'a' request.params['b'] = 'b' request.params['term'] = 'Hello' self.assertEqual(batched_items.filter_term, u'Hello') self.assertEqual(batched_items.slice_target, u'http://example.com/container?a=a&b=b&term=Hello') # Test ``filter_target`` self.assertEqual(batched_items.filter_target, u'http://example.com/container?a=a&b=b&size=15') request.params['size'] = '30' self.assertEqual(batched_items.filter_target, u'http://example.com/container?a=a&b=b&size=30') # Header template path self.assertEqual(batched_items.header_template, 'cone.app.browser:templates/batched_items_header.pt') # Rendered header self.checkOutput( """ ...<div class="panel-heading batched_items_header">... """, batched_items.rendered_header) # Header title. Taken from ``model.metadata`` by default self.assertEqual(batched_items.title, 'container') # Title can be skipped by setting ``show_title`` to False expected = '<span class="label label-primary">container</span>' self.assertTrue(batched_items.rendered_header.find(expected) > -1) batched_items.show_title = False self.assertFalse(batched_items.rendered_header.find(expected) > -1) batched_items.show_title = True # Slice size can be skipped by setting ``show_slice_size`` to False expected = '<select name="size"' self.assertTrue(batched_items.rendered_header.find(expected) > -1) batched_items.show_slice_size = False self.assertFalse(batched_items.rendered_header.find(expected) > -1) batched_items.show_slice_size = True # CSS class set on slice size selection wrapper expected = 'col-xs-4 col-sm3' self.assertTrue(batched_items.rendered_header.find(expected) > -1) batched_items.slice_size_css = 'col-xs-3 col-sm2' self.assertFalse(batched_items.rendered_header.find(expected) > -1) batched_items.slice_size_css = 'col-xs-4 col-sm3' # Flag whether to show search filter expected = '<input name="term"' self.assertTrue(batched_items.rendered_header.find(expected) > -1) batched_items.show_filter = False self.assertFalse(batched_items.rendered_header.find(expected) > -1) batched_items.show_filter = True # CSS class set on slice search filter expected = 'col-xs-3' self.assertTrue(batched_items.rendered_header.find(expected) > -1) batched_items.filter_css = 'col-xs-4' self.assertFalse(batched_items.rendered_header.find(expected) > -1) batched_items.filter_css = 'col-xs-3' # Additional markup displayed in header expected = '<div class="additional">Additional</div>' self.assertFalse(batched_items.rendered_header.find(expected) > -1) batched_items.head_additional = expected self.assertTrue(batched_items.rendered_header.find(expected) > -1) batched_items.head_additional = None # Batched items pagination. Pagination object is provided by # ``pagination`` property on ``BatchedItems`` request = self.layer.new_request() set_related_view(request, 'someview') batched_items = MyBatchedItems() batched_items.model = BaseNode(name='container') batched_items.request = request pagination = batched_items.pagination self.assertTrue(isinstance(pagination, BatchedItemsBatch)) pagination.model = batched_items.model pagination.request = batched_items.request # Pagination batch uses ``page_target`` on ``BatchedItems`` for target # URL computing. path = node_path(batched_items.model) page = '1' self.assertEqual(batched_items.page_target(path, page), u'http://example.com/container?b_page=1&size=15') # Pagination batch name is created from batched items ``items_id`` self.assertEqual(batched_items.items_id, 'batched_items') self.assertEqual(pagination.name, 'batched_itemsbatch') # Pagination batch only gets displayed if there are batched items. self.assertEqual(batched_items.item_count, 0) self.assertFalse(pagination.display) self.assertEqual(pagination.vocab, []) batched_items.model = pagination.model = model self.assertEqual(batched_items.item_count, 35) self.assertTrue(pagination.display) self.assertEqual(batched_items.current_page, 0) request.params['b_page'] = '1' self.assertEqual(batched_items.current_page, 1) vocab = pagination.vocab self.assertEqual(len(vocab), 3) self.assertEqual( sorted(vocab[0].items()), [('current', False), ('href', u'http://example.com/container/someview?b_page=0&size=15'), ('page', '1'), ('target', u'http://example.com/container?b_page=0&size=15'), ('visible', True)]) self.assertEqual( sorted(vocab[1].items()), [('current', True), ('href', u'http://example.com/container/someview?b_page=1&size=15'), ('page', '2'), ('target', u'http://example.com/container?b_page=1&size=15'), ('visible', True)]) self.assertEqual( sorted(vocab[2].items()), [('current', False), ('href', u'http://example.com/container/someview?b_page=2&size=15'), ('page', '3'), ('target', u'http://example.com/container?b_page=2&size=15'), ('visible', True)]) # Rendered pagination self.checkOutput( """ ...<ul class="pagination pagination-sm">... """, batched_items.rendered_pagination) # Batched items footer batched_items = MyBatchedItems() batched_items.model = model batched_items.request = self.layer.new_request() # Default template path self.assertEqual(batched_items.footer_template, 'cone.app.browser:templates/batched_items_footer.pt') self.checkOutput( """ ...<div class="panel-footer batched_items_footer">... """, batched_items.rendered_footer) # Slice ID self.assertEqual(batched_items.slice_id, 'batched_items_slice') # Current slice to display as tuple self.assertEqual(batched_items.current_slice, (0, 15)) # Overall item count self.assertEqual(batched_items.item_count, 35) # Current slice items self.checkOutput( """ [<BaseNode object 'child_0' at ...>, ... <BaseNode object 'child_14' at ...>] """, str(batched_items.slice_items)) # Chage current page and check again request = batched_items.request = self.layer.new_request() request.params['b_page'] = '1' self.assertEqual(batched_items.current_slice, (15, 30)) self.checkOutput( """ [<BaseNode object 'child_15' at ...>, ... <BaseNode object 'child_29' at ...>] """, str(batched_items.slice_items)) # Change the slice size request = batched_items.request = self.layer.new_request() request.params['size'] = '10' self.assertEqual(batched_items.slice_size, 10) self.assertEqual(batched_items.current_slice, (0, 10)) self.checkOutput( """ [<BaseNode object 'child_0' at ...>, ... <BaseNode object 'child_9' at ...>] """, str(batched_items.slice_items)) # Change the filter term request = batched_items.request = self.layer.new_request() request.params['term'] = '1' request.params['size'] = '5' self.assertEqual(batched_items.filter_term, u'1') self.checkOutput( """ [<BaseNode object 'child_1' at ...>, <BaseNode object 'child_10' at ...>, <BaseNode object 'child_11' at ...>, <BaseNode object 'child_12' at ...>, <BaseNode object 'child_13' at ...>, <BaseNode object 'child_14' at ...>, <BaseNode object 'child_15' at ...>, <BaseNode object 'child_16' at ...>, <BaseNode object 'child_17' at ...>, <BaseNode object 'child_18' at ...>, <BaseNode object 'child_19' at ...>, <BaseNode object 'child_21' at ...>, <BaseNode object 'child_31' at ...>] """, str(batched_items.filtered_items)) self.assertEqual(batched_items.current_slice, (0, 5)) self.checkOutput( """ [<BaseNode object 'child_1' at ...>, <BaseNode object 'child_10' at ...>, <BaseNode object 'child_11' at ...>, <BaseNode object 'child_12' at ...>, <BaseNode object 'child_13' at ...>] """, str(batched_items.slice_items)) request.params['b_page'] = '1' self.assertEqual(batched_items.current_slice, (5, 10)) self.checkOutput( """ [<BaseNode object 'child_14' at ...>, <BaseNode object 'child_15' at ...>, <BaseNode object 'child_16' at ...>, <BaseNode object 'child_17' at ...>, <BaseNode object 'child_18' at ...>] """, str(batched_items.slice_items)) # Test ``rendered_slice`` request = batched_items.request = self.layer.new_request() self.checkOutput( """ <div id="batched_items_slice"> <div>child_0</div> ... <div>child_14</div> </div> """, batched_items.rendered_slice) # ``BatchItems`` rendering default template self.assertEqual(batched_items.path, 'cone.app.browser:templates/batched_items.pt') # Batched items DOM element ID. Used for bdajax binding. self.assertEqual(batched_items.items_id, 'batched_items') self.checkOutput( """ ...<div id="batched_items"... """, batched_items(model=model, request=self.layer.new_request())) batched_items.items_id = 'my_batched_items' self.checkOutput( """ ...<div id="my_batched_items"... """, batched_items(model=model, request=self.layer.new_request())) batched_items.items_id = 'batched_items' # Test ``items_css`` self.assertEqual(batched_items.items_css, 'batched_items panel panel-default') self.checkOutput( """ ...class="...batched_items ... """, batched_items(model=model, request=self.layer.new_request())) batched_items.items_css = ( 'my_batched_items batched_items panel panel-default') self.checkOutput( """ ...class="...my_batched_items batched_items ... """, batched_items(model=model, request=self.layer.new_request())) batched_items.items_css = 'batched_items panel panel-default' # Test ``bind_events`` self.assertEqual(batched_items.bind_events, 'batchclicked') self.checkOutput( """ ...ajax:bind="batchclicked"... """, batched_items(model=model, request=self.layer.new_request())) # Test ``bind_selectors`` self.assertEqual(batched_items.bind_selectors, 'batched_itemsbatchsensitiv') self.checkOutput( """ ...class="batched_itemsbatchsensitiv... """, batched_items(model=model, request=self.layer.new_request())) # Test ``display_header`` self.assertTrue(batched_items.display_header) expected = '<div class="panel-heading batched_items_header">' rendered = batched_items(model=model, request=self.layer.new_request()) self.assertTrue(rendered.find(expected) > -1) batched_items.display_header = False rendered = batched_items(model=model, request=self.layer.new_request()) self.assertFalse(rendered.find(expected) > -1) batched_items.display_header = True # Test ``display_footer`` self.assertTrue(batched_items.display_header) expected = '<div class="panel-footer batched_items_footer">' rendered = batched_items(model=model, request=self.layer.new_request()) self.assertTrue(rendered.find(expected) > -1) batched_items.display_footer = False rendered = batched_items(model=model, request=self.layer.new_request()) self.assertFalse(rendered.find(expected) > -1)
def test_node_path(self): root = BaseNode() root['child'] = BaseNode() self.assertEqual(node_path(root['child']), [u'child'])