Coverage for khufu/tables/sortable_table.py : 14%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#!/usr/bin/env python
2# encoding: utf-8
3"""
4*A sortable, customisable HTML table*
6:Author:
7 David Young
8"""
9from __future__ import division
10from builtins import str
11from builtins import object
12from past.utils import old_div
13from . import *
14import sys
15import os
16import datetime
17import math
18import re
19# from ..__init__ import *
20from khufu.typography import *
21from khufu.addons import *
22from khufu.tables import *
23from khufu.helpers import *
24from fundamentals import times
26class sortable_table(object):
27 """
28 *The worker class for the sortable_table module*
30 **Key Arguments**
32 - ``dbConn`` -- mysql database connection
33 - ``log`` -- logger
34 - ``currentPageUrl`` -- the baseurl for the webpage
35 - ``columnsToDisplay`` -- a list of column objects for the table
36 - ``defaultSort`` -- the column to sort on by default
37 - ``tableRowsDictionary`` -- dictionary of column names and values (e.g. a mysql query result)
39 """
41 def __init__(
42 self,
43 log,
44 dbConn=False,
45 currentPageUrl="",
46 columnsToDisplay=[],
47 defaultSort=False,
48 tableRowsDictionary={}
49 ):
50 self.log = log
51 self.dbConn = dbConn
52 self.currentPageUrl = currentPageUrl
53 self.columnsToDisplay = columnsToDisplay
54 self.defaultSort = defaultSort
55 self.tableRowsDictionary = tableRowsDictionary
56 # xt-self-arg-tmpx
58 # VARIABLE DATA ATRRIBUTES
59 self.colors = ["green", "blue", "red", "yellow",
60 "orange", "violet", "magenta", "cyan", ]
61 self.modifyDisplayNameDict = {}
62 self.modifySortByDict = {}
63 self.modifyColumnWidths = []
64 self.headerPopoverText = "click to sort"
65 self.searchKeyAndColumn = False
66 self.columnsToHide = []
67 self.columnWidth = int(math.floor(old_div(100, len(self.columnsToDisplay))))
68 self.extraColumnWidth = 100 - \
69 self.columnWidth * len(self.columnsToDisplay)
71 # DETERMINE HOW TABLE IS TO BE SORTED FROM URL
72 thisSort = re.search(
73 r'sortBy=(\w+)&',
74 self.currentPageUrl,
75 flags=0 # re.S
76 )
77 if thisSort:
78 thisSort = thisSort.group(1)
79 elif self.defaultSort:
80 thisSort = self.defaultSort
81 else:
82 thisSort = False
84 thisSortDesc = re.search(
85 r'sortDesc=(\w+)&?',
86 self.currentPageUrl,
87 flags=0 # re.S
88 )
89 if thisSortDesc:
90 thisSortDesc = thisSortDesc.group(1)
91 else:
92 thisSortDesc = "False"
94 arrow = ""
95 if "true" in thisSortDesc.lower():
96 arrow = coloredText(
97 text="""  <i class="icon-arrow-up4"></i>""" % locals(),
98 color="red",
99 )
100 else:
101 arrow = coloredText(
102 text="""  <i class="icon-arrow-down4"></i>""",
103 color="red",
104 )
105 self.thisSort = thisSort
106 self.thisSortDesc = thisSortDesc
107 self.arrow = arrow
109 # REMOVE SORT AND SORTDESC FROM URL TO GENERAL A BASEURL FOR HEADER
110 # SORTING
111 reSort = re.compile(r'sortBy=\w+&?')
112 reDesc = re.compile(r'sortDesc=\w+&?')
113 self.baseUrl = reSort.sub("", self.currentPageUrl)
114 self.baseUrl = reDesc.sub("", self.baseUrl)
115 thisUrl = self.baseUrl
116 if thisUrl[-3:] == ".py":
117 thisUrl = "%(thisUrl)s?" % locals()
118 elif "?" not in thisUrl:
119 thisUrl = "%(thisUrl)s?" % locals()
120 elif thisUrl[-1:] not in ["?", "&"]:
121 thisUrl = "%(thisUrl)s&" % locals()
122 self.baseUrl = thisUrl
124 return None
126 def close(self):
127 del self
128 return None
130 def get(self):
131 """
132 *get the sortable_table object*
134 **Return**
136 - ``sortable_table``
138 """
140 tableHead = self.get_table_head()
141 tbody = self.get_table_body()
143 sortable_table = table(
144 caption='',
145 thead=tableHead,
146 tbody=tbody,
147 striped=True,
148 bordered=False,
149 hover=True,
150 condensed=True,
151 )
153 return sortable_table
155 def get_table_head(
156 self):
157 """
158 *get table head*
160 **Return**
162 - ``tableHead`` -- the table head
164 """
165 tableHead = ""
167 # BUILD THE TABLE HEADER
168 _popover = popover(
169 tooltip=True,
170 placement="bottom", # [ top | bottom | left | right ]
171 trigger="hover", # [ False | click | hover | focus | manual ]
172 title=self.headerPopoverText,
173 content=False,
174 delay=600
175 )
177 colorIndex = 0
178 columnIndex = 0
180 for i, c in enumerate(self.columnsToDisplay):
181 # build sort url
182 direction = "False"
183 if c in list(self.modifySortByDict.keys()):
184 columnSortByAlias = self.modifySortByDict[c]
185 else:
186 columnSortByAlias = c
188 if not columnSortByAlias:
189 newSortUrl = False
190 thisPopover = False
191 thisArrow = ""
192 else:
193 thisPopover = _popover
194 if self.thisSort == columnSortByAlias and self.thisSortDesc == "False":
195 direction = "True"
196 thisUrl = self.baseUrl
197 newSortUrl = """%(thisUrl)ssortBy=%(columnSortByAlias)s&sortDesc=%(direction)s""" % locals(
198 )
200 thisArrow = ""
201 if self.thisSort and (columnSortByAlias.lower() == self.thisSort.lower()):
202 thisArrow = self.arrow
204 # add text color and change display names if necessary
205 if c in list(self.modifyDisplayNameDict.keys()):
206 thisText = self.modifyDisplayNameDict[c]
207 else:
208 thisText = c
209 self.modifyDisplayNameDict[c] = coloredText(
210 text=thisText + thisArrow,
211 color=self.colors[colorIndex],
212 size=False, # 1-10
213 pull=False, # "left" | "right"
214 )
215 if colorIndex < len(self.colors) - 1:
216 colorIndex += 1
217 else:
218 colorIndex = 0
220 if c not in self.columnsToHide:
221 if len(self.modifyColumnWidths) == len(self.columnsToDisplay) - len(self.columnsToHide):
222 columnWidth = self.modifyColumnWidths[columnIndex]
223 elif columnIndex < self.extraColumnWidth:
224 columnWidth = self.columnWidth + 1
225 else:
226 columnWidth = self.columnWidth
227 columnIndex += 1
228 cell = th(
229 content=self.modifyDisplayNameDict[c],
230 color=False,
231 href=newSortUrl,
232 popover=thisPopover,
233 columnWidth=columnWidth
234 )
235 tableHead = "%(tableHead)s %(cell)s" % locals()
237 tableHead = tr(
238 cellContent=tableHead,
239 color=False,
240 )
241 tableHead = thead(
242 trContent=tableHead
243 )
244 return tableHead
246 def get_table_body(
247 self):
248 """
249 *get table body*
251 **Return**
253 - ``tableBody``
255 """
256 theseTickets = ""
258 # BUILD THE TABLE BODY
259 for obj in self.tableRowsDictionary:
261 if self.searchKeyAndColumn:
262 regex = re.compile(r'^(.*?)\?.*')
263 href = regex.sub("\g<1>", self.baseUrl, count=1)
264 href = href.replace("?", "")
265 href = href + "\\" + \
266 self.searchKeyAndColumn[0] + "=" + \
267 obj[self.searchKeyAndColumn[1]]
268 else:
269 href = False
271 tableRow = ""
272 colorIndex = 0
274 for i, c in enumerate(self.columnsToDisplay):
276 if (isinstance(obj[c], ("".__class__, u"".__class__)) or isinstance(obj[c], str)) and "." not in obj[c]:
277 try:
278 obj[c] = int(obj[c])
279 except:
280 pass
282 if not isinstance(obj[c], int):
283 try:
284 obj[c] = float(obj[c])
285 except:
286 pass
288 if c.lower() in ["radeg", "decdeg"]:
289 obj[c] = "%6.3f" % obj[c]
290 elif (isinstance(obj[c], float) or isinstance(obj[c], int)) and obj[c]:
291 obj[c] = "%6.2f" % obj[c]
292 elif obj[c] == 0:
293 pass
294 elif not obj[c] or ((isinstance(obj[c], ("".__class__, u"".__class__)) or isinstance(obj[c], str)) and ("unkn" in obj[c].lower())):
295 obj[c] = ""
296 elif isinstance(obj[c], datetime.datetime):
297 # obj[c] = "boom"
299 relativeDate = times.datetime_relative_to_now(obj[c])
300 thisDate = str(obj[c])[:10]
301 thisDate = coloredText(
302 text="(%(thisDate)s)" % locals(),
303 color="grey",
304 size=2,
305 )
306 thisDate = hide_from_device(
307 content=thisDate,
308 onPhone=False,
309 onTablet=False,
310 onDesktop=True
311 )
312 obj[c] = "%(relativeDate)s %(thisDate)s" % locals()
314 obj[c] = coloredText(
315 text=obj[c],
316 color=self.colors[colorIndex],
317 )
318 if colorIndex < len(self.colors) - 1:
319 colorIndex += 1
320 else:
321 colorIndex = 0
323 if c not in self.columnsToHide:
324 cell = td(
325 content=obj[c],
326 )
327 tableRow = "%(tableRow)s %(cell)s" % locals()
329 tableRow = tr(
330 cellContent=tableRow,
331 color=False,
332 href=href,
333 popover=False,
334 )
335 theseTickets = "%(theseTickets)s%(tableRow)s" % locals()
337 tableBody = tbody(
338 trContent=theseTickets
339 )
340 return tableBody
342 # xt-class-method