Module:Tablebuilder

From The Satanic Wiki
Jump to navigation Jump to search

Documentation for this module may be created at Module:Tablebuilder/doc

-- <nowiki>
--|Creates a new html table using the functions and mw.html library
---Variables prefixed with h are mw.html nodes. e.g. hTable is created using mw.html.create('table')
local p = {}
local tableModel = {}
local libraryUtil = require( 'libraryUtil' )

-- //Lazy load methods
local createCol,appendRow,appendCol,createRow

--% Creates  table model
--@  arrTable (table) A Two dimensional array of the table ,e.g. {{'header','header2'},{"cell1","cell2"}}
--@ sTableDescription (string) Caption of the table (e.g."green")
--@ sStyle (string) Table style ( e.g. sStyle="color:green")
--@ tClass (table)- Table classes (e.g. {"wikitable","sortable"})
--: (table) a tablemodel "class" that allows users to create tables 
function tableModel.new(arrExtData,sTableDescription, sStyle,tClass)
    local  self = {} 
    local checkSelf = libraryUtil.makeCheckSelfFunction( 'tableModel', 'obj', self, 'tableModel object' )

    self.tableFormatting = {caption="",class={},style=""}
    self.arrTable =  {}

    --% Outputs the attributes of a html table
    --@ iRow (number) Row number
    --@ iCol (number) Column number
    --: (table) attributes for a specific cell (row + col)
    function self:getAttribs(iRow, iCol)
        checkSelf(self,"getAttribs")
        if (self.arrTable[iRow] and self.arrTable[iRow][iCol]) then
            return self.arrTable[iRow][iCol]
        end
    end
    --% Sets an attribute to a cell
    --@ iRow (number) Row number
    --@ iCol (number) Column number
    --@ oCellAttributes (table) Attributes to be set, a single string attribute  or many as a table 
    --@ oAttrVal (string) attribute to be set
    function self:setCellAttr(iRow,iCol, oCellAttributes, oAttrVal)
        checkSelf(self,"setCellAttr")
        if (self.arrTable[iRow] and self.arrTable[iRow][iCol]  ) then
            local oTableData = self:getAttribs(iRow,iCol)
            local sCellVal = oTableData.sValue
            
            if  oCellAttributes and type (oCellAttributes)=="string" then
                oTableData.oFormatting = {[oCellAttributes]=oAttrVal}
            end
        
            if (type(oCellAttributes)=="table" and  next(oCellAttributes)) then
                oTableData.oFormatting = oCellAttributes
            end
        end
    end
    --% Sets a value to a cell	
    --@ sValue (string) Value to be set to a table
    --@ iRow (number) Row number
    --@ iCol (number)  Column number
    --@ formatting (table) Formatting to be set, e.g. {"style"="color:red"}
    --@ header (boolean) Sets this cell to a header  (true to set, false to remove)
    function self:setCell (sValue,iRow,iCol,oFormatting,bHeader)
        checkSelf(self,"setCell")
        if self.arrTable[iRow] and (self.arrTable[iRow][iCol]) then
            local oTableData = self:getAttribs(iRow,iCol)
            oTableData.sValue = sValue
            oTableData.bHeader = bHeader
            
            if (not(self.arrTable[iRow]["rowdata"])) then
                self.arrTable[iRow]["rowdata"]={}
            end
            self:setCellAttr(iRow,iCol,oFormatting)
        end
    end
    --% Imports a lua table, changes it to an html table
    --@ arrInput (table) Table two dimensional (e.g. {{'f','z'}})
    function self:setTable(arrInput)
        checkSelf(self,"setTable")
        local bHeader 
        
        if arrInput and type(arrInput) =="table" then
            for iRow,tCols in pairs(arrInput) do
                
                if type(tCols)=="table" then
                    self.arrTable[iRow] = {}
                    for iCol,sValue in ipairs(tCols) do
                        bHeader = (iRow==1)
                        self.arrTable[iRow][iCol]={}
                        self:setCell (sValue,iRow,iCol,{},bHeader)
                    end
                else
                    bHeader = true
                    self.arrTable[1] = self.arrTable[1] or {}
                    local iCol = #self.arrTable[1]+1
                    self.arrTable[1][iCol] = {}
                    self:setCell (tCols,1,iCol,{},bHeader)
                end
            end
        end
    end

    --% Sets data to a cell 
    --@ iRow (number) Row number
    --@ iCol (number) Column number
    --@ sField (string) internal table field to set data
    --@ sNewValue (string) new value
    function self:setData(iRow,iCol,sField, sNewValue)
        checkSelf(self,"setData")
        if (self.arrTable[iRow] and self.arrTable[iRow][iCol]
            and self.arrTable[iRow][iCol][sField]) then
            local arrMetaData = self.arrTable[iRow][iCol]
            arrMetaData[sField] = sNewValue
        end
    end
    --% Gets a cell from a table
    --@ iRow (number) Row number
    --@ iCol (number)  Column number
    --: (table) attributes for a specific cell (row + col)
    function self:getCell(iRow,iCol)
        checkSelf(self,"getCell")
        if self.arrTable[iRow] and self.arrTable[iRow][iCol] then  
            return self.arrTable[iRow][iCol].sValue
        end
    end
    --% Sets the style of a cell
    --@ iRow (number) Row number
    --@ iCol (number)  Column number
    --@ sCellStyle (string) Cell style, e.g. ("color")
    --@ sAttrVal (string) Cell attribute, e.g. ("blue")
    function self:setCellStyle(iRow,iCol,sCellStyle,sAttrVal)
        self:setCellAttr(iRow,iCol,sCellStyle,sAttrVal)
    end
    --% Sets a cell as a header
    --@ iRow (number) Row number
    --@ iCol (number) Column number
    --@ bHeader (boolean) true if header
    function self:setCellHeader(iRow,iCol,bHeader)
        checkSelf(self,"setCellHeader")
        if self.arrTable[iRow] and self.arrTable[iRow][iCol] then
            local oTableData = self:getAttribs(iRow,iCol)
            local sCellVal =  oTableData.sValue      
            
            if (type(bHeader)=="boolean") then
                oTableData["bHeader"] =  bHeader
            end 
        end
    end

    --% Creates a row 
    --@ tFormatting (string) Formatting to be set, e.g. {"style"="color:red"}.)
    --: (table) A mw.html node containing a row
    function createRow(tFormatting)
        local hTableRow= mw.html.create('tr')
        
        if(tFormatting and type(tFormatting)=="table" and next(tFormatting)) then
            hTableRow:attr(tFormatting)
            hTableRow:node(sHeadingCol) 
        end
        hTableRow:done()
        
        return hTableRow
    end
    
    --% Appends a row to a table 
    --@ hTable (table) hTable mw.html table node --e.g. mw.html.create('table')) 
    --@ tFormatting (table)  {["style"]="color:green"}
    --: (table) A full mw.html table 
    function appendRow(hTable, hRow,tFormatting)
        if(tFormatting and type(tFormatting)=="table" and next(tFormatting)) then
               hRow:attr(tFormatting)
        end
        
        if (hRow) and  (hTable) then
            hTable:node(hRow)
        else 
           return "Syntax error: Row and table cannot be nil!"  
        end
        
        return hTable:done()
    end 
    
    --% Creates a new column 
    --@ sColValue (string) Value of table column
    --@ tFormatting (table) Formatting to be set, e.g. {"style"="color:red"}.
    --@ bHeader (boolean) Returns true if header
    --: (table) A full mw.html node containing a "td"
    function createCol(sColValue,tFormatting,bHeader)
        local sTagCol = "td"
        
        if (bHeader) then 
            sTagCol ="th"
        end
        
        local hHeadingCol =mw.html.create(sTagCol)
        if  (sColValue and type(sColValue)=="string") or  sColValue =="" or type(sColValue)=="number"  then
            hHeadingCol:wikitext(sColValue)
        end
        
        if (tFormatting and type(tFormatting)=="table") then
            local sAttribute, sValues = next(tFormatting)
             if (type(sAttribute)=="string" and sValues) then 
                hHeadingCol :attr(tFormatting )
             else
                if (sAttribute) then
                    return "Error: Attributes need Key and value ({[key]='value'}), e.g. {['style']='color:blue'}"
                end
             end
        end
        
        hHeadingCol:done()
        return hHeadingCol
    end
    --% Appends a column cell to a row 
    --@ hColumn (table) A mw.html node containing a column (html th)
    --@ hTableRow (table) A mw.html node containing a cell (html td)
    --@ tFormatting (table) Formatting to be set, e.g. {"style"="color:red"}.
    --: (string) An error if the table is invalid or nil if not
    function appendCol(hTableRow,hColumn,tFormatting)
        local sColType = type (hColumn)
        
        if sColType =="string" or  sColType =="number" or  sColType =="boolean" then
            hColumn = createCol(hColumn)
        end
        
        if(tFormatting and type(tFormatting)=="table" and next(tFormatting)) then
            local sAttribute, sValues = next(tFormatting)
            if (type(sAttribute)=="string" and sValues) then 
                hHeadingCol :attr(tFormatting )
            else
                if (sAttribute) then
                    return "Error: Attributes need Key and value ({[key]='value'}), e.g. {['style']='color:blue'}"
                end
            end
        end
        
        if (hTableRow and hColumn and type(hColumn)=="table" ) then
            hTableRow = hTableRow:node(hColumn)
        else 
           return "Syntax error: Table row and table column cannot be nil!"  
        end
    end
    --% Outputs the html table
    --: (table) An mw.html node containing the whole table
    function self:getTable ()
        checkSelf(self,"getTable")
        local hRow,hCell 
        local hTable = mw.html.create("table")
        hTable:tag("caption")
            :wikitext(self.tableFormatting.caption)
        hTable:cssText(self.tableFormatting.style)
        
        for i,sClassName in pairs(self.tableFormatting.class) do
            if type(sClassName) == "string" then
                hTable:addClass(sClassName)
            end
        end
        for iRow,tRow in pairs(self.arrTable) do
            if (self.arrTable[iRow]) then
                tRowFormat = self.arrTable[iRow]["rowdata"] 
            end
            hRow = createRow(tRowFormat)
            
            for iCol,oCell in ipairs(tRow)  do
                if (oCell) then
                    hCell = createCol(oCell.sValue,oCell.oFormatting,oCell.bHeader)
                    appendCol(hRow,hCell)
                end
            end
            appendRow(hTable, hRow)
        end
        
        return hTable:done()
    end
    --% Sets the rows and columns of table
    --iRows (number) Number of rows in the table
    --iColumns (number) Number of columns in the table
    function self:setGrid(iRows,iColumns)
        checkSelf(self,"setGrid")
        local bHeader

        for iRowCount=0,iRows  do
            self.arrTable[iRowCount] = {}
            bHeader = false
            for iColCount=0, iColumns do
                bHeader = (iRowCount==1)
                self.arrTable[iRowCount][iColCount] ={["sValue"]= "",["oFormatting"] =  {},["bHeader"] =  bHeader}
            end
        end
    end
    --% Prints out text representation of the table
    --: (string) text representation of the table
    function self:getGrid()
        checkSelf(self,"getGrid")
        local sGrid  = "\tCol1\tCol2\n"
        local sValue 
        for iRow =1,#self.arrTable do
            sGrid = sGrid ..iRow.."\t|"
            for iCol =1, #self.arrTable[iRow] do
                sValue = self:getCell(iRow,iCol) or ""
                sGrid = sGrid .."\t" .. sValue .. "\t|"
            end
            sGrid = sGrid .."\n"
        end
        return sGrid
    end
    --% Sets the styling of a table
    --@ sTableDescription (string) Description or caption of the table
    --@ sStyle (string) the styles (e.g. "color:green")
    --@ tClass  (table) the css classes the table will use (e.g.{"bluetable","greentext"}
    function self:setTableFormat(sTableDescription, sStyle,tClass)
        checkSelf(self,"setTableFormat")
        if sTableDescription and type(sTableDescription)=="string"  then
              self.tableFormatting.caption = sTableDescription
        end
        
        if (tClass) then
            if type(tClass)=="table" and next(tClass) then  
                self.tableFormatting.class= tClass
            end
        end 
    
        if(sStyle and  type(sStyle)=="string" and sStyle~="") then
            self.tableFormatting.style =sStyle
        end
       
    end 
    --% Sets the formatting of a table
    --@ iRow (number) The row to add the styling
    --@ tFormatting (table) Formatting to be set, e.g. {"style"="color:red"}.
    function self:setRowFormat(iRow,tFormatting)
        checkSelf(self,"setRowFormat")
        if (iRow and  self.arrTable[iRow] and self.arrTable[iRow]["rowdata"]) then
            self.arrTable[iRow]["rowdata"] = tFormatting
        end
    end 
    --% Adds a new row to a table
    --@ iRow (number)  The index of the row to add
    function self:addRow(iRow)
        checkSelf(self,"addRow")
        local sValue =""
        local tColumns ={}
        local iRowToAdd = tonumber(iRow) or 1
        
        if iRow and (iRow>=(#self.arrTable +2) or iRow<1) then
            return
        end
        
        if self.arrTable and self.arrTable[1]  then
            iRowToAdd = iRow or #self.arrTable+1
             for i=1,#self.arrTable[1] do
                tColumns[i] = {}
             end
        end
        table.insert(self.arrTable,iRowToAdd,tColumns)
    end
    --% Removes a row from the table	
    --@ iRow (number) The index of the row to remove
    function self:removeRow(iRow)
        checkSelf(self,"removeRow")
        if self.arrTable[iRow] then
            table.remove(self.arrTable,iRow)
        end
    end
    --% Sets the contents of a row
    --@ iRow (number) The index of the row to set
    --@ tTable (table) contents (e.g. {2,3})
    function self:setRow(iRow,tTable)
        checkSelf(self,"setRow")
        if iRow and self.arrTable[iRow] and tTable then
            for iCol,sValue in pairs(tTable) do
                self:setCell(sValue,iRow,iCol)
            end
        end
    end
   
    --% Adds a new column to the table
    --@ sColName(string) Name of the column
    --@ iCol (number) The index of the column to set
    function self:addCol(sColName,iCol)
        checkSelf(self,"addCol")

        if iCol and self.arrTable 
            and self.arrTable[1]
            and (iCol>=#self.arrTable[1] +2 or  iCol<1) then
            return
        end

        if self.arrTable and self.arrTable[1] and not(iCol) then
            iCol = #self.arrTable[1]+1
        end

        if self.arrTable[1] then 
            table.insert(self.arrTable[1],iCol,{})
            self:setCell(sColName,1,iCol,{},true)
        end
    end
    
    --% Removes a new column to the table
    --@ iCol (number) The index of the column to remove
    function self:removeCol(iCol)
        checkSelf(self,"removeCol")

        if iCol then
            for i,v in pairs(self.arrTable) do
                if self.arrTable[i] and self.arrTable[i][iCol] then
                    table.remove(self.arrTable[i],iCol)
                end    
            end
        end
    end
    --% Gets number of rows in table
    --: (number) Number of rows
    function self:getRowCount()
        checkSelf(self,"getRowCount")
        return #self.arrTable
    end
    --% Gets number of columns in table
    --: (number) Number of columns
    function self:getColCount(iRow)
        checkSelf(self,"getColCount")
        iRow = iRow or 1
        if self.arrTable[iRow] then
            return #self.arrTable[iRow]
        end
        return 0
    end
    --% Initializes the tablebuilder (internal use)
    function initialize()
        self.setTableFormat(self,sTableDescription, sStyle,tClass)
        self:setTable(arrExtData)
    end
    -- //Constructor 
    initialize()
    
    return self
end
--%  Create a new table builder 
--@ arrExtData (table) A two dimensional array containing a table e.g {{"Girls","Boys"},{"Xena","Hercules"}}
--@ sTableDescription (string) A caption for the table  e.g. "Table of boys and girls
--@ sStyle (string) Basic styling for the table  e.g. "background:green"
--@ tClass (table) CSS classes for the whole table e.g. {"boysandgirls","red"}
function p.new(arrExtData,sTableDescription, sStyle,tClass)
    return tableModel.new(arrExtData,sTableDescription, sStyle,tClass)
end

-- Test code
function p.test(frame)
    -- Array consisting of rows and columns
    local tRowData = {
    -- Row Columns
        {"1","2"},
        {"44","3"}, 
        {"6","8"}, 
    }

    local c = tableModel.new(tRowData,"Table","",{"wikitable"})
    local row1 = 4
    local col1 = 1
    local celltext = "green"
    local cellFormat = {["style"]="color:green"}
    
    c:addRow()
    c:setCell("7",row1,col1)
    c:setCell("2",row1,2)
    
    local row2 = 1
    local col2 = 1
    
    c:setCell(celltext,row2,col2,cellFormat)
    
    return c:getTable()
end
-- End Test code
return p