The following sections explain the tiles shipped with this package. Some of
them are abstract and can be used as base classes for custom tiles, while
others are already registered and ready to be used.
Main layout related
Livesearch
Tile registration name: livesearch
Renders the live search widget. Cone provides a serverside livesearch
JSON
view, which is expecting an ILiveSearch
implementing adapter for model
node in order to get a reasonable result.
from cone.app.interfaces import IApplicationNode
from cone.app.interfaces import ILiveSearch
from zope.component import adapter
from zope.interface import implementer
@implementer(ILiveSearch)
@adapter(IApplicationNode)
class LiveSearch(object):
def __init__(self, model):
self.model = model
def search(self, request, query):
return [{
'value': 'Example',
'target': 'https://example.com/example',
'icon': 'ion-ios7-gear'
}]
Another option to implement serverside search logic is to overwrite the
livesearch
JSON view.
from pyramid.view import view_config
@view_config(
name='livesearch',
context=IApplicationNode,
accept='application/json',
renderer='json')
def livesearch(model, request):
query = request.params['term']
return [{
'value': 'Example',
'target': 'https://example.com/example',
'icon': 'ion-ios7-gear'
}]
cone.app
uses typeahead.js
on the client side for the livesearch implementation. Since cone makes no
assumptions about what should happen with the livesearch results, a plugin
must provide some JS handling it. Cone not even makes assumptions about the
format of the received suggestions from the server. This is all up to the
integration. The following example renders suggestions with icon and value
text. When suggestion gets clicked, layout rendering is triggered on target
URL.
Note
The example binds to typeahead:selected
event. For a complete list of
available custom typeahead events, look at the
typeahead documentation.
(function($) {
$(document).ready(function() {
bdajax.register(example.binder.bind(example), true);
});
example = {
binder: function(context) {
var input = $('input#search-text', context);
var event = 'typeahead:selected';
input.off(event).on(event, function(e, suggestion, dataset) {
// trigger layout rendering on target URL
bdajax.trigger(
'contextchanged',
'#layout',
suggestion.target
);
});
},
// render livesearch suggestion
render_livesearch_suggestion: function (suggestion) {
return '<span class="' + suggestion.icon + '"></span> ' +
suggestion.value;
}
};
// extend livesearch options by suggestion renderer. this options gets
// passed to typeahead as datasets
livesearch_options.templates = {
suggestion: example.render_livesearch_suggestion
};
})(jQuery);
Main menu
Tile registration name: mainmenu
Renders root children as main menu. Optionally render first level children of
main menu node as dropdown.
Expected metadata
:
- title: Node title.
- description: Node description.
Considered properties
:
- skip_mainmenu: Set to
True
if node should not be displayed in
mainmenu.
- mainmenu_empty_title: If set to
True
, links are rendered
as icon only without the title.
- mainmenu_display_children: Set to
True
if children nodes of main menu
node should be rendered as dropdown menu.
- default_child: If set, referring child is marked selected if no other
current path is found.
- default_content_tile: If set, it is considered in target link creation.
- icon: If set, used to render the node icon. As fallback, the icon defined
in
@node_info
decorator is used.
from cone.app import model
from node.utils import instance_property
class ExamplePlugin(model.BaseNode):
@instance_property
def properties(self):
props = model.Properties()
props.skip_mainmenu = False
props.mainmenu_empty_title = False
props.mainmenu_display_children = False
props.default_content_tile = 'examplecontent'
props.icon = 'ion-ios7-gear'
return props
@instance_property
def metadata(self):
metadata = model.Metadata()
metadata.title = 'Example'
metadata.description = 'Example Plugin'
return metadata
Path Bar
Tile registration name: pathbar
Renders the path bar navigation.
Expected metadata
:
Considered properties
:
- default_child: Render default child instead of current node in pathbar
if selected.
- default_content_tile: If set, it is considered in target link creation.
from cone.app import model
from node.utils import instance_property
class ExampleNode(model.BaseNode):
@instance_property
def properties(self):
props = model.Properties()
props.default_child = 'child'
props.default_content_tile = 'examplecontent'
return props
@instance_property
def metadata(self):
metadata = model.Metadata()
metadata.title = 'Example'
return metadata
Navigation tree
Tile registration name: navtree
Renders a navigation tree. Nodes which do not grant permission ‘view’ are
skipped.
Expected metadata
:
Considered properties
:
- in_navtree: Flag whether to display the node in navigation tree.
- is_navroot: Flag whether this node should be used as navigation root in
navigation tree.
- default_child: Default child nodes are displayed in navigation tree.
- hide_if_default: If default child should not be displayed it navtree,
hide_if_default
must be True
. In this case, also children scope
switches. Instead of siblings, children of default child node are rendered.
- default_content_tile: If set, it is considered in target link creation.
- icon: If set, used to render the node icon. As fallback, the icon defined
in
@node_info
decorator is used.
from cone.app import model
from node.utils import instance_property
class ExampleNode(model.BaseNode):
@instance_property
def properties(self):
props = model.Properties()
props.in_navtree = True
props.is_navroot = False
props.default_child = 'child'
props.hide_if_default = False
props.default_content_tile = 'examplecontent'
props.icon = 'ion-ios7-gear'
return props
@instance_property
def metadata(self):
metadata = model.Metadata()
metadata.title = 'Example'
return metadata
Page Content Area
Tile registration name: content
Content area for node. cone.app
expects a tile registered by name
content
to render the default Content Area of a node. The plugin code is
responsible to provide a content tile for model nodes.
from cone.example.model import ExamplePlugin
from cone.tile import Tile
from cone.tile import tile
@tile(name='content',
path='templates/content.pt',
interface=ExamplePlugin,
permission='view')
class ExamplePluginContentTile(Tile):
pass
When providing tiles for displaying node content, it’s often desired to
render the login form if the user is not authenticated, or display a message
whether the user has insufficient privileges if access is forbidden. Therefor
class cone.app.browser.layout.ProtectedContentTile
is available.
Protected content tiles need to be registered for permission ‘login’. The
permission required to access the tile itself can be defined via
content_permission
and defaults to ‘view’. If content permission not granted
on node, a tile named insufficient_privileges
is rendered.
from cone.app.browser.layout import ProtectedContentTile
from cone.example.model import ExamplePlugin
from cone.tile import tile
@tile(name='content', interface=ExamplePlugin, permission='login')
class ExamplePluginProtectedContentTile(ProtectedContentTile):
content_permission = 'list'
def render(self):
return '<div>Example Plugin Content</div>'
Often it’s desired to render different “Content views” on the same application
node. Therefor an extended tile decorator exists at
cone.app.browser.content.content_view_tile
. In addition to the tile it
also registers a pyramid view by the same name which is traversable via
browser URL:
from cone.app.browser.content import content_view_tile
from cone.example.model import ExamplePlugin
from cone.tile import Tile
@content_view_tile(
name='details',
interface=ExamplePlugin,
permission='view')
class DetailsContentTile(Tile):
"""For this class a pyramid view is registered which is reachable
under 'http://domain.com/path/to/node/details'. This view renders
the main template with the ``details`` tile as page content.
"""
Furthermore it’s possible to register a view action for the contextmenu’s
‘contentviews’ group by applying content_view_action
decorator:
from cone.app.browser.content import content_view_action
from cone.app.browser.content import content_view_tile
from cone.example.model import ExamplePlugin
from cone.tile import Tile
@content_view_tile(
name='details',
interface=ExamplePlugin,
permission='view')
@content_view_action(
name='details_view_action',
tilename='details',
interface=ExamplePlugin,
permission='view',
text='Details',
icon='glyphicons glyphicons-magic')
class DetailsContentTile(Tile):
"""For this class a pyramid view is registered which is reachable
under 'http://domain.com/path/to/node/details'. This view renders
the main template with the ``details`` tile as page content.
"""
Abstract tiles
Batch
A tile for rendering batches is contained at cone.app.browser.batch.Batch
.
A subclass must at least implement vocab
. The example below renders a batch
for all children of model node.
from cone.app.browser.batch import Batch
from cone.app.browser.utils import make_query
from cone.app.browser.utils import make_url
from cone.tile import tile
@tile('examplebatch')
class ExampleBatch(Batch):
slicesize = 10
@property
def vocab(self):
count = len(self.model)
pages = count / self.slicesize
if count % self.slicesize != 0:
pages += 1
current = self.request.params.get('b_page', '0')
for i in range(pages):
query = make_query(b_page=str(i))
href = make_url(
self.request,
path=path,
resource='viewname',
query=query
)
target = make_url(self.request, path=path, query=query)
ret.append({
'page': '{}'.format(i + 1),
'current': current == str(i),
'visible': True,
'href': href,
'target': target,
})
return ret
More customization options on Batch
class:
- display: Flag whether to display the batch.
- batchrange: Number of batch pages displayed.
- ellipsis: Ellipsis is number of pages exceeds
batchrange
.
- firstpage: Overwrite with property returning
None
to suppress
rendering first page link.
- lastpage: Overwrite with property returning
None
to suppress
rendering last page link.
- prevpage: Overwrite with property returning
None
to suppress
rendering previous page link.
- nextpage: Overwrite with property returning
None
to suppress
rendering next page link.
Batched Items
A tile for creating batched, searchable listings is contained at
cone.app.browser.batch
.
It consists of a listing header which displays a search field and a slice size
selection, the actual listing slice and a listing footer which displays
information about the currently displayed slice and the pagination
Batch.
The listing slice is abstract and must be implemented while the listing header,
footer and pagination batch are generic implementations.
Create a template for rendering the slice, e.g. at
cone.example.browser:templates/example_slice.pt
:
<tal:example_slice
xmlns:tal="http://xml.zope.org/namespaces/tal"
omit-tag="True">
<div class="${context.slice_id}">
<div tal:repeat="item context.slice_items">
<span tal:content="item.metadata.title">Title</span>
</div>
</div>
</tal:example_slice>
The concrete tile implementation subclasses BatchedItems
and must at least
implement item_count
and slice_items
. To render the slice a template
is provided at slice_template
. Another option to render the slice is to
overwrite rendered_slice
or using a custom template for the entire
BatchedItems
implementation based on
cone.app.browser:templates/batched_items.pt
and render the slice there.
item_count
returns the overall item count, slice_items
returns the
current items to display in the slice.
The subclass of BatchedItems
gets registered under desired tile name.
items_id
is set as CSS id of the tile element and is used to bind JS events
on the client side for rerendering the tile.
In the following example, filtered_items
is used to compute the overall
items based on given search term. This function is no part of the contract,
but illustrates that filter criteria and current slice needs to be considered
by the concrete BatchedItems
implementation.
from cone.app.browser.batch import BatchedItems
@tile(name='example_items')
class ExampleBatchedItems(BatchedItems):
items_id = 'example_items'
slice_template = 'cone.example.browser:templates/example_slice.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
More customization options on BatchedItems
class:
- path: Path to template used for rendering the tile. Defaults to
cone.app.browser:templates/batched_items.pt
. Can also be set by passing
it as path
keyword argument to tile
decorator.
- header_template: Template rendering the slice header. Defaults to
cone.app.browser:templates/batched_items_header.pt
.
- footer_template: Template rendering the slice footer. Defaults to
cone.app.browser:templates/batched_items_footer.pt
.
- slice_template: Template rendering the slice items. Defaults to
None
.
Shall be set by subclass.
- items_id: CSS ID of the batched items container DOM element.
- items_css: CSS classes of the batched items container DOM element.
- query_whitelist: Additional incoming request parameters to consider when
creating URL’s. Defaults to
[]
.
- display_header: Flag whether to display the listing header. Defaults to
True
.
- display_footer: Flag whether to display the listing footer. Defaults to
True
.
- show_title: Flag whether to show title in the listing header. Defaults
to
True
.
- title_css: CSS classes to set on title container DOM element. Defaults
to
col-xs-4
. Can be used to change the size of the title area.
- default_slice_size: Default number of items displayed in slice. Defaults
to
15
.
- num_slice_sizes: Number of available slice sizes in slice size selection.
- show_slice_size: Flag whether to display the slice size selection in
listing header. Defaults to
True
.
- slice_size_css: CSS classes to set on slice size selection container DOM
element. Defaults to
col-xs-4 col-sm3
. Can be used to change the size
of the slice size selection.
- show_filter: Flag whether to display the search filter input in listing
header. Defaults to
True
.
- filter_css: CSS classes to set on search filter input container DOM
element. Defaults to
col-xs-3
. Can be used to change the size
of the search filter input.
- head_additional: Additional arbitrary markup rendered in listing header.
Can be used to add additional listing filter aspects or similar.
- title: Title in the listing header. Defaults to
model.metadata.title
.
- bind_selectors: CSS selector to bind the batched items container DOM
element to.
- bind_events: JS events to bind the batched items container DOM
element to.
- trigger_selector: CSS selector to trigger JS event to when changing slice
size or entering search filter term.
- trigger_event: JS event triggered when changing slice size or entering
search filter term.
- pagination:
BatchedItemsBatch
instance.
- page_target: Pagination batch page target.
- slice_id: CSS ID of the slice container DOM element.
- slice_target: Slice size selection target URL.
- filter_target: Search filter input target URL.
Table
A tile for rendering sortable, batched tables is contained at
cone.app.browser.table.Table
.
A subclass of this tile must be registered under the same name as defined
at table_tile_name
and is normally bound to template
cone.app:browser/templates/table.pt
.
Futher the implementation must provide col_defs
, item_count
and
sorted_rows
.
from cone.app.browser.table import RowData
from cone.app.browser.table import Table
@tile(name='example_table', path='cone.app:browser/templates/table.pt')
class ExampleTable(Table):
table_id = 'example_table'
table_css = 'example_table'
table_tile_name = 'example_table'
col_defs = [{
'id': 'column_a',
'title': 'Column A',
'sort_key': None,
'sort_title': None,
'content': 'string'
}, {
'id': 'column_b',
'title': 'Column B',
'sort_key': None,
'sort_title': None,
'content': 'string'
}]
@property
def item_count(self):
return len(self.model)
def sorted_rows(self, start, end, sort, order):
# ``sort`` and ``order`` must be considered when creating the
# sorted results.
rows = list()
for child in self.model.values()[start:end]:
row_data = RowData()
row_data['column_a'] = child.attrs['attr_a']
row_data['column_b'] = child.attrs['attr_b']
rows.append(row_data)
return rows
Column definitions:
- id: Column ID.
- title: Column Title.
- sort_key: Key used for sorting this column.
- sort_title: Sort Title.
- content: Column content format:
string
: Renders column content as is.
datetime
: Expects datetime as column value and formats datetime.
structure
: Renders column content as Markup.
More customization options on Table
class:
- default_sort: Default sort column by ID. Defaults to
None
.
- default_order: Default sort order. Can be
'asc'
or 'desc'
.
Defaults to None
.
- default_slicesize: Default table content slize size. Defaults to
15
.
- query_whitelist: List of URL query parameters considered when creating
Links. Defaults to
[]
.
- show_title: Flag whether to display table title. Defaults to
True
.
- table_title: Title of the table. Defaults to
self.model.metadata.title
.
- show_filter: Flag whether to display table filter search field. Defaults
to
False
. If used, server side implementation must consider
self.filter_term
when creating results.
- show_slicesize: Flag whether to display the slize size selection.
Defaults to
True
.
- head_additional: Additional table header markup. Defaults to
None
.
- display_table_header: Flag whether to display table header. Defaults
to
True
.
- display_table_footer: Flag whether to display table footer. Defaults
to
True
.
Actions
Action are no tiles but behave similar. They get called with context and
request as arguments, are responsible to read action related information from
node and request and render an appropriate action (or not).
Actions are used in contexmenu
and contents
tiles by default, but they
can be used elsewhere to render user actions for nodes.
There exist base objects Action
, TileAction
, TemplateAction
,
DropdownAction
and LinkAction
in cone.app.browser.actions
which can
be used as base classes for custom actions.
Class Toolbar
can be used to render a set of actions.
Class ActionContext
provides information about the current execution
scope. The scope is a tile name and used by actions to check it’s own state,
e.g. if action is selected, disabled or should be displayed at all. The scope
gets calculated by a set of rules.
- If
bdajax.action
found on request, use it as current scope.
bdajax.action
is always a tile name in cone.app
context.
- If tile name is
layout
, content tile name is used. The layout tile
renders the entire page, thus the user is normally interested in the content
tile name rather than the rendered tile name.
- If tile name is
content
and model defines
properties.default_content_tile
, this one is used instead of content
to ensure a user can detect the correct content tile currently rendered.
When inheriting from Action
directly, class must provide a render
function returning HTML markup.
from cone.app.browser.actions import Action
class ExampleAction(Action):
@property
def display(self):
return self.permitted('view') and self.action_scope == 'content'
def render(self):
return '<a href="http://example.com">Example</a>'
When inheriting from TileAction
, a tile by name is rendered.
from cone.app.browser.actions import TileAction
from cone.tile import tile
from cone.tile import Tile
@tile(name='example_action',
path='cone.example:browser/templates/example_action.pt',
permission='view')
class ExampleActionTile(Tile):
pass
class ExampleAction(TileAction):
tile = 'example_action'
When inheriting from TemplateAction
, a template is rendered.
from cone.app.browser.actions import TemplateAction
class ExampleAction(TemplateAction):
template = 'cone.example:browser/templates/example_action.pt'
When inheriting from DropdownAction
, class must implement items
which
are used as dropdown menu items.
from cone.app import model
from cone.app.browser.actions import DropdownAction
from cone.app.browser.utils import make_url
class ExampleAction(DropdownAction):
css = 'example_css_class'
title = 'Example Dropdown'
@property
def items(self):
item = model.Properties()
item.icon = 'ion-ios7-gear'
item.url = item.target = make_url(self.request, node=self.model)
item.action = 'example_action:NONE:NONE'
item.title = 'Example Action'
return [item]
LinkAction
represents a HTML link offering integration to bdajax
,
enabled and selected state and optionally rendering an icon.
from cone.app.browser.actions import LinkAction
class ExampleAction(LinkAction):
bind = 'click' # ``ajax:bind`` attribute
id = None # ``id`` attribute
href = '#' # ``href`` attribute
css = None # in addition for computed ``class`` attribute
title = None # ``title`` attribute
action = None # ``ajax:action`` attribute
event = None # ``ajax:event`` attribute
confirm = None # ``ajax:confirm`` attribute
overlay = None # ``ajax:overlay`` attribute
path = None # ``ajax:path`` attribute
path_target = None # ``ajax:path-target`` attribute
path_action = None # ``ajax:path-action`` attribute
path_event = None # ``ajax:path-event`` attribute
path_overlay = None # ``ajax:path-overlay`` attribute
text = None # link text
enabled = True # if ``False``, link gets 'disabled' CSS class
selected = False # if ``True``, link get 'selected' CSS class
icon = None # if set, render span tag with value as CSS class in link
Toolbar
can be used to create a set of actions.
from cone.app.browser.actions import Toolbar
from cone.app.browser.actions import ActionView
from cone.app.browser.actions import ActionEdit
toolbar = Toolbar()
toolbar['view'] = ActionView()
toolbar['edit'] = ActionEdit()
# render toolbar with model and request
markup = toolbar(model, request)
cone.app
ships with concrete Action
implementations which are described
in the following sections.
ActionUp
Renders content area tile on parent node to main content area.
Considered properties
:
- action_up: Flag whether to render “One level up” action.
- action_up_tile: Considered if
action_up
is true. Defines the tilename
used for rendering parent content area. Defaults to listing
if undefined.
- default_child: If set, use
model.parent
for target
link creation.
ActionView
Renders content
tile on node to main content area.
Considered properties
:
- action_view: Flag whether to render view action.
- default_content_tile: If set, it is considered in target link creation.
ViewLink
Like ActionView
but renders text only link.
ActionList
Renders listing
tile on node to main content area.
Considered properties
:
- action_list: Flag whether to render list action.
ActionAdd
Renders add dropdown menu.
Considered nodeinfo
:
- addables: Addable children defined for node.
ActionEdit
Renders edit
tile to main content area.
Considered nodeinfo
:
- action_edit: Flag whether to render edit action.
ActionDelete
Invokes delete
tile on node after confirming action.
Considered nodeinfo
:
- action_delete: Flag whether to render delete action.
- default_content_tile: If set, used to check if scope is
view
when
calculating whether to display action.
ActionCut
Writes selected elements contained in cone.selectable.selected
to cookie
on client.
Action related node must implement cone.app.interfaces.ICopySupport
.
ActionCopy
Writes selected elements contained in cone.selectable.selected
to cookie
on client.
Action related node must implement cone.app.interfaces.ICopySupport
.
ActionPaste
Invokes paste
tile on node.
Action related node must implement cone.app.interfaces.ICopySupport
.
Considered properties
:
- action_paste_tile: Content tile name to render after paste. Defaults to
listing
if undefined.
ActionMoveUp
Invokes move_up
tile on node.
Considered properties
:
- action_move: Flag on parent whether to render move up action.
ActionMoveDown
Invokes move_down
tile on node.
Considered properties
:
- action_move: Flag on parent whether to render move down action.
ActionSharing
Renders sharing
tile on node to main content area.
Action related node must implement cone.app.interfaces.IPrincipalACL
.
ActionState
Renders workflow state dropdown menu.
Action related node must implement cone.app.interfaces.IWorkflowState
.