Permalink
Browse files

Merge branch 'master' of github.com:Pylons/substanced

  • Loading branch information...
2 parents 3fbc76a + 274d871 commit bca3ca0ef9de45a02005ebe88710cd58690bef63 @mcdonc mcdonc committed Mar 5, 2013
@@ -144,6 +144,8 @@ The ``class`` on your buttons affect behavior in the datagrid:
- ``btn-sdi-sel`` disables the button until one or more items are
selected
+- ``btn-sdi-one`` disables the button until exactly one item is selected
+
- ``btn-sdi-del`` disables the button if any of the selected resources
is marked as "non-deletable" (discussed below)
View
@@ -27,7 +27,7 @@
'pyramid>=1.4dev', # effective_principals predicate
'ZODB3',
'hypatia>=0.1a3', # index-based querying
- 'venusian',
+ 'venusian>=1.0a3', # pyramid wants this too (prefer_finals...)
'deform>=0.9.6', # retail form rendering capability (for documentability)
'colander>=1.0a1', # subclassable schemanodes
'deform_bootstrap',
@@ -92,6 +92,7 @@ def __init__(
self.parent = parent
self.name = name
self.moving = moving
+ self.loading = loading
@implementer(IObjectModified)
class ObjectModified(object): # pragma: no cover
@@ -1,6 +1,6 @@
<div metal:use-macro="request.sdiapi.main_template">
- <div metal:fill-slot="head-more">
+ <metal:head-more fill-slot="head-more">
<style type="text/css">
.blockquote {
@@ -16,7 +16,7 @@
}
</style>
- </div>
+ </metal:head-more>
<div metal:fill-slot="main">
<h1>Substance D management interface demo</h1>
@@ -249,24 +249,39 @@ def _folder_contents(
Each button in a ``buttons`` dictionary is rendered using the button
tag and requires five keys: ``id`` for the button's id attribute,
``name`` for the button's name attribute, ``class`` for any additional
- css classes to be applied to it, ``value`` for the value that will be
- passed as a request parameter when the form is submitted and ``text``
- for the button's text.
+ css classes to be applied to it (see below), ``value`` for the value
+ that will be passed as a request parameter when the form is submitted
+ and ``text`` for the button's text.
+
+ The ``class`` value is special because it will define the button's
+ behavior. There are four mutually exclusive class names that can be
+ used. ``btn-sdi-act`` is for buttons that will always be enabled,
+ independently of any selected content items. ``btn-sdi-sel`` means
+ the button will start as disabled and will only be enabled once one
+ or more items are selected. ``btn-sdi-one`` means the button will
+ only be enabled if there's exactly one item selected. Finally,
+ ``btn-sdi-del`` means the button will stay disabled until one or
+ more *deletable* items are selected. You *must* use one of these
+ classes for the button to be enabled.
- Most of the time, the best strategy will be to return a value
- containing the default buttonspec sequence passed in to the function
- (it will be a list).::
+ The ``class`` value can contain several classes separated by spaces.
+ In addition to the classes mentioned above, any custom css class or any
+ bootstrap button class can be used.
+
+ Most of the time, the best strategy for using the buttons callable will
+ be to return a value containing the default buttonspec sequence passed
+ in to the function (it will be a list).::
def custom_buttons(context, request, default_buttonspec):
custom_buttonspec = [{'type': 'single',
'buttons': [{'id': 'button1',
'name': 'button1',
- 'class': 'btn-primary',
+ 'class': 'btn-sdi-sel',
'value': 'button1',
'text': 'Button 1'},
{'id': 'button2',
'name': 'button2',
- 'class': 'btn-primary',
+ 'class': 'btn-sdi-act',
'value': 'button2',
'text': 'Button 2'}]}]
return default_buttonspec + custom_buttonspec
@@ -307,33 +322,41 @@ def button1(context, request):
contents using a table with any given subobject attributes, a callable
named ``columns`` can be passed to a content type as metadata. When
the folder contents SDI view is invoked against an object of the type,
- the ``columns`` callable s.will be passed the folder, a subobject the
- ``request``, and a set of default column specification It will be
+ the ``columns`` callable will be passed the folder, a subobject, the
+ ``request``, and a default column specification. It will be
called once for every object in the folder to obtain column
representations for each of its subobjects. It must return a list of
- dictionaries with at least a ``name`` key for the column header and a
- ``value`` key with the correct column value given the subobject. The
+ dictionaries with at least a ``name`` key for the column header, a
+ ``field`` key for the field name to use in javascript manipulations,
+ and a ``value`` key with the correct column value given the subobject. The
callable **must** be prepared to receive subobjects that will *not*
have the desired attributes (the subobject passed will be ``None`` at
least once in order for the system to compute headers).
- In addition to ``name`` and ``value``, the column dictionary can
- contain the keys ``sortable`` and ``filterable``, which specify
- respectively whether the column will have buttons for sorting the rows
- and whether a row can be filtered using a simple text search. The
- default value for both of those parameters is ``True``.
+ In addition to ``name``, ``field`` and ``value``, the column dictionary can
+ contain the keys ``sortable`` and ``formatter``. The first one specifies
+ whether the column will have buttons for sorting the rows. The default value
+ is ``True``. The last key, ``formatter``, can give the name of a javascript
+ method for formatting the ``value``. Currently, available formatters are
+ ``icon_label_url`` and ``date``.
+
+ The ``icon_label_url`` formatter gets the URL and icon (if any) of the
+ subobject and creates a link using ``value`` as link text. The ``date``
+ formatter expects that ``value`` is an ISO date and returns a text date in
+ the format "<month name> <day>, <year>".
Here's an example of using the ``columns`` content type hook::
def custom_columns(folder, subobject, request, default_columnspec):
return default_columnspec + [
{'name': 'Review date',
+ 'field': 'date',
'value': getattr(subobject, 'review_date', ''),
'sortable': True,
- 'filterable': False},
+ 'formatter': 'date'},
{'name': 'Rating',
+ 'field': 'rating',
'value': getattr(subobject, 'rating', ''),
- 'filterable': False,
'sortable': True}
]
@@ -343,6 +366,26 @@ def custom_columns(folder, subobject, request, default_columnspec):
)
class MyCustomFolder(Persistent):
pass
+
+ In some cases, it might be needed to override the custom columns defined for
+ an already existing content type. This can be accomplished by registering the
+ content type a second time, but passing the columns then. For example, to add
+ columns to the user folder content listing from substanced::
+
+ from substanced import root_factory
+ from substanced.interfaces import IUsers
+ from substanced.principal import Users
+ from myapp import custom_user_columns
+
+ def main(global_config, **settings):
+ config = Configurator(root_factory=root_factory, settings=settings)
+ config.include('substanced')
+ config.add_content_type(IUsers,
+ factory=Users,
+ icon='icon-list-alt',
+ columns=custom_user_columns)
+ config.scan()
+
"""
folder = self.context
request = self.request
@@ -1,13 +1,13 @@
<div metal:use-macro="request.sdiapi.main_template">
- <div tal:omit-tag="" metal:fill-slot="head-more">
+ <metal:head-more fill-slot="head-more">
<!-- slickgrid -->
<script src="${request.static_url('substanced.sdi:static/js/slickgrid.upstream.js')}" type="text/javascript"></script>
<script src="${request.static_url('substanced.sdi:static/js/sdi.grid.remotemodel.js')}" type="text/javascript"></script>
<script src="${request.static_url('substanced.sdi:static/js/slickgrid-config.js')}" type="text/javascript"></script>
<link href="${request.static_url('substanced.sdi:static/css/slick.grid.upstream.css')}" rel="stylesheet" />
<link href="${request.static_url('substanced.sdi:static/css/sdi_slickgrid.css')}" rel="stylesheet" />
- </div>
+ </metal:head-more>
<div metal:fill-slot="main">
<div class="container-fluid"
@@ -123,6 +123,7 @@
var data = grid.getData();
if (selRows.length) {
var disable_delete = false;
+ var disable_multiple = false;
var i;
for (i = 0, l = selRows.length; i < l; i++) {
var item = data[selRows[i]];
@@ -132,12 +133,17 @@
disable_delete = true;
break;
}
+ if (i == 1) {
+ disable_multiple = true;
+ }
}
$('.btn-sdi-del').attr('disabled', disable_delete);
$('.btn-sdi-sel').attr('disabled', false);
+ $('.btn-sdi-one').attr('disabled', disable_multiple);
} else {
$('.btn-sdi-del').attr('disabled', true);
$('.btn-sdi-sel').attr('disabled', true);
+ $('.btn-sdi-one').attr('disabled', true);
}
});
@@ -1,6 +1,6 @@
<div metal:use-macro="request.sdiapi.main_template">
- <div metal:fill-slot="head-more">
+ <metal:head-more fill-slot="head-more">
<!-- CSS -->
<tal:block repeat="reqt css_links|[]">
<link rel="stylesheet"
@@ -13,7 +13,7 @@
src="${request.static_url(reqt)}"
></script>
</tal:block>
- </div>
+ </metal:head-more>
<div metal:fill-slot="main">
<h1>${view.title|None}</h1>
@@ -1,6 +1,6 @@
<div metal:use-macro="request.sdiapi.main_template">
- <div metal:fill-slot="head-more">
+ <metal:head-more fill-slot="head-more">
<!-- CSS -->
<tal:block repeat="reqt css_links|[]">
<link rel="stylesheet"
@@ -13,7 +13,7 @@
src="${request.static_url(reqt)}"
></script>
</tal:block>
- </div>
+ </metal:head-more>
<div metal:fill-slot="main">
@@ -1,6 +1,6 @@
<div metal:use-macro="request.sdiapi.main_template">
- <div metal:fill-slot="head-more">
+ <metal:head-more fill-slot="head-more">
<!-- CSS -->
<tal:block repeat="reqt css_links|[]">
<link rel="stylesheet"
@@ -13,7 +13,7 @@
src="${request.static_url(reqt)}"
></script>
</tal:block>
- </div>
+ </metal>
<div metal:fill-slot="main">
<h1>${view.title|None}</h1>

0 comments on commit bca3ca0

Please sign in to comment.