Ejemplo n.º 1
0
    def htmlConfig(html, id, orderby, rfields=None, cache=None, **attr):
        """
            Method to wrap the html for a dataTable in a form, add the export formats
            and the config details required by dataTables

            @param html: The html table
            @param id: The id of the table
            @param orderby: the sort details see http://datatables.net/reference/option/order
            @param rfields: The list of resource fields
            @param attr: dictionary of attributes which can be passed in
                   dt_lengthMenu: The menu options for the number of records to be shown
                   dt_pageLength : The default number of records that will be shown
                   dt_dom : The Datatable DOM initialisation variable, describing
                            the order in which elements are displayed.
                            See http://datatables.net/ref for more details.
                   dt_pagination : Is pagination enabled, dafault 'true'
                   dt_pagingType : How the pagination buttons are displayed
                   dt_searching: Enable or disable filtering of data.
                   dt_ajax_url: The URL to be used for the Ajax call
                   dt_action_col: The column where the action buttons will be placed
                   dt_bulk_actions: list of labels for the bulk actions.
                   dt_bulk_col: The column in which the checkboxes will appear,
                                by default it will be the column immediately
                                before the first data item
                   dt_group: The column(s) that is(are) used to group the data
                   dt_group_totals: The number of record in each group.
                                    This will be displayed in parenthesis
                                    after the group title.
                   dt_group_titles: The titles to be used for each group.
                                    These are a list of lists with the inner list
                                    consisting of two values, the repr from the
                                    db and the label to display. This can be more than
                                    the actual number of groups (giving an empty group).
                   dt_group_space: Insert a space between the group heading and the next group
                   dt_bulk_selected: A list of selected items
                   dt_actions: dictionary of actions
                   dt_styles: dictionary of styles to be applied to a list of ids
                              for example:
                              {"warning" : [1,3,6,7,9],
                               "alert" : [2,10,13]}
                   dt_text_maximum_len: The maximum length of text before it is condensed
                   dt_text_condense_len: The length displayed text is condensed down to
                   dt_shrink_groups: If set then the rows within a group will be hidden
                                     two types are supported, 'individulal' and 'accordion'
                   dt_group_types: The type of indicator for groups that can be 'shrunk'
                                   Permitted valies are: 'icon' (the default) 'text' and 'none'
                   dt_base_url: base URL to construct export format URLs, resource
                                default URL without any URL method or query part

            @global current.response.s3.actions used to get the RowActions
        """

        from gluon.serializers import json as jsons

        s3 = current.response.s3
        settings = current.deployment_settings

        dataTableID = s3.dataTableID
        if not dataTableID or not isinstance(dataTableID, list):
            dataTableID = s3.dataTableID = [id]
        elif id not in dataTableID:
            dataTableID.append(id)

        # The configuration parameter from the server to the client will be
        # sent in a json object stored in an hidden input field. This object
        # will then be parsed by s3.dataTable.js and the values used.
        config = Storage()
        config.id = id
        _aget = attr.get
        config.dom = _aget("dt_dom", settings.get_ui_datatables_dom())
        config.lengthMenu = _aget(
            "dt_lengthMenu",
            [[25, 50, -1], [25, 50, str(current.T("All"))]])
        config.pageLength = _aget("dt_pageLength", s3.ROWSPERPAGE)
        config.pagination = _aget("dt_pagination", "true")
        config.pagingType = _aget("dt_pagingType",
                                  settings.get_ui_datatables_pagingType())
        config.searching = _aget("dt_searching", "true")

        ajaxUrl = _aget("dt_ajax_url", None)
        if not ajaxUrl:
            request = current.request
            url = URL(
                c=request.controller,
                f=request.function,
                args=request.args,
                vars=request.get_vars,
            )
            ajaxUrl = s3_set_extension(url, "aadata")
        config.ajaxUrl = ajaxUrl

        config.rowStyles = _aget("dt_styles", [])

        rowActions = _aget("dt_row_actions", s3.actions)
        if rowActions:
            config.rowActions = rowActions
        else:
            config.rowActions = []
        bulkActions = _aget("dt_bulk_actions", None)
        if bulkActions and not isinstance(bulkActions, list):
            bulkActions = [bulkActions]
        config.bulkActions = bulkActions
        config.bulkCol = bulkCol = _aget("dt_bulk_col", 0)
        action_col = _aget("dt_action_col", 0)
        if bulkActions and bulkCol <= action_col:
            action_col += 1
        config.actionCol = action_col

        group_list = _aget("dt_group", [])
        if not isinstance(group_list, list):
            group_list = [group_list]
        dt_group = []
        for group in group_list:
            if bulkActions and bulkCol <= group:
                group += 1
            if action_col >= group:
                group -= 1
            dt_group.append([group, "asc"])
        config.group = dt_group
        config.groupTotals = _aget("dt_group_totals", [])
        config.groupTitles = _aget("dt_group_titles", [])
        config.groupSpacing = _aget("dt_group_space", "false")
        for order in orderby:
            if bulkActions:
                if bulkCol <= order[0]:
                    order[0] += 1
            if action_col > 0 and action_col >= order[0]:
                order[0] -= 1
        config.order = orderby
        config.textMaxLength = _aget("dt_text_maximum_len", 80)
        config.textShrinkLength = _aget("dt_text_condense_len", 75)
        config.shrinkGroupedRows = _aget("dt_shrink_groups", "false")
        config.groupIcon = _aget("dt_group_types", [])

        # Wrap the table in a form and add some data in hidden fields
        form = FORM(_class="dt-wrapper")
        if not s3.no_formats:
            # @todo: move export-format update into drawCallback()
            # @todo: poor UX with onclick-JS, better to render real
            #        links which can be bookmarked, and then update them
            #        in drawCallback()
            permalink = _aget("dt_permalink", None)
            base_url = _aget("dt_base_url", None)
            export_formats = S3DataTable.export_formats(rfields,
                                                        permalink=permalink,
                                                        base_url=base_url)
            # Nb These can be moved around in initComplete()
            form.append(export_formats)

        form.append(html)

        # Add the configuration details for this dataTable
        form.append(
            INPUT(_type="hidden",
                  _id="%s_configurations" % id,
                  _name="config",
                  _value=jsons(config)))

        # If we have a cache set up then pass it in
        if cache:
            form.append(
                INPUT(_type="hidden",
                      _id="%s_dataTable_cache" % id,
                      _name="cache",
                      _value=jsons(cache)))

        # If we have bulk actions then add the hidden fields
        if bulkActions:
            form.append(
                INPUT(_type="hidden",
                      _id="%s_dataTable_bulkMode" % id,
                      _name="mode",
                      _value="Inclusive"))
            bulk_selected = _aget("dt_bulk_selected", "")
            if isinstance(bulk_selected, list):
                bulk_selected = ",".join(bulk_selected)
            form.append(
                INPUT(_type="hidden",
                      _id="%s_dataTable_bulkSelection" % id,
                      _name="selected",
                      _value="[%s]" % bulk_selected))
            form.append(
                INPUT(_type="hidden",
                      _id="%s_dataTable_filterURL" % id,
                      _class="dataTable_filterURL",
                      _name="filterURL",
                      _value="%s" % config.ajaxUrl))

        # Set callback?
        initComplete = settings.get_ui_datatables_initComplete()
        if initComplete:
            # Processed in views/dataTables.html
            s3.dataTable_initComplete = initComplete

        return form
Ejemplo n.º 2
0
Archivo: s3data.py Proyecto: mauld/eden
    def htmlConfig(html,
                   id,
                   orderby,
                   rfields = None,
                   cache = None,
                   **attr
                   ):
        """
            Method to wrap the html for a dataTable in a form, add the export formats
            and the config details required by dataTables

            @param html: The html table
            @param id: The id of the table
            @param orderby: the sort details see http://datatables.net/reference/option/order
            @param rfields: The list of resource fields
            @param attr: dictionary of attributes which can be passed in
                   dt_lengthMenu: The menu options for the number of records to be shown
                   dt_pageLength : The default number of records that will be shown
                   dt_dom : The Datatable DOM initialisation variable, describing
                            the order in which elements are displayed.
                            See http://datatables.net/ref for more details.
                   dt_pagination : Is pagination enabled, dafault 'true'
                   dt_pagingType : How the pagination buttons are displayed
                   dt_searching: Enable or disable filtering of data.
                   dt_ajax_url: The URL to be used for the Ajax call
                   dt_action_col: The column where the action buttons will be placed
                   dt_bulk_actions: list of labels for the bulk actions.
                   dt_bulk_col: The column in which the checkboxes will appear,
                                by default it will be the column immediately
                                before the first data item
                   dt_group: The column(s) that is(are) used to group the data
                   dt_group_totals: The number of record in each group.
                                    This will be displayed in parenthesis
                                    after the group title.
                   dt_group_titles: The titles to be used for each group.
                                    These are a list of lists with the inner list
                                    consisting of two values, the repr from the
                                    db and the label to display. This can be more than
                                    the actual number of groups (giving an empty group).
                   dt_group_space: Insert a space between the group heading and the next group
                   dt_bulk_selected: A list of selected items
                   dt_actions: dictionary of actions
                   dt_styles: dictionary of styles to be applied to a list of ids
                              for example:
                              {"warning" : [1,3,6,7,9],
                               "alert" : [2,10,13]}
                   dt_text_maximum_len: The maximum length of text before it is condensed
                   dt_text_condense_len: The length displayed text is condensed down to
                   dt_shrink_groups: If set then the rows within a group will be hidden
                                     two types are supported, 'individual' and 'accordion'
                   dt_group_types: The type of indicator for groups that can be 'shrunk'
                                   Permitted valies are: 'icon' (the default) 'text' and 'none'
                   dt_base_url: base URL to construct export format URLs, resource
                                default URL without any URL method or query part

            @global current.response.s3.actions used to get the RowActions
        """

        from gluon.serializers import json as jsons

        s3 = current.response.s3
        settings = current.deployment_settings

        dataTableID = s3.dataTableID
        if not dataTableID or not isinstance(dataTableID, list):
            dataTableID = s3.dataTableID = [id]
        elif id not in dataTableID:
            dataTableID.append(id)

        # The configuration parameter from the server to the client will be
        # sent in a json object stored in an hidden input field. This object
        # will then be parsed by s3.dataTable.js and the values used.
        config = Storage()
        config.id = id
        _aget = attr.get
        config.dom = _aget("dt_dom", settings.get_ui_datatables_dom())
        config.lengthMenu = _aget("dt_lengthMenu",
                                  [[25, 50, -1],
                                   [25, 50, s3_str(current.T("All"))]
                                   ]
                                  )
        config.pageLength = _aget("dt_pageLength", s3.ROWSPERPAGE)
        config.pagination = _aget("dt_pagination", "true")
        config.pagingType = _aget("dt_pagingType",
                                  settings.get_ui_datatables_pagingType())
        config.searching = _aget("dt_searching", "true")

        ajaxUrl = _aget("dt_ajax_url", None)
        if not ajaxUrl:
            request = current.request
            url = URL(c=request.controller,
                      f=request.function,
                      args=request.args,
                      vars=request.get_vars,
                      )
            ajaxUrl = s3_set_extension(url, "aadata")
        config.ajaxUrl = ajaxUrl

        config.rowStyles = _aget("dt_styles", [])

        rowActions = _aget("dt_row_actions", s3.actions)
        if rowActions:
            config.rowActions = rowActions
        else:
            config.rowActions = []
        bulkActions = _aget("dt_bulk_actions", None)
        if bulkActions and not isinstance(bulkActions, list):
            bulkActions = [bulkActions]
        config.bulkActions = bulkActions
        config.bulkCol = bulkCol = _aget("dt_bulk_col", 0)
        action_col = _aget("dt_action_col", 0)
        if bulkActions and bulkCol <= action_col:
            action_col += 1
        config.actionCol = action_col

        group_list = _aget("dt_group", [])
        if not isinstance(group_list, list):
            group_list = [group_list]
        dt_group = []
        for group in group_list:
            if bulkActions and bulkCol <= group:
                group += 1
            if action_col >= group:
                group -= 1
            dt_group.append([group, "asc"])
        config.group = dt_group
        config.groupTotals = _aget("dt_group_totals", [])
        config.groupTitles = _aget("dt_group_titles", [])
        config.groupSpacing = _aget("dt_group_space", "false")
        for order in orderby:
            if bulkActions:
                if bulkCol <= order[0]:
                    order[0] += 1
            if action_col > 0 and action_col >= order[0]:
                order[0] -= 1
        config.order = orderby
        config.textMaxLength = _aget("dt_text_maximum_len", 80)
        config.textShrinkLength = _aget("dt_text_condense_len", 75)
        config.shrinkGroupedRows = _aget("dt_shrink_groups", "false")
        config.groupIcon = _aget("dt_group_types", [])

        # Wrap the table in a form and add some data in hidden fields
        form = FORM(_class="dt-wrapper")
        if not s3.no_formats:
            # @todo: move export-format update into drawCallback()
            # @todo: poor UX with onclick-JS, better to render real
            #        links which can be bookmarked, and then update them
            #        in drawCallback()
            permalink = _aget("dt_permalink", None)
            base_url = _aget("dt_base_url", None)
            export_formats = S3DataTable.export_formats(rfields,
                                                        permalink=permalink,
                                                        base_url=base_url)
            # Nb These can be moved around in initComplete()
            form.append(export_formats)

        form.append(html)

        # Add the configuration details for this dataTable
        form.append(INPUT(_type="hidden",
                          _id="%s_configurations" % id,
                          _name="config",
                          _value=jsons(config)))

        # If we have a cache set up then pass it in
        if cache:
            form.append(INPUT(_type="hidden",
                              _id="%s_dataTable_cache" %id,
                              _name="cache",
                              _value=jsons(cache)))

        # If we have bulk actions then add the hidden fields
        if bulkActions:
            form.append(INPUT(_type="hidden",
                              _id="%s_dataTable_bulkMode" % id,
                              _name="mode",
                              _value="Inclusive"))
            bulk_selected = _aget("dt_bulk_selected", "")
            if isinstance(bulk_selected, list):
                bulk_selected = ",".join(bulk_selected)
            form.append(INPUT(_type="hidden",
                              _id="%s_dataTable_bulkSelection" % id,
                              _name="selected",
                              _value="[%s]" % bulk_selected))
            form.append(INPUT(_type="hidden",
                              _id="%s_dataTable_filterURL" % id,
                              _class="dataTable_filterURL",
                              _name="filterURL",
                              _value="%s" % config.ajaxUrl))

        # Set callback?
        initComplete = settings.get_ui_datatables_initComplete()
        if initComplete:
            # Processed in views/dataTables.html
            s3.dataTable_initComplete = initComplete

        return form
Ejemplo n.º 3
0
    def htmlConfig(html,
                   id,
                   orderby,
                   rfields = None,
                   cache = None,
                   filteredrows = None,
                   **attr
                   ):
        """
            Method to wrap the html for a dataTable in a form, the list of formats
            used for data export and add the config details required by dataTables,

            @param html: The html table
            @param id: The id of the table
            @param orderby: the sort details see aaSort at http://datatables.net/ref
            @param rfields: The list of resource fields
            @param attr: dictionary of attributes which can be passed in
                   dt_displayLength : The default number of records that will be shown
                   dt_sDom : The Datatable DOM initialisation variable, describing
                             the order in which elements are displayed.
                             See http://datatables.net/ref for more details.
                   dt_pagination : Is pagination enabled, dafault 'true'
                   dt_pagination_type : How the pagination buttons are displayed
                   dt_bFilter: Enable or disable filtering of data.
                   dt_ajax_url: The URL to be used for the Ajax call
                   dt_action_col: The column where the action buttons will be placed
                   dt_bulk_actions: list of labels for the bulk actions.
                   dt_bulk_col: The column in which the checkboxes will appear,
                                by default it will be the column immediately
                                before the first data item
                   dt_group: The column(s) that is(are) used to group the data
                   dt_group_totals: The number of record in each group.
                                    This will be displayed in parenthesis
                                    after the group title.
                   dt_group_titles: The titles to be used for each group.
                                    These are a list of lists with the inner list
                                    consisting of two values, the repr from the
                                    db and the label to display. This can be more than
                                    the actual number of groups (giving an empty group).
                   dt_group_space: Insert a space between the group heading and the next group
                   dt_bulk_selected: A list of selected items
                   dt_actions: dictionary of actions
                   dt_styles: dictionary of styles to be applied to a list of ids
                              for example:
                              {"warning" : [1,3,6,7,9],
                               "alert" : [2,10,13]}
                   dt_text_maximum_len: The maximum length of text before it is condensed
                   dt_text_condense_len: The length displayed text is condensed down to
                   dt_shrink_groups: If set then the rows within a group will be hidden
                                     two types are supported, 'individulal' and 'accordion'
                   dt_group_types: The type of indicator for groups that can be 'shrunk'
                                   Permitted valies are: 'icon' (the default) 'text' and 'none'
            @global current.response.s3.actions used to get the RowActions
        """

        from gluon.serializers import json

        request = current.request
        s3 = current.response.s3

        dataTableID = s3.dataTableID
        if not dataTableID or not isinstance(dataTableID, list):
            dataTableID = s3.dataTableID = [id]
        elif id not in dataTableID:
            dataTableID.append(id)
        # The configuration parameter from the server to the client will be
        # sent in a json object stored in an hidden input field. This object
        # will then be parsed by s3.dataTable.js and the values used.
        config = Storage()
        config.id = id
        config.displayLength = attr.get("dt_displayLength",
                                        current.manager.ROWSPERPAGE)
        config.sDom = attr.get("dt_sDom", 'fril<"dataTable_table"t>pi')
        config.pagination = attr.get("dt_pagination", "true")
        config.paginationType = attr.get("dt_pagination_type", "full_numbers")
        config.bFilter = attr.get("dt_bFilter", "true")
        config.ajaxUrl = attr.get("dt_ajax_url", URL(c=request.controller,
                                                     f=request.function,
                                                     extension="aadata",
                                                     args=request.args,
                                                     vars=request.get_vars,
                                                     ))
        config.rowStyles = attr.get("dt_styles", [])


        rowActions = s3.actions
        if rowActions:
            config.rowActions = rowActions
        else:
            config.rowActions = []
        bulkActions = attr.get("dt_bulk_actions", None)
        if bulkActions and not isinstance(bulkActions, list):
            bulkActions = [bulkActions]
        config.bulkActions = bulkActions
        config.bulkCol = bulkCol = attr.get("dt_bulk_col", 0)
        action_col = attr.get("dt_action_col", 0)
        if bulkActions and bulkCol <= action_col:
            action_col += 1
        config.actionCol = action_col
        group_list = attr.get("dt_group", [])
        if not isinstance(group_list, list):
            group_list = [group_list]
        dt_group = []
        for group in group_list:
            if bulkActions and bulkCol <= group:
                group += 1
            if action_col >= group:
                group -= 1
            dt_group.append([group, "asc"])
        config.group = dt_group
        config.groupTotals = attr.get("dt_group_totals", [])
        config.groupTitles = attr.get("dt_group_titles", [])
        config.groupSpacing = attr.get("dt_group_space", "false")
        for order in orderby:
            if bulkActions:
                if bulkCol <= order[0]:
                    order[0] += 1
            if action_col >= order[0]:
                order[0] -= 1
        config.aaSort = orderby
        config.textMaxLength = attr.get("dt_text_maximum_len", 80)
        config.textShrinkLength = attr.get("dt_text_condense_len", 75)
        config.shrinkGroupedRows = attr.get("dt_shrink_groups", "false")
        config.groupIcon = attr.get("dt_group_types", [])
        # Wrap the table in a form and add some data in hidden fields
        form = FORM()
        if not s3.no_formats and len(html) > 0:
            permalink = attr.get("dt_permalink", None)
            form.append(S3DataTable.listFormats(id, rfields,
                                                permalink=permalink))
        form.append(html)
        # Add the configuration details for this dataTable
        form.append(INPUT(_type="hidden",
                          _id="%s_configurations" % id,
                          _name="config",
                          _value=json(config)))
        # If we have a cache set up then pass it in
        if cache:
            form.append(INPUT(_type="hidden",
                              _id="%s_dataTable_cache" %id,
                              _name="cache",
                              _value=json(cache)))
        # If we have bulk actions then add the hidden fields
        if config.bulkActions:
            form.append(INPUT(_type="hidden",
                              _id="%s_dataTable_bulkMode" % id,
                              _name="mode",
                              _value="Inclusive"))
            bulk_selected = attr.get("dt_bulk_selected", "")
            if isinstance(bulk_selected, list):
                bulk_selected = ",".join(bulk_selected)
            form.append(INPUT(_type="hidden",
                              _id="%s_dataTable_bulkSelection" % id,
                              _name="selected",
                              _value="[%s]" % bulk_selected))
        return form
Ejemplo n.º 4
0
    def htmlConfig(html,
                   id,
                   orderby,
                   rfields=None,
                   cache=None,
                   filteredrows=None,
                   **attr):
        """
            Method to wrap the html for a dataTable in a form, the list of formats
            used for data export and add the config details required by dataTables,

            @param html: The html table
            @param id: The id of the table
            @param orderby: the sort details see aaSort at http://datatables.net/ref
            @param rfields: The list of resource fields
            @param attr: dictionary of attributes which can be passed in
                   dt_displayLength : The default number of records that will be shown
                   dt_sDom : The Datatable DOM initialisation variable, describing
                             the order in which elements are displayed.
                             See http://datatables.net/ref for more details.
                   dt_pagination : Is pagination enabled, dafault 'true'
                   dt_pagination_type : How the pagination buttons are displayed
                   dt_bFilter: Enable or disable filtering of data.
                   dt_ajax_url: The URL to be used for the Ajax call
                   dt_action_col: The column where the action buttons will be placed
                   dt_bulk_actions: list of labels for the bulk actions.
                   dt_bulk_col: The column in which the checkboxes will appear,
                                by default it will be the column immediately
                                before the first data item
                   dt_group: The column(s) that is(are) used to group the data
                   dt_group_totals: The number of record in each group.
                                    This will be displayed in parenthesis
                                    after the group title.
                   dt_group_titles: The titles to be used for each group.
                                    These are a list of lists with the inner list
                                    consisting of two values, the repr from the
                                    db and the label to display. This can be more than
                                    the actual number of groups (giving an empty group).
                   dt_group_space: Insert a space between the group heading and the next group
                   dt_bulk_selected: A list of selected items
                   dt_actions: dictionary of actions
                   dt_styles: dictionary of styles to be applied to a list of ids
                              for example:
                              {"warning" : [1,3,6,7,9],
                               "alert" : [2,10,13]}
                   dt_text_maximum_len: The maximum length of text before it is condensed
                   dt_text_condense_len: The length displayed text is condensed down to
                   dt_shrink_groups: If set then the rows within a group will be hidden
                                     two types are supported, 'individulal' and 'accordion'
                   dt_group_types: The type of indicator for groups that can be 'shrunk'
                                   Permitted valies are: 'icon' (the default) 'text' and 'none'
            @global current.response.s3.actions used to get the RowActions
        """

        from gluon.serializers import json

        request = current.request
        s3 = current.response.s3

        dataTableID = s3.dataTableID
        if not dataTableID or not isinstance(dataTableID, list):
            dataTableID = s3.dataTableID = [id]
        elif id not in dataTableID:
            dataTableID.append(id)
        # The configuration parameter from the server to the client will be
        # sent in a json object stored in an hidden input field. This object
        # will then be parsed by s3.dataTable.js and the values used.
        config = Storage()
        config.id = id
        config.displayLength = attr.get("dt_displayLength",
                                        current.manager.ROWSPERPAGE)
        config.sDom = attr.get("dt_sDom", 'fril<"dataTable_table"t>pi')
        config.pagination = attr.get("dt_pagination", "true")
        config.paginationType = attr.get("dt_pagination_type", "full_numbers")
        config.bFilter = attr.get("dt_bFilter", "true")
        config.ajaxUrl = attr.get(
            "dt_ajax_url",
            URL(
                c=request.controller,
                f=request.function,
                extension="aadata",
                args=request.args,
                vars=request.get_vars,
            ))
        config.rowStyles = attr.get("dt_styles", [])

        rowActions = s3.actions
        if rowActions:
            config.rowActions = rowActions
        else:
            config.rowActions = []
        bulkActions = attr.get("dt_bulk_actions", None)
        if bulkActions and not isinstance(bulkActions, list):
            bulkActions = [bulkActions]
        config.bulkActions = bulkActions
        config.bulkCol = bulkCol = attr.get("dt_bulk_col", 0)
        action_col = attr.get("dt_action_col", 0)
        if bulkActions and bulkCol <= action_col:
            action_col += 1
        config.actionCol = action_col
        group_list = attr.get("dt_group", [])
        if not isinstance(group_list, list):
            group_list = [group_list]
        dt_group = []
        for group in group_list:
            if bulkActions and bulkCol <= group:
                group += 1
            if action_col >= group:
                group -= 1
            dt_group.append([group, "asc"])
        config.group = dt_group
        config.groupTotals = attr.get("dt_group_totals", [])
        config.groupTitles = attr.get("dt_group_titles", [])
        config.groupSpacing = attr.get("dt_group_space", "false")
        for order in orderby:
            if bulkActions:
                if bulkCol <= order[0]:
                    order[0] += 1
            if action_col >= order[0]:
                order[0] -= 1
        config.aaSort = orderby
        config.textMaxLength = attr.get("dt_text_maximum_len", 80)
        config.textShrinkLength = attr.get("dt_text_condense_len", 75)
        config.shrinkGroupedRows = attr.get("dt_shrink_groups", "false")
        config.groupIcon = attr.get("dt_group_types", [])
        # Wrap the table in a form and add some data in hidden fields
        form = FORM()
        if not s3.no_formats and len(html) > 0:
            permalink = attr.get("dt_permalink", None)
            form.append(
                S3DataTable.listFormats(id, rfields, permalink=permalink))
        form.append(html)
        # Add the configuration details for this dataTable
        form.append(
            INPUT(_type="hidden",
                  _id="%s_configurations" % id,
                  _name="config",
                  _value=json(config)))
        # If we have a cache set up then pass it in
        if cache:
            form.append(
                INPUT(_type="hidden",
                      _id="%s_dataTable_cache" % id,
                      _name="cache",
                      _value=json(cache)))
        # If we have bulk actions then add the hidden fields
        if config.bulkActions:
            form.append(
                INPUT(_type="hidden",
                      _id="%s_dataTable_bulkMode" % id,
                      _name="mode",
                      _value="Inclusive"))
            bulk_selected = attr.get("dt_bulk_selected", "")
            if isinstance(bulk_selected, list):
                bulk_selected = ",".join(bulk_selected)
            form.append(
                INPUT(_type="hidden",
                      _id="%s_dataTable_bulkSelection" % id,
                      _name="selected",
                      _value="[%s]" % bulk_selected))
        return form