A table of one text column, and three further button columns of up and down arrows and a Remove button.
Below is a TableList widget.
apple | ↓ | Remove | |
pear | ↑ | ↓ | Remove |
banana | ↑ | ↓ | Remove |
strawberry | ↑ | Remove |
This table lists the Responders called to produce this page:
skiwidgets,9202 | SubmitData | Sets up title and widget description |
skiwidgets,9204 | This page | lists.TableList template |
This is a ShowCallData widget, which displays the contents of the skicall.call_data dictionary.
{}
Below is the Python file which populates this page.
import os, json from skipole import FailPage, GoTo, ValidateError, ServerError, ServeFile, PageData, SectionData # In this example, TABLECONTENTS is a global variable, normally data would be # taken from a file or database or other source of data. TABLECONTENTS = ['apple', 'pear', 'banana', 'strawberry'] def index(skicall): "Called by a SubmitData responder, and sets up the page" # the title and widget decription is in section 'header' which contains a # HeadText widget with name 'title' and a TextBlockPara widget with name 'widgetdesc' # It also has a ButtonLink2 widget with name 'tomodule' headersection = SectionData('header') headersection['title', 'large_text'] = 'TableList' # A textblock contains the widget description ref = "widgets.lists.TableList" headersection['widgetdesc','textblock_ref'] = ref headersection['widgetdesc','text_refnotfound'] = f'Textblock reference {ref} not found' # link to this widgets module page headersection['tomodule','button_text'] = "Module: lists" headersection['tomodule','link_ident'] = skicall.makepath('lists') skicall.update(headersection) # this code file contents is placed in section 'codefile' which contains a # PreText widget with name 'pretext' codesection = SectionData('codefile') code = os.path.realpath(__file__) with open(code) as f: codesection['pretext', 'pre_text'] = f.read() skicall.update(codesection) # fill in the TableList widget with initial values, in this case the list items # are taken from TABLECONTENTS, and the get fields for up, down, remove are the # row number of the button pressed pd = PageData() pd['tablelist','contents'] = [ [TABLECONTENTS[0], "0", "0", "0"], [TABLECONTENTS[1], "1", "1", "1"], [TABLECONTENTS[2], "2", "2", "2"], [TABLECONTENTS[3], "3", "3", "3"] ] # Normally the list would be altered on the source of the data, such as a database. # In this example the list is set onto the client browser, using the ident_data # attribute of pd. The client browser will send this list back when a widget # submits data and it will be available as the skicall.ident_data attribute. So # the list is persistent to the client session. # As ident_data must be a string, this example uses json.dumps to serialise a # list of indexes to the TABLECONTENTS list, rather than the full list itself. pd.ident_data = json.dumps([0,1,2,3]) skicall.update(pd) def _createtablecontents(skicall, indexlist): """Takes a list of index numbers, such as [0,1,2,3], these numbers being indexes of the TABLECONTENTS list, and creates the new table contents, then updates skicall""" if not indexlist: # The table is empty pd = PageData() pd['tablelist','contents'] = [] pd['tablelist','hide'] = True pd.ident_data = "[]" skicall.update(pd) return contents = [] for rownumber, itemindex in enumerate(indexlist): rowstring = str(rownumber) rowlist = [TABLECONTENTS[itemindex], rowstring, rowstring, rowstring] contents.append(rowlist) pd = PageData() pd['tablelist','contents'] = contents pd.ident_data = json.dumps(indexlist) skicall.update(pd) def up(skicall): "Called to move the row upwards" # the get field of the button pressed is in skicall.call_data if ('tablelist', 'contents') not in skicall.call_data: raise FailPage(message="No submission received") if skicall.ident_data is None: # no table data has been received raise FailPage(message="Invalid submission received") try: # get the row of the table from the button pressed row = int(skicall.call_data['tablelist', 'contents']) if not row: # row position is 0, cannot move above row 0 return indexlist = json.loads(skicall.ident_data) # indexlist is a list such as [0,1,2,3] giving the order of # the indexes of the TABLECONTENTS list # move the selected row in the indexlist itemtomove = indexlist.pop(row) indexlist.insert(row-1, itemtomove) except: raise FailPage(message="Invalid submission received") # update the table using the new indexlist _createtablecontents(skicall, indexlist) def down(skicall): "Called to move the row downwards" # the get field of the button pressed is in skicall.call_data if ('tablelist', 'contents') not in skicall.call_data: raise FailPage(message="No submission received") if skicall.ident_data is None: # no table data has been received raise FailPage(message="Invalid submission received") try: # get the row of the table from the button pressed row = int(skicall.call_data['tablelist', 'contents']) indexlist = json.loads(skicall.ident_data) # indexlist is a list such as [0,1,2,3] giving the order of # the indexes of the TABLECONTENTS list if row >= len(indexlist) - 1: # row is at the last position, cannot move further down return # move the selected row in the indexlist itemtomove = indexlist.pop(row) indexlist.insert(row+1, itemtomove) except: raise FailPage(message="Invalid submission received") # update the table using the new indexlist _createtablecontents(skicall, indexlist) def remove(skicall): "Called to remove a row" # the get field of the button pressed is in skicall.call_data if ('tablelist', 'contents') not in skicall.call_data: raise FailPage(message="No submission received") if skicall.ident_data is None: # no table data has been received raise FailPage(message="Invalid submission received") try: # get the row of the table from the button pressed row = int(skicall.call_data['tablelist', 'contents']) indexlist = json.loads(skicall.ident_data) # indexlist is a list such as [0,1,2,3] giving the order of # the indexes of the TABLECONTENTS list # remove the selected row in the indexlist itemtoremove = indexlist.pop(row) except: raise FailPage(message="Invalid submission received") # update the table using the new indexlist _createtablecontents(skicall, indexlist)