Ejemplo n.º 1
0
    def __init__(self, simple=None, advanced=None, any=False, **args):
        """
            Constructor

            @param simple: the widgets for the simple search form as list
            @param advanced: the widgets for the advanced search form as list
            @param any: match "any of" (True) or "all of" (False) the options
                        in advanced search
        """

        S3CRUD.__init__(self)

        args = Storage(args)
        if simple is None:
            if "field" in args:
                if "name" in args:
                    name = args.name
                elif "_name" in args:
                    name = args._name
                else:
                    name = "search_simple"
                simple = S3SearchSimpleWidget(field=args.field, name=name, label=args.label, comment=args.comment)
        names = []
        self.__simple = []
        if not isinstance(simple, (list, tuple)):
            simple = [simple]
        for widget in simple:
            if widget is not None:
                name = widget.attr._name
                if name in names:
                    raise SyntaxError("Duplicate widget: %s") % name
                elif not name:
                    raise SyntaxError("Widget with no name")
                else:
                    self.__simple.append((name, widget))
                    names.append(name)

        names = []
        self.__advanced = []
        if not isinstance(advanced, (list, tuple)):
            advanced = [advanced]
        for widget in advanced:
            if widget is not None:
                name = widget.attr._name
                if name in names:
                    raise SyntaxError("Duplicate widget: %s") % name
                elif not name:
                    raise SyntaxError("Widget with no name")
                else:
                    self.__advanced.append((name, widget))
                    names.append(name)

        self.__any = any

        if self.__simple or self.__advanced:
            self.__interactive = True
        else:
            self.__interactive = False
Ejemplo n.º 2
0
    def __init__(self, simple=None, advanced=None, any=False):
        """
        Constructor

        @param simple: the widgets for the simple search form as list
        @param advanced: the widgets for the advanced search form as list
        @param any: match "any of" (True) or "all of" (False) the options
                    in advanced search

        """

        S3CRUD.__init__(self)

        names = []
        self.__simple = []
        if not isinstance(simple, (list, tuple)):
            simple = [simple]
        for widget in simple:
            if widget is not None:
                name = widget.attr._name
                if name in names:
                    raise SyntaxError("Duplicate widget: %s") % name
                elif not name:
                    raise SyntaxError("Widget with no name")
                else:
                    self.__simple.append((name, widget))
                    names.append(name)

        names = []
        self.__advanced = []
        if not isinstance(advanced, (list, tuple)):
            advanced = [advanced]
        for widget in advanced:
            if widget is not None:
                name = widget.attr._name
                if name in names:
                    raise SyntaxError("Duplicate widget: %s") % name
                elif not name:
                    raise SyntaxError("Widget with no name")
                else:
                    self.__advanced.append((name, widget))
                    names.append(name)

        self.__any = any

        if self.__simple or self.__advanced:
            self.__interactive = True
        else:
            self.__interactive = False
Ejemplo n.º 3
0
    def __init__(self, simple=None, advanced=None, any=False):
        """
        Constructor

        @param simple: the widgets for the simple search form as list
        @param advanced: the widgets for the advanced search form as list
        @param any: match "any of" (True) or "all of" (False) the options
                    in advanced search

        """

        S3CRUD.__init__(self)

        names = []
        self.__simple = []
        if not isinstance(simple, (list, tuple)):
            simple = [simple]
        for widget in simple:
            if widget is not None:
                name = widget.attr._name
                if name in names:
                    raise SyntaxError("Duplicate widget: %s") % name
                elif not name:
                    raise SyntaxError("Widget with no name")
                else:
                    self.__simple.append((name, widget))
                    names.append(name)

        names = []
        self.__advanced = []
        if not isinstance(advanced, (list, tuple)):
            advanced = [advanced]
        for widget in advanced:
            if widget is not None:
                name = widget.attr._name
                if name in names:
                    raise SyntaxError("Duplicate widget: %s") % name
                elif not name:
                    raise SyntaxError("Widget with no name")
                else:
                    self.__advanced.append((name, widget))
                    names.append(name)

        self.__any = any

        if self.__simple or self.__advanced:
            self.__interactive = True
        else:
            self.__interactive = False
Ejemplo n.º 4
0
    def __init__(self, label=None, comment=None, fields=None):
        """
        Constructor

        """

        S3CRUD.__init__(self)
        self.__label = label
        self.__comment = comment
        self.__fields = fields

        if self.__fields:
            self.interactive_search = True
        else:
            self.interactive_search = False
Ejemplo n.º 5
0
    def __init__(self, label=None, comment=None, fields=None):
        """
        Constructor

        """

        S3CRUD.__init__(self)
        self.__label = label
        self.__comment = comment
        self.__fields = fields

        if self.__fields:
            self.interactive_search = True
        else:
            self.interactive_search = False
Ejemplo n.º 6
0
    def defaultActionButtons(resource, custom_actions=None, r=None):
        """
            Configure default action buttons

            @param resource: the resource
            @param r: the request, if specified, all action buttons will
                      be linked to the controller/function of this request
                      rather than to prefix/name of the resource
            @param custom_actions: custom actions as list of dicts like
                                   {"label":label, "url":url, "_class":class},
                                   will be appended to the default actions
        """

        from s3crud import S3CRUD

        auth = current.auth
        actions = current.response.s3.actions

        table = resource.table
        actions = None
        has_permission = auth.s3_has_permission
        ownership_required = auth.permission.ownership_required

        labels = current.manager.LABEL
        args = ["[id]"]

        # Choose controller/function to link to
        if r is not None:
            c = r.controller
            f = r.function
        else:
            c = resource.prefix
            f = resource.name

        # "Open" button
        if has_permission("update", table) and \
           not ownership_required("update", table):
            update_url = URL(c=c, f=f, args=args + ["update"])
            S3CRUD.action_button(labels.UPDATE, update_url)
        else:
            read_url = URL(c=c, f=f, args=args)
            S3CRUD.action_button(labels.READ, read_url)
        # Delete action
        # @todo: does not apply selective action (renders DELETE for
        #        all items even if the user is only permitted to delete
        #        some of them) => should implement "restrict", see
        #        S3CRUD.action_buttons
        deletable = current.s3db.get_config(resource.tablename, "deletable",
                                            True)
        if deletable and \
           has_permission("delete", table) and \
           not ownership_required("delete", table):
            delete_url = URL(c=c, f=f, args=args + ["delete"])
            S3CRUD.action_button(labels.DELETE, delete_url)

        # Append custom actions
        if custom_actions:
            actions = actions + custom_actions if actions else custom_actions
Ejemplo n.º 7
0
    def defaultActionButtons(resource, custom_actions=None, r=None):
        """
            Configure default action buttons

            @param resource: the resource
            @param r: the request, if specified, all action buttons will
                      be linked to the controller/function of this request
                      rather than to prefix/name of the resource
            @param custom_actions: custom actions as list of dicts like
                                   {"label":label, "url":url, "_class":class},
                                   will be appended to the default actions
        """

        from s3crud import S3CRUD

        auth = current.auth
        actions = current.response.s3.actions

        table = resource.table
        actions = None
        has_permission = auth.s3_has_permission
        ownership_required = auth.permission.ownership_required

        labels = current.manager.LABEL
        args = ["[id]"]

        # Choose controller/function to link to
        if r is not None:
            c = r.controller
            f = r.function
        else:
            c = resource.prefix
            f = resource.name

        # "Open" button
        if has_permission("update", table) and not ownership_required("update", table):
            update_url = URL(c=c, f=f, args=args + ["update"])
            S3CRUD.action_button(labels.UPDATE, update_url)
        else:
            read_url = URL(c=c, f=f, args=args)
            S3CRUD.action_button(labels.READ, read_url)
        # Delete action
        # @todo: does not apply selective action (renders DELETE for
        #        all items even if the user is only permitted to delete
        #        some of them) => should implement "restrict", see
        #        S3CRUD.action_buttons
        deletable = current.s3db.get_config(resource.tablename, "deletable", True)
        if deletable and has_permission("delete", table) and not ownership_required("delete", table):
            delete_url = URL(c=c, f=f, args=args + ["delete"])
            S3CRUD.action_button(labels.DELETE, delete_url)

        # Append custom actions
        if custom_actions:
            actions = actions + custom_actions if actions else custom_actions
Ejemplo n.º 8
0
    def _datalist(self, r, widget, **attr):
        """
            Generate a dataList

            @param r: the S3Request instance
            @param widget: the widget as a tuple: (label, tablename, icon, filter)
            @param attr: controller attributes for the request
        """

        T = current.T
        s3db = current.s3db
        id = r.id
        context = widget.get("context", None)
        if context:
            context = self._resolve_context(context, id)
        s3db.context = context

        tablename = widget.get("tablename", None)
        resource = s3db.resource(tablename, context=True)
        table = resource.table

        # Config Options:
        # 1st choice: Widget
        # 2nd choice: get_config
        # 3rd choice: Default
        config = resource.get_config
        list_fields = widget.get("list_fields", config("list_fields", None))
        list_layout = widget.get("list_layout", config("list_layout", None))
        orderby = widget.get("orderby", config("list_orderby", ~resource.table.created_on))

        filter = widget.get("filter", None)
        if filter:
            resource.add_filter(filter)

        # Use the widget-index to create a unique ID
        listid = "profile-list-%s-%s" % (tablename, widget["index"])

        # Page size
        pagesize = widget.get("pagesize", 4)
        representation = r.representation
        if representation == "dl":
            # Ajax-update
            get_vars = r.get_vars
            record_id = get_vars.get("record", None)
            if record_id is not None:
                # Ajax-update of a single record
                resource.add_filter(S3FieldSelector("id") == record_id)
                start, limit = 0, 1
            else:
                # Ajax-update of full page
                start = get_vars.get("start", None)
                limit = get_vars.get("limit", None)
                if limit is not None:
                    try:
                        start = int(start)
                        limit = int(limit)
                    except ValueError:
                        start, limit = 0, pagesize
                else:
                    start = None
        else:
            # Page-load
            start, limit = 0, pagesize

        # Ajax-delete items?
        if representation == "dl" and r.http in ("DELETE", "POST"):
            if "delete" in r.get_vars:
                return self._dl_ajax_delete(r, resource)
            else:
                r.error(405, r.ERROR.BAD_METHOD)

        # dataList
        datalist, numrows, ids = resource.datalist(
            fields=list_fields, start=start, limit=limit, listid=listid, orderby=orderby, layout=list_layout
        )
        # Render the list
        ajaxurl = r.url(vars={"update": widget["index"]}, representation="dl")
        data = datalist.html(
            ajaxurl=ajaxurl,
            pagesize=pagesize,
            empty=P(
                I(_class="icon-folder-open-alt"),
                BR(),
                S3CRUD.crud_string(tablename, "msg_no_match"),
                _class="empty_card-holder",
            ),
        )

        if representation == "dl":
            # This is an Ajax-request, so we don't need the wrapper
            current.response.view = "plain.html"
            return data

        # Interactive only below here
        label = widget.get("label", "")
        if label:
            label = T(label)
        icon = widget.get("icon", "")
        if icon:
            icon = TAG[""](I(_class=icon), " ")

        # Permission to create new items?
        create = ""
        insert = widget.get("insert", True)
        if insert and current.auth.s3_has_permission("create", table):
            # if r.tablename = "org_organisation":
            # @ToDo: Special check for creating resources on Organisation profile
            if filter:
                vars = filter.serialize_url(filter)
            else:
                vars = Storage()
            vars.refresh = listid
            if context:
                filters = context.serialize_url(resource)
                for f in filters:
                    vars[f] = filters[f]
            default = widget.get("default", None)
            if default:
                k, v = default.split("=", 1)
                vars[k] = v
            title_create = widget.get("title_create", None)
            if title_create:
                title_create = T(title_create)
            else:
                title_create = S3CRUD.crud_string(tablename, "title_create")
            c, f = tablename.split("_", 1)
            c = widget.get("create_controller", c)
            f = widget.get("create_function", f)
            add_url = URL(c=c, f=f, args=["create.popup"], vars=vars)
            if callable(insert):
                create = insert(r, title_create, add_url)
            else:
                create = A(
                    I(_class="icon icon-plus-sign small-add"), _href=add_url, _class="s3_modal", _title=title_create
                )
            multiple = widget.get("multiple", True)
            if not multiple and hasattr(create, "update"):
                # If this is a multiple=False widget and we already
                # have a record, we hide the create-button
                if numrows:
                    create.update(_style="display:none;")
                else:
                    create.update(_style="display:block;")
                # Script to hide/unhide the create-button on Ajax
                # list updates
                createid = create["_id"]
                if not createid:
                    createid = "%s-add-button" % listid
                    create.update(_id=createid)
                script = """
$('#%(listid)s').on('listUpdate', function() {
 $('#%(createid)s').css({display: $(this).datalist('getTotalItems') ? 'none' : 'block'});
});""" % dict(
                    listid=listid, createid=createid
                )
                current.response.s3.jquery_ready.append(script)

        if pagesize and numrows > pagesize:
            # Button to display the rest of the records in a Modal
            more = numrows - pagesize
            vars = {}
            if context:
                filters = context.serialize_url(resource)
                for f in filters:
                    vars[f] = filters[f]
            if filter:
                filters = filter.serialize_url(resource)
                for f in filters:
                    vars[f] = filters[f]
            c, f = tablename.split("_", 1)
            url = URL(c=c, f=f, args=["datalist.popup"], vars=vars)
            more = DIV(
                A(
                    BUTTON("%s (%s)" % (T("see more"), more), _class="btn btn-mini", _type="button"),
                    _class="s3_modal",
                    _href=url,
                    _title=label,
                ),
                _class="more_profile",
            )
        else:
            more = ""

        # Render the widget
        output = DIV(
            create, H4(icon, label, _class="profile-sub-header"), DIV(data, more, _class="card-holder"), _class="span6"
        )

        return output
Ejemplo n.º 9
0
    def _datalist(self, r, widget, **attr):
        """
            Generate a data list

            @param r: the S3Request instance
            @param widget: the widget definition as dict
            @param attr: controller attributes for the request
        """

        T = current.T
        s3db = current.s3db
        
        context = widget.get("context", None)
        tablename = widget.get("tablename", None)
        resource, context = self._resolve_context(r, tablename, context)

        # Config Options:
        # 1st choice: Widget
        # 2nd choice: get_config
        # 3rd choice: Default
        config = resource.get_config
        list_fields = widget.get("list_fields", 
                                 config("list_fields", None))
        list_layout = widget.get("list_layout", 
                                 config("list_layout", None))
        orderby = widget.get("orderby",
                             config("list_orderby",
                                    ~resource.table.created_on))

        filter = widget.get("filter", None)
        if filter:
            resource.add_filter(filter)

        # Use the widget-index to create a unique ID
        list_id = "profile-list-%s-%s" % (tablename, widget["index"])

        # Page size
        pagesize = widget.get("pagesize", 4)
        representation = r.representation
        if representation == "dl":
            # Ajax-update
            get_vars = r.get_vars
            record_id = get_vars.get("record", None)
            if record_id is not None:
                # Ajax-update of a single record
                resource.add_filter(S3FieldSelector("id") == record_id)
                start, limit = 0, 1
            else:
                # Ajax-update of full page
                start = get_vars.get("start", None)
                limit = get_vars.get("limit", None)
                if limit is not None:
                    try:
                        start = int(start)
                        limit = int(limit)
                    except ValueError:
                        start, limit = 0, pagesize
                else:
                    start = None
        else:
            # Page-load
            start, limit = 0, pagesize

        # Ajax-delete items?
        if representation == "dl" and r.http in ("DELETE", "POST"):
            if "delete" in r.get_vars:
                return self._dl_ajax_delete(r, resource)
            else:
                r.error(405, current.ERROR.BAD_METHOD)

        # dataList
        datalist, numrows, ids = resource.datalist(fields=list_fields,
                                                   start=start,
                                                   limit=limit,
                                                   list_id=list_id,
                                                   orderby=orderby,
                                                   layout=list_layout)
        # Render the list
        ajaxurl = r.url(vars={"update": widget["index"]},
                        representation="dl")
        data = datalist.html(ajaxurl=ajaxurl,
                             pagesize=pagesize,
                             empty = P(I(_class="icon-folder-open-alt"),
                                       BR(),
                                       S3CRUD.crud_string(tablename,
                                                          "msg_no_match"),
                                       _class="empty_card-holder"
                                      ),
                             )

        if representation == "dl":
            # This is an Ajax-request, so we don't need the wrapper
            current.response.view = "plain.html"
            return data

        # Interactive only below here
        label = widget.get("label", "")
        if label:
            label = T(label)
        icon = widget.get("icon", "")
        if icon:
            icon = TAG[""](I(_class=icon), " ")

        s3 = current.response.s3

        if pagesize and numrows > pagesize:
            # Button to display the rest of the records in a Modal
            more = numrows - pagesize
            vars = {}
            if context:
                filters = context.serialize_url(resource)
                for f in filters:
                    vars[f] = filters[f]
            if filter:
                filters = filter.serialize_url(resource)
                for f in filters:
                    vars[f] = filters[f]
            c, f = tablename.split("_", 1)
            url = URL(c=c, f=f, args=["datalist.popup"],
                      vars=vars)
            more = DIV(A(BUTTON("%s (%s)" % (T("see more"), more),
                                _class="btn btn-mini",
                                _type="button",
                                ),
                         _class="s3_modal",
                         _href=url,
                         _title=label,
                         ),
                       _class="more_profile")
        else:
            more = ""

        # Link for create-popup
        create_popup = self._create_popup(r,
                                          widget,
                                          list_id,
                                          resource,
                                          context,
                                          numrows)

        colspan = widget.get("colspan", 1)
        if colspan == 1:
            _class = "span6"
        elif colspan == 2:
            _class = "span12"
        else:
            # Unsupported
            raise

        # Render the widget
        output = DIV(create_popup,
                     H4(icon,
                        label,
                        _class="profile-sub-header"),
                     DIV(data,
                         more,
                         _class="card-holder"),
                     _class=_class)

        return output
Ejemplo n.º 10
0
    def _create_popup(self, r, widget, list_id, resource, context, numrows):
        """
            Render an action link for a create-popup (used in data lists
            and data tables).

            @param r: the S3Request instance
            @param widget: the widget definition as dict
            @param list_id: the list ID
            @param resource: the target resource
            @param context: the context filter
            @param numrows: the total number of rows in the list/table
        """

        create = ""
        insert = widget.get("insert", True)
        
        table = resource.table
        if insert and current.auth.s3_has_permission("create", table):

            s3 = current.response.s3
            tablename = resource.tablename
            
            #if tablename = "org_organisation":
                # @ToDo: Special check for creating resources on Organisation profile

            # URL-serialize the widget filter
            widget_filter = widget.get("filter")
            if widget_filter:
                vars = widget_filter.serialize_url(resource)
            else:
                vars = Storage()

            # URL-serialize the context filter
            if context:
                filters = context.serialize_url(resource)
                for f in filters:
                    vars[f] = filters[f]

            # URL-serialize the widget default
            default = widget.get("default")
            if default:
                k, v = default.split("=", 1)
                vars[k] = v

            # URL-serialize the list ID (refresh-target of the popup)
            vars.refresh = list_id

            # CRUD string
            title_create = widget.get("title_create", None)
            if title_create:
                title_create = current.T(title_create)
            else:
                title_create = S3CRUD.crud_string(tablename, "title_create")

            # Popup URL
            # Default to primary REST controller for the resource being added
            c, f = tablename.split("_", 1)
            c = widget.get("create_controller", c)
            f = widget.get("create_function", f)
            component = widget.get("create_component", None)
            if component:
                args = [r.id, component, "create.popup"]
            else:
                args = ["create.popup"]
            add_url = URL(c=c, f=f, args=args, vars=vars)

            if callable(insert):
                # Custom widget
                create = insert(r, list_id, title_create, add_url)
                
            elif s3.crud.formstyle == "bootstrap":
                # Bootstrap-style action icon
                create = A(I(_class="icon icon-plus-sign small-add"),
                           _href=add_url,
                           _class="s3_modal",
                           _title=title_create,
                           )
            else:
                # Standard action button
                create = A(title_create,
                           _href=add_url,
                           _class="action-btn profile-add-btn s3_modal",
                           )

            if widget.get("type") == "datalist":
                
                # If this is a multiple=False widget and we already
                # have a record, we hide the create-button
                multiple = widget.get("multiple", True)
                if not multiple and hasattr(create, "update"):
                    if numrows:
                        create.update(_style="display:none;")
                    else:
                        create.update(_style="display:block;")
                    # Script to hide/unhide the create-button on Ajax
                    # list updates
                    createid = create["_id"]
                    if not createid:
                        createid = "%s-add-button" % list_id
                        create.update(_id=createid)
                    script = \
'''$('#%(list_id)s').on('listUpdate',function(){
$('#%(createid)s').css({display:$(this).datalist('getTotalItems')?'none':'block'})
})''' % dict(list_id=list_id, createid=createid)
                    s3.jquery_ready.append(script)

        return create
Ejemplo n.º 11
0
    def _create_popup(r, widget, list_id, resource, context, numrows):
        """
            Render an action link for a create-popup (used in data lists
            and data tables).

            @param r: the S3Request instance
            @param widget: the widget definition as dict
            @param list_id: the list ID
            @param resource: the target resource
            @param context: the context filter
            @param numrows: the total number of rows in the list/table
        """

        create = ""
        insert = widget.get("insert", True)

        table = resource.table
        tablename = resource.tablename

        # Default to primary REST controller for the resource being added
        c, f = tablename.split("_", 1)
        c = widget.get("create_controller", c)
        f = widget.get("create_function", f)

        if insert and \
           current.auth.s3_has_permission("create", table, c=c, f=f):

            #if tablename = "org_organisation":
                # @ToDo: Special check for creating resources on Organisation profile

            # URL-serialize the widget filter
            widget_filter = widget.get("filter")
            if widget_filter:
                url_vars = widget_filter.serialize_url(resource)
            else:
                url_vars = Storage()

            # URL-serialize the context filter
            if context:
                filters = context.serialize_url(resource)
                for selector in filters:
                    url_vars[selector] = filters[selector]

            # URL-serialize the widget default
            default = widget.get("default")
            if default:
                k, v = default.split("=", 1)
                url_vars[k] = v

            # URL-serialize the list ID (refresh-target of the popup)
            url_vars.refresh = list_id

            # Indicate that popup comes from profile (and which)
            url_vars.profile = r.tablename

            # CRUD string
            label_create = widget.get("label_create", None)
            if label_create:
                label_create = current.T(label_create)
            else:
                label_create = S3CRUD.crud_string(tablename, "label_create")

            # Popup URL
            component = widget.get("create_component", None)
            if component:
                args = [r.id, component, "create.popup"]
            else:
                args = ["create.popup"]
            add_url = URL(c=c, f=f, args=args, vars=url_vars)

            if callable(insert):
                # Custom widget
                create = insert(r, list_id, label_create, add_url)

            elif current.deployment_settings.ui.formstyle == "bootstrap":
                # Bootstrap-style action icon
                create = A(ICON("plus-sign", _class="small-add"),
                           _href=add_url,
                           _class="s3_modal",
                           _title=label_create,
                           )
            else:
                # Standard action button
                create = A(label_create,
                           _href=add_url,
                           _class="action-btn profile-add-btn s3_modal",
                           )

            if widget.get("type") == "datalist":

                # If this is a multiple=False widget and we already
                # have a record, we hide the create-button
                multiple = widget.get("multiple", True)
                if not multiple and hasattr(create, "update"):
                    if numrows:
                        create.update(_style="display:none;")
                    else:
                        create.update(_style="display:block;")
                    # Script to hide/unhide the create-button on Ajax
                    # list updates
                    createid = create["_id"]
                    if not createid:
                        createid = "%s-add-button" % list_id
                        create.update(_id=createid)
                    script = \
'''$('#%(list_id)s').on('listUpdate',function(){
$('#%(createid)s').css({display:$(this).datalist('getTotalItems')?'none':'block'})
})''' % dict(list_id=list_id, createid=createid)
                    current.response.s3.jquery_ready.append(script)

        return create
Ejemplo n.º 12
0
    def _datalist(self, r, widget, **attr):
        """
            Generate a data list

            @param r: the S3Request instance
            @param widget: the widget definition as dict
            @param attr: controller attributes for the request
        """

        T = current.T

        context = widget.get("context", None)
        tablename = widget.get("tablename", None)
        resource, context = self._resolve_context(r, tablename, context)

        # Config Options:
        # 1st choice: Widget
        # 2nd choice: get_config
        # 3rd choice: Default
        config = resource.get_config
        list_fields = widget.get("list_fields",
                                 config("list_fields", None))
        list_layout = widget.get("list_layout",
                                 config("list_layout", None))
        orderby = widget.get("orderby",
                             config("list_orderby",
                                    config("orderby",
                                           ~resource.table.created_on)))

        filter = widget.get("filter", None)
        if filter:
            resource.add_filter(filter)

        # Use the widget-index to create a unique ID
        list_id = "profile-list-%s-%s" % (tablename, widget["index"])

        # Page size
        pagesize = widget.get("pagesize", 4)
        representation = r.representation
        if representation == "dl":
            # Ajax-update
            get_vars = r.get_vars
            record_id = get_vars.get("record", None)
            if record_id is not None:
                # Ajax-update of a single record
                resource.add_filter(FS("id") == record_id)
                start, limit = 0, 1
            else:
                # Ajax-update of full page
                start = get_vars.get("start", None)
                limit = get_vars.get("limit", None)
                if limit is not None:
                    try:
                        start = int(start)
                        limit = int(limit)
                    except ValueError:
                        start, limit = 0, pagesize
                else:
                    start = None
        else:
            # Page-load
            start, limit = 0, pagesize

        # Ajax-delete items?
        if representation == "dl" and r.http in ("DELETE", "POST"):
            if "delete" in r.get_vars:
                return self._dl_ajax_delete(r, resource)
            else:
                r.error(405, current.ERROR.BAD_METHOD)

        # dataList
        datalist, numrows, ids = resource.datalist(fields=list_fields,
                                                   start=start,
                                                   limit=limit,
                                                   list_id=list_id,
                                                   orderby=orderby,
                                                   layout=list_layout)
        # Render the list
        ajaxurl = r.url(vars={"update": widget["index"]},
                        representation="dl")
        data = datalist.html(ajaxurl=ajaxurl,
                             pagesize=pagesize,
                             empty = P(ICON("folder-open-alt"),
                                       BR(),
                                       S3CRUD.crud_string(tablename,
                                                          "msg_no_match"),
                                       _class="empty_card-holder"
                                      ),
                             )

        if representation == "dl":
            # This is an Ajax-request, so we don't need the wrapper
            current.response.view = "plain.html"
            return data

        # Interactive only below here
        label = widget.get("label", "")
        if label:
            label = T(label)
        icon = widget.get("icon", "")
        if icon:
            icon = ICON(icon)

        if pagesize and numrows > pagesize:
            # Button to display the rest of the records in a Modal
            more = numrows - pagesize
            get_vars_new = {}
            if context:
                filters = context.serialize_url(resource)
                for f in filters:
                    get_vars_new[f] = filters[f]
            if filter:
                filters = filter.serialize_url(resource)
                for f in filters:
                    get_vars_new[f] = filters[f]
            c, f = tablename.split("_", 1)
            f = widget.get("function", f)
            url = URL(c=c, f=f, args=["datalist.popup"],
                      vars=get_vars_new)
            more = DIV(A(BUTTON("%s (%s)" % (T("see more"), more),
                                _class="btn btn-mini",
                                _type="button",
                                ),
                         _class="s3_modal",
                         _href=url,
                         _title=label,
                         ),
                       _class="more_profile")
        else:
            more = ""

        # Link for create-popup
        create_popup = self._create_popup(r,
                                          widget,
                                          list_id,
                                          resource,
                                          context,
                                          numrows)

        _class = self._lookup_class(r, widget)

        # Render the widget
        output = DIV(create_popup,
                     H4(icon,
                        label,
                        _class="profile-sub-header"),
                     DIV(data,
                         more,
                         _class="card-holder"),
                     _class=_class)

        return output
Ejemplo n.º 13
0
    def _datatable(self, r, widget, **attr):
        """
            Generate a data table.

            @param r: the S3Request instance
            @param widget: the widget definition as dict
            @param attr: controller attributes for the request

            @todo: fix export formats
        """

        # Parse context
        context = widget.get("context")
        tablename = widget.get("tablename")
        resource, context = self._resolve_context(r, tablename, context)

        # List fields
        list_fields = widget.get("list_fields")
        if not list_fields:
            # @ToDo: Set the parent so that the fkey gets removed from the list_fields
            #resource.parent = s3db.resource("")
            list_fields = resource.list_fields()

        # Widget filter option
        widget_filter = widget.get("filter")
        if widget_filter:
            resource.add_filter(widget_filter)

        # Use the widget-index to create a unique ID
        list_id = "profile-list-%s-%s" % (tablename, widget["index"])

        # Default ORDERBY
        # - first field actually in this table
        def default_orderby():
            for f in list_fields:
                selector = f[1] if isinstance(f, tuple) else f
                if selector == "id":
                    continue
                rfield = resource.resolve_selector(selector)
                if rfield.field:
                    return rfield.field
            return None

        # Pagination
        representation = r.representation
        get_vars = self.request.get_vars
        if representation == "aadata":
            start = get_vars.get("displayStart", None)
            limit = get_vars.get("pageLength", 0)
        else:
            start = get_vars.get("start", None)
            limit = get_vars.get("limit", 0)
        if limit:
            if limit.lower() == "none":
                limit = None
            else:
                try:
                    start = int(start)
                    limit = int(limit)
                except (ValueError, TypeError):
                    start = None
                    limit = 0  # use default
        else:
            # Use defaults
            start = None

        dtargs = attr.get("dtargs", {})

        if r.interactive:
            s3 = current.response.s3

            # How many records per page?
            if s3.dataTable_pageLength:
                display_length = s3.dataTable_pageLength
            else:
                display_length = widget.get("pagesize", 10)
            dtargs["dt_lengthMenu"] = [[10, 25, 50, -1],
                                       [10, 25, 50,
                                        str(current.T("All"))]]

            # ORDERBY fallbacks: widget->resource->default
            orderby = widget.get("orderby")
            if not orderby:
                orderby = resource.get_config("orderby")
            if not orderby:
                orderby = default_orderby()

            # Server-side pagination?
            if not s3.no_sspag:
                dt_pagination = "true"
                if not limit and display_length is not None:
                    limit = 2 * display_length
                else:
                    limit = None
            else:
                dt_pagination = "false"

            # Get the data table
            dt, totalrows, ids = resource.datatable(fields=list_fields,
                                                    start=start,
                                                    limit=limit,
                                                    orderby=orderby)
            displayrows = totalrows

            if dt.empty:
                empty_str = self.crud_string(tablename, "msg_list_empty")
            else:
                empty_str = self.crud_string(tablename, "msg_no_match")
            empty = DIV(empty_str, _class="empty")

            dtargs["dt_pagination"] = dt_pagination
            dtargs["dt_pageLength"] = display_length
            # @todo: fix base URL (make configurable?) to fix export options
            s3.no_formats = True
            dtargs["dt_base_url"] = r.url(method="", vars={})
            dtargs["dt_ajax_url"] = r.url(vars={"update": widget["index"]},
                                          representation="aadata")
            actions = widget.get("actions")
            if callable(actions):
                actions = actions(r, list_id)
            if actions:
                dtargs["dt_row_actions"] = actions

            datatable = dt.html(totalrows, displayrows, id=list_id, **dtargs)

            if dt.data:
                empty.update(_style="display:none")
            else:
                datatable.update(_style="display:none")
            contents = DIV(datatable, empty, _class="dt-contents")

            # Link for create-popup
            create_popup = self._create_popup(r, widget, list_id, resource,
                                              context, totalrows)

            # Card holder label and icon
            label = widget.get("label", "")
            # Activate if-required
            #if label and isinstance(label, basestring):
            if label:
                label = current.T(label)
            else:
                label = S3CRUD.crud_string(tablename, "title_list")
            icon = widget.get("icon", "")
            if icon:
                icon = ICON(icon)

            _class = self._lookup_class(r, widget)

            # Render the widget
            output = DIV(create_popup,
                         H4(icon, label, _class="profile-sub-header"),
                         DIV(contents, _class="card-holder"),
                         _class=_class)

            return output

        elif representation == "aadata":

            # Parse datatable filter/sort query
            searchq, orderby, left = resource.datatable_filter(
                list_fields, get_vars)

            # ORDERBY fallbacks - datatable->widget->resource->default
            if not orderby:
                orderby = widget.get("orderby")
            if not orderby:
                orderby = resource.get_config("orderby")
            if not orderby:
                orderby = default_orderby()

            # DataTable filtering
            if searchq is not None:
                totalrows = resource.count()
                resource.add_filter(searchq)
            else:
                totalrows = None

            # Get the data table
            if totalrows != 0:
                dt, displayrows, ids = resource.datatable(fields=list_fields,
                                                          start=start,
                                                          limit=limit,
                                                          left=left,
                                                          orderby=orderby,
                                                          getids=False)
            else:
                dt, displayrows = None, 0

            if totalrows is None:
                totalrows = displayrows

            # Echo
            draw = int(get_vars.draw or 0)

            # Representation
            if dt is not None:
                data = dt.json(totalrows, displayrows, list_id, draw, **dtargs)
            else:
                data = '{"recordsTotal":%s,' \
                       '"recordsFiltered":0,' \
                       '"dataTable_id":"%s",' \
                       '"draw":%s,' \
                       '"data":[]}' % (totalrows, list_id, draw)

            return data

        else:
            # Really raise an exception here?
            r.error(415, current.ERROR.BAD_FORMAT)
Ejemplo n.º 14
0
    def _datatable(self, r, widget, **attr):
        """
            Generate a data table.

            @param r: the S3Request instance
            @param widget: the widget definition as dict
            @param attr: controller attributes for the request

            @todo: fix export formats
        """

        # Parse context
        context = widget.get("context")
        tablename = widget.get("tablename")
        resource, context = self._resolve_context(r, tablename, context)

        # List fields
        list_fields = widget.get("list_fields")
        if not list_fields:
            # @ToDo: Set the parent so that the fkey gets removed from the list_fields
            #resource.parent = s3db.resource("")
            list_fields = resource.list_fields()

        # Widget filter option
        widget_filter = widget.get("filter")
        if widget_filter:
            resource.add_filter(widget_filter)

        # Use the widget-index to create a unique ID
        list_id = "profile-list-%s-%s" % (tablename, widget["index"])

        # Default ORDERBY
        # - first field actually in this table
        def default_orderby():
            for f in list_fields:
                selector = f[1] if isinstance(f, tuple) else f
                if selector == "id":
                    continue
                rfield = resource.resolve_selector(selector)
                if rfield.field:
                    return rfield.field
            return None

        # Pagination
        representation = r.representation
        get_vars = self.request.get_vars
        if representation == "aadata":
            start = get_vars.get("displayStart", None)
            limit = get_vars.get("pageLength", 0)
        else:
            start = get_vars.get("start", None)
            limit = get_vars.get("limit", 0)
        if limit:
            if limit.lower() == "none":
                limit = None
            else:
                try:
                    start = int(start)
                    limit = int(limit)
                except (ValueError, TypeError):
                    start = None
                    limit = 0 # use default
        else:
            # Use defaults
            start = None

        dtargs = attr.get("dtargs", {})

        if r.interactive:
            s3 = current.response.s3

            # How many records per page?
            if s3.dataTable_pageLength:
                display_length = s3.dataTable_pageLength
            else:
                display_length = widget.get("pagesize", 10)
            dtargs["dt_lengthMenu"] = [[10, 25, 50, -1],
                                       [10, 25, 50, str(current.T("All"))]
                                      ]

            # ORDERBY fallbacks: widget->resource->default
            orderby = widget.get("orderby")
            if not orderby:
                orderby = resource.get_config("orderby")
            if not orderby:
                orderby = default_orderby()

            # Server-side pagination?
            if not s3.no_sspag:
                dt_pagination = "true"
                if not limit and display_length is not None:
                    limit = 2 * display_length
                else:
                    limit = None
            else:
                dt_pagination = "false"

            # Get the data table
            dt, totalrows, ids = resource.datatable(fields=list_fields,
                                                    start=start,
                                                    limit=limit,
                                                    orderby=orderby)
            displayrows = totalrows

            if dt.empty:
                empty_str = self.crud_string(tablename,
                                             "msg_list_empty")
            else:
                empty_str = self.crud_string(tablename,
                                             "msg_no_match")
            empty = DIV(empty_str, _class="empty")

            dtargs["dt_pagination"] = dt_pagination
            dtargs["dt_pageLength"] = display_length
            # @todo: fix base URL (make configurable?) to fix export options
            s3.no_formats = True
            dtargs["dt_base_url"] = r.url(method="", vars={})
            dtargs["dt_ajax_url"] = r.url(vars={"update": widget["index"]},
                                            representation="aadata")
            actions = widget.get("actions")
            if callable(actions):
                actions = actions(r, list_id)
            if actions:
                dtargs["dt_row_actions"] = actions

            datatable = dt.html(totalrows,
                                displayrows,
                                id=list_id,
                                **dtargs)

            if dt.data:
                empty.update(_style="display:none")
            else:
                datatable.update(_style="display:none")
            contents = DIV(datatable, empty, _class="dt-contents")

            # Link for create-popup
            create_popup = self._create_popup(r,
                                              widget,
                                              list_id,
                                              resource,
                                              context,
                                              totalrows)

            # Card holder label and icon
            label = widget.get("label", "")
            # Activate if-required
            #if label and isinstance(label, basestring):
            if label:
                label = current.T(label)
            else:
                label = S3CRUD.crud_string(tablename, "title_list")
            icon = widget.get("icon", "")
            if icon:
                icon = ICON(icon)

            _class = self._lookup_class(r, widget)

            # Render the widget
            output = DIV(create_popup,
                         H4(icon, label,
                            _class="profile-sub-header"),
                         DIV(contents,
                             _class="card-holder"),
                         _class=_class)

            return output

        elif representation == "aadata":

            # Parse datatable filter/sort query
            searchq, orderby, left = resource.datatable_filter(list_fields,
                                                               get_vars)

            # ORDERBY fallbacks - datatable->widget->resource->default
            if not orderby:
                orderby = widget.get("orderby")
            if not orderby:
                orderby = resource.get_config("orderby")
            if not orderby:
                orderby = default_orderby()

            # DataTable filtering
            if searchq is not None:
                totalrows = resource.count()
                resource.add_filter(searchq)
            else:
                totalrows = None

            # Get the data table
            if totalrows != 0:
                dt, displayrows, ids = resource.datatable(fields=list_fields,
                                                          start=start,
                                                          limit=limit,
                                                          left=left,
                                                          orderby=orderby,
                                                          getids=False)
            else:
                dt, displayrows = None, 0

            if totalrows is None:
                totalrows = displayrows

            # Echo
            draw = int(get_vars.draw or 0)

            # Representation
            if dt is not None:
                data = dt.json(totalrows,
                               displayrows,
                               list_id,
                               draw,
                               **dtargs)
            else:
                data = '{"recordsTotal":%s,' \
                       '"recordsFiltered":0,' \
                       '"dataTable_id":"%s",' \
                       '"draw":%s,' \
                       '"data":[]}' % (totalrows, list_id, draw)

            return data

        else:
            # Really raise an exception here?
            r.error(415, current.ERROR.BAD_FORMAT)
Ejemplo n.º 15
0
    def _create_popup(r, widget, list_id, resource, context, numrows):
        """
            Render an action link for a create-popup (used in data lists
            and data tables).

            @param r: the S3Request instance
            @param widget: the widget definition as dict
            @param list_id: the list ID
            @param resource: the target resource
            @param context: the context filter
            @param numrows: the total number of rows in the list/table
        """

        create = ""

        insert = widget.get("insert", True)
        if not insert:
            return create

        table = resource.table
        tablename = resource.tablename

        # Default to primary REST controller for the resource being added
        c, f = tablename.split("_", 1)
        create_controller = widget.get("create_controller")
        if create_controller:
            c = create_controller
        create_function = widget.get("create_function")
        if create_function:
            f = create_function

        permit = current.auth.s3_has_permission
        create_ok = permit("create", table, c=c, f=f)
        if create_ok:
            if not create_controller or not create_function:
                # Assume not component context
                create_ok = permit("update", r.table, record_id=r.id, c=c, f=f)
        if create_ok:
            #if tablename = "org_organisation":
                # @ToDo: Special check for creating resources on Organisation profile

            # URL-serialize the widget filter
            widget_filter = widget.get("filter")
            if widget_filter:
                url_vars = widget_filter.serialize_url(resource)
            else:
                url_vars = Storage()

            # URL-serialize the context filter
            if context:
                filters = context.serialize_url(resource)
                for selector in filters:
                    url_vars[selector] = filters[selector]

            # URL-serialize the widget default
            default = widget.get("default")
            if default:
                k, v = default.split("=", 1)
                url_vars[k] = v

            # URL-serialize the list ID (refresh-target of the popup)
            url_vars.refresh = list_id

            # Indicate that popup comes from profile (and which)
            url_vars.profile = r.tablename

            # CRUD string
            label_create = widget.get("label_create", None)
            # Activate if-required
            #if label_create and isinstance(label_create, basestring):
            if label_create:
                label_create = current.T(label_create)
            else:
                label_create = S3CRUD.crud_string(tablename, "label_create")

            # Popup URL
            component = widget.get("create_component", None)
            if component:
                args = [r.id, component, "create.popup"]
            else:
                args = ["create.popup"]
            add_url = URL(c=c, f=f, args=args, vars=url_vars)

            if callable(insert):
                # Custom widget
                create = insert(r, list_id, label_create, add_url)

            elif current.deployment_settings.ui.formstyle == "bootstrap":
                # Bootstrap-style action icon
                create = A(ICON("plus-sign", _class="small-add"),
                           _href=add_url,
                           _class="s3_modal",
                           _title=label_create,
                           )
            else:
                # Standard action button
                create = A(label_create,
                           _href=add_url,
                           _class="action-btn profile-add-btn s3_modal",
                           )

            if widget.get("type") == "datalist":

                # If this is a multiple=False widget and we already
                # have a record, we hide the create-button
                multiple = widget.get("multiple", True)
                if not multiple and hasattr(create, "update"):
                    if numrows:
                        create.update(_style="display:none")
                    else:
                        create.update(_style="display:block")
                    # Script to hide/unhide the create-button on Ajax
                    # list updates
                    createid = create["_id"]
                    if not createid:
                        createid = "%s-add-button" % list_id
                        create.update(_id=createid)
                    script = \
'''$('#%(list_id)s').on('listUpdate',function(){
$('#%(createid)s').css({display:$(this).datalist('getTotalItems')?'none':'block'})
})''' % dict(list_id=list_id, createid=createid)
                    current.response.s3.jquery_ready.append(script)

        return create
Ejemplo n.º 16
0
    def _datalist(self, r, widget, **attr):
        """
            Generate a dataList

            @param r: the S3Request instance
            @param widget: the widget as a tuple: (label, tablename, icon, filter)
            @param attr: controller attributes for the request
        """

        T = current.T
        s3db = current.s3db
        id = r.id
        context = widget.get("context", None)
        if context:
            context = self._resolve_context(context, id)
        s3db.context = context

        tablename = widget.get("tablename", None)
        resource = s3db.resource(tablename, context=True)
        table = resource.table

        # Config Options:
        # 1st choice: Widget
        # 2nd choice: get_config
        # 3rd choice: Default
        config = resource.get_config
        list_fields = widget.get("list_fields", config("list_fields", None))
        list_layout = widget.get("list_layout", config("list_layout", None))
        orderby = widget.get(
            "orderby", config("list_orderby", ~resource.table.created_on))

        filter = widget.get("filter", None)
        if filter:
            resource.add_filter(filter)

        # Use the widget-index to create a unique ID
        listid = "profile-list-%s-%s" % (tablename, widget["index"])

        # Page size
        pagesize = 4
        representation = r.representation
        if representation == "dl":
            # Ajax-update
            get_vars = r.get_vars
            record_id = get_vars.get("record", None)
            if record_id is not None:
                # Ajax-update of a single record
                resource.add_filter(S3FieldSelector("id") == record_id)
                start, limit = 0, 1
            else:
                # Ajax-update of full page
                start = get_vars.get("start", None)
                limit = get_vars.get("limit", None)
                if limit is not None:
                    try:
                        start = int(start)
                        limit = int(limit)
                    except ValueError:
                        start, limit = 0, pagesize
                else:
                    start = None
        else:
            # Page-load
            start, limit = 0, pagesize

        # Ajax-delete items?
        if representation == "dl" and r.http in ("DELETE", "POST"):
            if "delete" in r.get_vars:
                return self._dl_ajax_delete(r, resource)
            else:
                r.error(405, r.ERROR.BAD_METHOD)

        # dataList
        datalist, numrows, ids = resource.datalist(fields=list_fields,
                                                   start=start,
                                                   limit=limit,
                                                   listid=listid,
                                                   orderby=orderby,
                                                   layout=list_layout)
        # Render the list
        ajaxurl = r.url(vars={"update": widget["index"]}, representation="dl")
        data = datalist.html(ajaxurl=ajaxurl, pagesize=pagesize)
        if numrows == 0:
            msg = P(I(_class="icon-folder-open-alt"),
                    BR(),
                    S3CRUD.crud_string(tablename, "msg_no_match"),
                    _class="empty_card-holder")
            data.insert(1, msg)

        if representation == "dl":
            # This is an Ajax-request, so we don't need the wrapper
            current.response.view = "plain.html"
            return data

        # Interactive only below here
        label = widget.get("label", "")
        if label:
            label = T(label)
        icon = widget.get("icon", "")
        if icon:
            icon = TAG[""](I(_class=icon), " ")

        # Permission to create new items?
        insert = widget.get("insert", True)
        if insert and current.auth.s3_has_permission("create", table):
            #if r.tablename = "org_organisation":
            # @ToDo: Special check for creating resources on Organisation profile
            if filter:
                vars = filter.serialize_url(filter)
            else:
                vars = Storage()
            vars.refresh = listid
            if context:
                filters = context.serialize_url(resource)
                for f in filters:
                    vars[f] = filters[f]
            default = widget.get("default", None)
            if default:
                k, v = default.split("=", 1)
                vars[k] = v
            title_create = widget.get("title_create", None)
            if title_create:
                title_create = T(title_create)
            else:
                title_create = S3CRUD.crud_string(tablename, "title_create")
            c, f = tablename.split("_", 1)
            c = widget.get("create_controller", c)
            f = widget.get("create_function", f)
            create = A(
                I(_class="icon icon-plus-sign small-add"),
                _href=URL(c=c, f=f, args=["create.popup"], vars=vars),
                _class="s3_modal",
                _title=title_create,
            )
        else:
            create = ""

        if numrows > pagesize:
            # Button to display the rest of the records in a Modal
            more = numrows - pagesize
            vars = {}
            if context:
                filters = context.serialize_url(resource)
                for f in filters:
                    vars[f] = filters[f]
            if filter:
                filters = filter.serialize_url(resource)
                for f in filters:
                    vars[f] = filters[f]
            c, f = tablename.split("_", 1)
            url = URL(c=c, f=f, args=["datalist.popup"], vars=vars)
            more = DIV(A(
                BUTTON(
                    "%s (%s)" % (T("see more"), more),
                    _class="btn btn-mini",
                    _type="button",
                ),
                _class="s3_modal",
                _href=url,
                _title=label,
            ),
                       _class="more_profile")
        else:
            more = ""

        # Render the widget
        output = DIV(create,
                     H4(icon, label, _class="profile-sub-header"),
                     DIV(data, more, _class="card-holder"),
                     _class="span6")

        return output
Ejemplo n.º 17
0
    def _datalist(self, r, widget, **attr):
        """
            Generate a dataList

            @param r: the S3Request instance
            @param widget: the widget as a tuple: (label, tablename, icon, filter)
            @param attr: controller attributes for the request
        """

        context = widget.get("context", None)
        if context:
            context = "(%s)" % context
            current.s3db.context = S3FieldSelector(context) == r.id

        tablename = widget.get("tablename", None)
        resource = current.s3db.resource(tablename, context=True)
        table = resource.table

        # Config Options:
        # 1st choice: Widget
        # 2nd choice: get_config
        # 3rd choice: Default
        config = resource.get_config
        list_fields = widget.get("list_fields", 
                                 config("list_fields", None))
        list_layout = widget.get("list_layout", 
                                 config("list_layout", None))
        orderby = widget.get("orderby",
                             config("list_orderby",
                                    ~resource.table.created_on))

        filter = widget.get("filter", None)
        if filter:
            resource.add_filter(filter)

        # Use the widget-index to create a unique ID
        listid = "profile-list-%s-%s" % (tablename, widget["index"])

        c, f = tablename.split("_", 1)

        # Permission to create new items?
        # @ToDo: Special check for creating resources on Organisation profile
        if current.auth.s3_has_permission("create", table):
            if filter:
                vars = filter.serialize_url(filter)
            else:
                vars = Storage()
            vars.refresh = listid
            if context:
                vars[context] = r.id
            create = A(I(_class="icon icon-plus-sign small-add"),
                       _href=URL(c=c, f=f, args=["create.popup"], vars=vars),
                       _class="s3_modal",
                       )
        else:
            create = "" 

        # Page size
        pagesize = 4
        representation = r.representation
        if representation == "dl":
            # Ajax-update
            get_vars = r.get_vars
            record_id = get_vars.get("record", None)
            if record_id is not None:
                # Ajax-update of a single record
                resource.add_filter(S3FieldSelector("id") == record_id)
                start, limit = 0, 1
            else:
                # Ajax-update of full page
                start = get_vars.get("start", None)
                limit = get_vars.get("limit", None)
                if limit is not None:
                    try:
                        start = int(start)
                        limit = int(limit)
                    except ValueError:
                        start, limit = 0, 4
                else:
                    start = None
        else:
            # Page-load
            start, limit = 0, 4

        # Ajax-delete items?
        if representation == "dl" and r.http in ("DELETE", "POST"):
            if "delete" in r.get_vars:
                return self._dl_ajax_delete(r, resource)
            else:
                r.error(405, r.ERROR.BAD_METHOD)

        # dataList
        datalist, numrows, ids = resource.datalist(fields=list_fields,
                                                   start=start,
                                                   limit=limit,
                                                   listid=listid,
                                                   orderby=orderby,
                                                   layout=list_layout)
        # Render the list
        ajaxurl = r.url(vars={"update": widget["index"]},
                        representation="dl")
        data = datalist.html(ajaxurl=ajaxurl, pagesize=pagesize)
        if numrows == 0:
            msg = P(I(_class="icon-folder-open-alt"),
                    BR(),
                    S3CRUD.crud_string(resource.tablename,
                                       "msg_no_match"),
                    _class="empty_card-holder")
            data.insert(1, msg)

        if representation == "dl":
            # This is an Ajax-request, so we don't need the wrapper
            current.response.view = "plain.html"
            return data

        label = widget.get("label", "")
        if label:
            label = current.T(label)
        icon = widget.get("icon", "")
        if icon:
            icon = TAG[""](I(_class=icon), " ")

        # Render the widget
        output = DIV(create,
                     H4(icon,
                        label,
                        _class="profile-sub-header"),
                     DIV(data,
                         _class="card-holder"),
                     _class="span6")

        return output