diff options
author | 2021-10-14 08:00:04 +1100 | |
---|---|---|
committer | 2021-10-14 08:00:04 +1100 | |
commit | 96ca1dbd965df08ed4ab1f23053690c9ce540f94 (patch) | |
tree | 7c357aa9efe72e7e9c8b6e7084cec9fa859e214a /scripts/minimaws/lib | |
parent | 75f9660fa29d3d68a522fa96dbc92ef02baff2b8 (diff) |
More user experience improvements:
frontend: Allow clicking the adjuster arrows on menu items. This allows
things like video options and DIP switches to be configured using a
mouse only. Also fixed a bug preventing paging menus with a mouse if
the first item scrolled off the bottom is not selectable.
debugger: Allow wplist and bplist to accept a CPU argument to list
breakpoints/watchpoints for a single CPU only.
debugger: Fixed some corner cases in address space syntax in memory
accesses, and allowed memory region accesses to use tags relative to the
visible CPU.
emu/softlist.cpp: Ignore notes elements when loading software lists.
It's effectively a comment that isn't a comment syntactically, it's
being used for things that are not useful to display in the internal UI,
and it slows down startup.
docs: Updated three more pages of debugger documentation. Also updated
more of the built-in debugger help.
minimaws: Fixed up schema for software list notes, made sofware list
notes display initially collapsed.
Diffstat (limited to 'scripts/minimaws/lib')
-rw-r--r-- | scripts/minimaws/lib/assets/common.js | 7 | ||||
-rw-r--r-- | scripts/minimaws/lib/assets/disclosedown.svg | 2 | ||||
-rw-r--r-- | scripts/minimaws/lib/assets/discloseup.svg | 2 | ||||
-rw-r--r-- | scripts/minimaws/lib/dbaccess.py | 42 | ||||
-rw-r--r-- | scripts/minimaws/lib/htmltmpl.py | 38 | ||||
-rw-r--r-- | scripts/minimaws/lib/lxparse.py | 24 | ||||
-rw-r--r-- | scripts/minimaws/lib/wsgiserve.py | 42 |
7 files changed, 106 insertions, 51 deletions
diff --git a/scripts/minimaws/lib/assets/common.js b/scripts/minimaws/lib/assets/common.js index baedcf3940d..7439aaa5a21 100644 --- a/scripts/minimaws/lib/assets/common.js +++ b/scripts/minimaws/lib/assets/common.js @@ -37,6 +37,13 @@ function make_collapsible(heading, section) } } }); + + return function () + { + hidden = true; + icon.setAttribute('src', assetsurl + '/discloseup.svg'); + section.style.display = 'none'; + }; } diff --git a/scripts/minimaws/lib/assets/disclosedown.svg b/scripts/minimaws/lib/assets/disclosedown.svg index 5a5ffbb9be7..bb66c7f5de9 100644 --- a/scripts/minimaws/lib/assets/disclosedown.svg +++ b/scripts/minimaws/lib/assets/disclosedown.svg @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="16" width="16"> - <path d="m 0,6 h 16 l -8,10 z" /> + <path d="m 0,5 h 16 l -8,10 z" /> </svg> diff --git a/scripts/minimaws/lib/assets/discloseup.svg b/scripts/minimaws/lib/assets/discloseup.svg index 6ff4e7cd838..010065a446b 100644 --- a/scripts/minimaws/lib/assets/discloseup.svg +++ b/scripts/minimaws/lib/assets/discloseup.svg @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="16" width="16"> - <path d="m 6,0 v 16 l 10,-8 z" /> + <path d="m 5,0 v 16 l 10,-8 z" /> </svg> diff --git a/scripts/minimaws/lib/dbaccess.py b/scripts/minimaws/lib/dbaccess.py index 208b22a02c7..3cfbec0c508 100644 --- a/scripts/minimaws/lib/dbaccess.py +++ b/scripts/minimaws/lib/dbaccess.py @@ -32,8 +32,12 @@ class SchemaQueries(object): ' id INTEGER PRIMARY KEY,\n' \ ' shortname TEXT NOT NULL,\n' \ ' description TEXT NOT NULL,\n' \ - ' notes TEXT NULL,\n' \ ' UNIQUE (shortname ASC))' + CREATE_SOFTWARELISTNOTES = \ + 'CREATE TABLE softwarelistnotes (\n' \ + ' softwarelist INTEGER PRIMARY KEY,\n' \ + ' notes TEXT NOT NULL,\n' \ + ' FOREIGN KEY (softwarelist) REFERENCES softwarelist (id))' CREATE_SOFTWARE = \ 'CREATE TABLE software (\n' \ ' id INTEGER PRIMARY KEY,\n' \ @@ -43,7 +47,6 @@ class SchemaQueries(object): ' description TEXT NOT NULL,\n' \ ' year TEXT NOT NULL,\n' \ ' publisher TEXT NOT NULL,\n' \ - ' notes TEXT NULL,\n' \ ' UNIQUE (softwarelist ASC, shortname ASC),\n' \ ' FOREIGN KEY (softwarelist) REFERENCES softwarelist (id))' CREATE_SOFTWARECLONEOF = \ @@ -52,6 +55,11 @@ class SchemaQueries(object): ' parent INTEGER NOT NULL,\n' \ ' FOREIGN KEY (id) REFERENCES software (id),\n' \ ' FOREIGN KEY (parent) REFERENCES software (id))' + CREATE_SOFTWARENOTES = \ + 'CREATE TABLE softwarenotes (\n' \ + ' software INTEGER PRIMARY KEY,\n' \ + ' notes TEXT NOT NULL,\n' \ + ' FOREIGN KEY (software) REFERENCES software (id))' CREATE_SOFTWAREINFO = \ 'CREATE TABLE softwareinfo (\n' \ ' id INTEGER PRIMARY KEY,\n' \ @@ -392,8 +400,10 @@ class SchemaQueries(object): CREATE_SOFTWARESHAREDFEATTYPE, CREATE_SOFTWAREPARTFEATURETYPE, CREATE_SOFTWARELIST, + CREATE_SOFTWARELISTNOTES, CREATE_SOFTWARE, CREATE_SOFTWARECLONEOF, + CREATE_SOFTWARENOTES, CREATE_SOFTWAREINFO, CREATE_SOFTWARESHAREDFEAT, CREATE_SOFTWAREPART, @@ -502,13 +512,13 @@ class UpdateQueries(object): ADD_SOFTWARESHAREDFEATTYPE = 'INSERT OR IGNORE INTO softwaresharedfeattype (name) VALUES (?)' ADD_SOFTWAREPARTFEATURETYPE = 'INSERT OR IGNORE INTO softwarepartfeaturetype (name) VALUES(?)' ADD_SOFTWARELIST = 'INSERT INTO softwarelist (shortname, description) VALUES (?, ?)' + ADD_SOFTWARELISTNOTES = 'INSERT INTO softwarelistnotes (softwarelist, notes) VALUES (?, ?)' ADD_SOFTWARE = 'INSERT INTO software (softwarelist, shortname, supported, description, year, publisher) VALUES (?, ?, ?, ?, ?, ?)' + ADD_SOFTWARENOTES = 'INSERT INTO softwarenotes (software, notes) VALUES (?, ?)' ADD_SOFTWAREINFO = 'INSERT INTO softwareinfo (software, infotype, value) SELECT ?, id, ? FROM softwareinfotype WHERE name = ?' ADD_SOFTWARESHAREDFEAT = 'INSERT INTO softwaresharedfeat (software, sharedfeattype, value) SELECT ?, id, ? FROM softwaresharedfeattype WHERE name = ?' ADD_SOFTWAREPART = 'INSERT INTO softwarepart (software, shortname, interface) VALUES (?, ?, ?)' ADD_SOFTWAREPARTFEATURE = 'INSERT INTO softwarepartfeature (part, featuretype, value) SELECT ?, id, ? FROM softwarepartfeaturetype WHERE name = ?' - UPDATE_SOFTWARELIST_NOTES = 'UPDATE softwarelist SET notes = ? WHERE id = ?' - UPDATE_SOFTWARE_NOTES = 'UPDATE software SET notes = ? WHERE id = ?' # machines ADD_FEATURETYPE = 'INSERT OR IGNORE INTO featuretype (name) VALUES (?)' @@ -777,7 +787,7 @@ class QueryCursor(object): def get_machine_softwarelists(self, machine): return self.dbcurs.execute( - 'SELECT machinesoftwarelist.tag AS tag, machinesoftwareliststatustype.value AS status, softwarelist.shortname AS shortname, softwarelist.description AS description, softwarelist.notes AS notes, COUNT(software.id) AS total, COUNT(CASE software.supported WHEN 0 THEN 1 ELSE NULL END) AS supported, COUNT(CASE software.supported WHEN 1 THEN 1 ELSE NULL END) AS partiallysupported, COUNT(CASE software.supported WHEN 2 THEN 1 ELSE NULL END) AS unsupported ' \ + 'SELECT machinesoftwarelist.tag AS tag, machinesoftwareliststatustype.value AS status, softwarelist.shortname AS shortname, softwarelist.description AS description, COUNT(software.id) AS total, COUNT(CASE software.supported WHEN 0 THEN 1 ELSE NULL END) AS supported, COUNT(CASE software.supported WHEN 1 THEN 1 ELSE NULL END) AS partiallysupported, COUNT(CASE software.supported WHEN 2 THEN 1 ELSE NULL END) AS unsupported ' \ 'FROM machinesoftwarelist LEFT JOIN machinesoftwareliststatustype ON machinesoftwarelist.status = machinesoftwareliststatustype.id LEFT JOIN softwarelist ON machinesoftwarelist.softwarelist = softwarelist.id LEFT JOIN software ON softwarelist.id = software.softwarelist ' \ 'WHERE machinesoftwarelist.machine = ? ' \ 'GROUP BY machinesoftwarelist.id', @@ -789,15 +799,15 @@ class QueryCursor(object): def get_softwarelist_details(self, shortname, pattern): if pattern is not None: return self.dbcurs.execute( - 'SELECT softwarelist.id AS id, softwarelist.shortname AS shortname, softwarelist.description AS description, softwarelist.notes AS notes, COUNT(software.id) AS total, COUNT(CASE software.supported WHEN 0 THEN 1 ELSE NULL END) AS supported, COUNT(CASE software.supported WHEN 1 THEN 1 ELSE NULL END) AS partiallysupported, COUNT(CASE software.supported WHEN 2 THEN 1 ELSE NULL END) AS unsupported ' \ - 'FROM softwarelist LEFT JOIN software ON softwarelist.id = software.softwarelist ' \ + 'SELECT softwarelist.id AS id, softwarelist.shortname AS shortname, softwarelist.description AS description, softwarelistnotes.notes AS notes, COUNT(software.id) AS total, COUNT(CASE software.supported WHEN 0 THEN 1 ELSE NULL END) AS supported, COUNT(CASE software.supported WHEN 1 THEN 1 ELSE NULL END) AS partiallysupported, COUNT(CASE software.supported WHEN 2 THEN 1 ELSE NULL END) AS unsupported ' \ + 'FROM softwarelist LEFT JOIN softwarelistnotes ON softwarelist.id = softwarelistnotes.softwarelist LEFT JOIN software ON softwarelist.id = software.softwarelist ' \ 'WHERE softwarelist.shortname = ? AND software.shortname GLOB ? ' \ 'GROUP BY softwarelist.id', (shortname, pattern)) else: return self.dbcurs.execute( - 'SELECT softwarelist.id AS id, softwarelist.shortname AS shortname, softwarelist.description AS description, softwarelist.notes AS notes, COUNT(software.id) AS total, COUNT(CASE software.supported WHEN 0 THEN 1 ELSE NULL END) AS supported, COUNT(CASE software.supported WHEN 1 THEN 1 ELSE NULL END) AS partiallysupported, COUNT(CASE software.supported WHEN 2 THEN 1 ELSE NULL END) AS unsupported ' \ - 'FROM softwarelist LEFT JOIN software ON softwarelist.id = software.softwarelist ' \ + 'SELECT softwarelist.id AS id, softwarelist.shortname AS shortname, softwarelist.description AS description, softwarelistnotes.notes AS notes, COUNT(software.id) AS total, COUNT(CASE software.supported WHEN 0 THEN 1 ELSE NULL END) AS supported, COUNT(CASE software.supported WHEN 1 THEN 1 ELSE NULL END) AS partiallysupported, COUNT(CASE software.supported WHEN 2 THEN 1 ELSE NULL END) AS unsupported ' \ + 'FROM softwarelist LEFT JOIN softwarelistnotes ON softwarelist.id = softwarelistnotes.softwarelist LEFT JOIN software ON softwarelist.id = software.softwarelist ' \ 'WHERE softwarelist.shortname = ? ' \ 'GROUP BY softwarelist.id', (shortname, )) @@ -840,8 +850,8 @@ class QueryCursor(object): def get_software_details(self, softwarelist, software): return self.dbcurs.execute( - 'SELECT software.id AS id, software.shortname AS shortname, software.supported AS supported, software.description AS description, software.year AS year, software.publisher AS publisher, software.notes AS notes, softwarelist.shortname AS softwarelist, softwarelist.description AS softwarelistdescription, parent.shortname AS parent, parent.description AS parentdescription, parentsoftwarelist.shortname AS parentsoftwarelist, parentsoftwarelist.description AS parentsoftwarelistdescription ' \ - 'FROM software LEFT JOIN softwarelist ON software.softwarelist = softwarelist.id LEFT JOIN softwarecloneof ON software.id = softwarecloneof.id LEFT JOIN software AS parent ON softwarecloneof.parent = parent.id LEFT JOIN softwarelist AS parentsoftwarelist ON parent.softwarelist = parentsoftwarelist.id ' \ + 'SELECT software.id AS id, software.shortname AS shortname, software.supported AS supported, software.description AS description, software.year AS year, software.publisher AS publisher, softwarelist.shortname AS softwarelist, softwarelist.description AS softwarelistdescription, parent.shortname AS parent, parent.description AS parentdescription, parentsoftwarelist.shortname AS parentsoftwarelist, parentsoftwarelist.description AS parentsoftwarelistdescription, softwarenotes.notes AS notes ' \ + 'FROM software LEFT JOIN softwarelist ON software.softwarelist = softwarelist.id LEFT JOIN softwarecloneof ON software.id = softwarecloneof.id LEFT JOIN software AS parent ON softwarecloneof.parent = parent.id LEFT JOIN softwarelist AS parentsoftwarelist ON parent.softwarelist = parentsoftwarelist.id LEFT JOIN softwarenotes ON softwarenotes.software = software.id ' \ 'WHERE software.softwarelist = (SELECT id FROM softwarelist WHERE shortname = ?) AND software.shortname = ?', (softwarelist, software)) @@ -916,8 +926,8 @@ class UpdateCursor(object): self.dbcurs.execute(UpdateQueries.ADD_SOFTWARELIST, (shortname, description)) return self.dbcurs.lastrowid - def update_softwarelist_notes(self, id, notes): - self.dbcurs.execute(UpdateQueries.UPDATE_SOFTWARELIST_NOTES, (notes, id)) + def add_softwarelistnotes(self, softwarelist, notes): + self.dbcurs.execute(UpdateQueries.ADD_SOFTWARELISTNOTES, (softwarelist, notes)) def add_softwareinfotype(self, name): self.dbcurs.execute(UpdateQueries.ADD_SOFTWAREINFOTYPE, (name, )) @@ -932,13 +942,13 @@ class UpdateCursor(object): self.dbcurs.execute(UpdateQueries.ADD_SOFTWARE, (softwarelist, shortname, supported, description, year, publisher)) return self.dbcurs.lastrowid - def update_software_notes(self, id, notes): - self.dbcurs.execute(UpdateQueries.UPDATE_SOFTWARE_NOTES, (notes, id)) - def add_softwarecloneof(self, software, parent): self.dbcurs.execute(UpdateQueries.ADD_TEMPORARY_SOFTWARECLONEOF, (software, parent)) return self.dbcurs.lastrowid + def add_softwarenotes(self, software, notes): + self.dbcurs.execute(UpdateQueries.ADD_SOFTWARENOTES, (software, notes)) + def add_softwareinfo(self, software, infotype, value): self.dbcurs.execute(UpdateQueries.ADD_SOFTWAREINFO, (software, value, infotype)) return self.dbcurs.lastrowid diff --git a/scripts/minimaws/lib/htmltmpl.py b/scripts/minimaws/lib/htmltmpl.py index 4f3bf12bb46..62e1bbcf1ea 100644 --- a/scripts/minimaws/lib/htmltmpl.py +++ b/scripts/minimaws/lib/htmltmpl.py @@ -258,10 +258,6 @@ SOFTWARE_PROLOGUE = string.Template( ' <tr><th>Year:</th><td>${year}</td></tr>\n' \ ' <tr><th>Publisher:</th><td>${publisher}</td></tr>\n'); -SOFTWARE_EPILOGUE = string.Template( - '<h2>Notes</h2>\n' \ - '<p><pre>${notes}<p></pre>\n'); - SOFTWARE_CLONES_PROLOGUE = string.Template( '<h2 id="heading-clones">Clones</h2>\n' \ '<table id="tbl-clones">\n' \ @@ -285,11 +281,27 @@ SOFTWARE_CLONES_ROW = string.Template( ' <td>${supported}</td>\n' \ ' </tr>\n') +SOFTWARE_NOTES_PROLOGUE = string.Template( + '<h2 id="heading-notes">Notes</h2>\n' \ + '<div id="div-notes">\n') + +SOFTWARE_NOTES_EPILOGUE = string.Template( + '</div>\n' \ + '<script>make_collapsible(document.getElementById("heading-notes"), document.getElementById("div-notes"))();</script>\n\n') + +SOFTWARE_PARTS_PROLOGUE = string.Template( + '<h2 id="heading-parts">Parts</h2>\n' \ + '<div id="div-parts">\n\n') + +SOFTWARE_PARTS_EPILOGUE = string.Template( + '</div>\n' \ + '<script>make_collapsible(document.getElementById("heading-parts"), document.getElementById("div-parts"));</script>\n\n') + SOFTWARE_PART_PROLOGUE = string.Template( - '<h3>${heading}</h3>\n' \ - '<table class="sysinfo">\n' \ - ' <tr><th>Short name:</th><td>${shortname}</td></tr>\n' \ - ' <tr><th>Interface:</th><td>${interface}</td></tr>\n') + ' <h3>${heading}</h3>\n' \ + ' <table class="sysinfo">\n' \ + ' <tr><th>Short name:</th><td>${shortname}</td></tr>\n' \ + ' <tr><th>Interface:</th><td>${interface}</td></tr>\n') SOFTWARELIST_PROLOGUE = string.Template( @@ -332,9 +344,13 @@ SOFTWARELIST_PROLOGUE = string.Template( ' </tr>\n' \ '</table>\n') -SOFTWARELIST_EPILOGUE = string.Template( - '<h2>Notes</h2>\n' \ - '<p><pre>${notes}<p></pre>\n') +SOFTWARELIST_NOTES_PROLOGUE = string.Template( + '<h2 id="heading-notes">Notes</h2>\n' \ + '<div id="div-notes">\n') + +SOFTWARELIST_NOTES_EPILOGUE = string.Template( + '</div>\n' \ + '<script>make_collapsible(document.getElementById("heading-notes"), document.getElementById("div-notes"))();</script>\n\n') SOFTWARELIST_MACHINE_TABLE_HEADER = string.Template( '<h2 id="heading-machines">Machines</h2>\n' \ diff --git a/scripts/minimaws/lib/lxparse.py b/scripts/minimaws/lib/lxparse.py index 699695577fc..e773669080d 100644 --- a/scripts/minimaws/lib/lxparse.py +++ b/scripts/minimaws/lib/lxparse.py @@ -391,11 +391,14 @@ class SoftwareHandler(ElementHandler): if self.cloneof is not None: self.dbcurs.add_softwarecloneof(self.id, self.cloneof) elif name == 'notes': - self.notes = handler.text - self.dbcurs.update_software_notes(self.id, self.notes) + self.dbcurs.add_softwarenotes(self.id, handler.text) class SoftwareListHandler(ElementHandler): + CHILD_HANDLERS = { + 'notes': TextAccumulator, + 'software': SoftwareHandler } + def __init__(self, dbconn, **kwargs): super(SoftwareListHandler, self).__init__(parent=None, **kwargs) self.dbconn = dbconn @@ -414,33 +417,28 @@ class SoftwareListHandler(ElementHandler): locator=self.locator) self.shortname = attrs['name'] self.description = attrs['description'] - self.notes = None self.entries = 0 dbcurs = self.dbconn.cursor() self.id = dbcurs.add_softwarelist(self.shortname, self.description) dbcurs.close() def endMainElement(self, name): - if self.notes: - dbcurs = self.dbconn.cursor() - dbcurs.update_softwarelist_notes(self.id, self.notes) - dbcurs.close() self.dbconn.commit() def startChildElement(self, name, attrs): - if name == 'notes': - self.setChildHandler(name, attrs, TextAccumulator(self)) - elif name == 'software': - self.setChildHandler(name, attrs, SoftwareHandler(self)) + if name in self.CHILD_HANDLERS: + self.setChildHandler(name, attrs, self.CHILD_HANDLERS[name](self)) else: raise xml.sax.SAXParseException( - msg=('Expected "software" element but found "%s"' % (name, )), + msg=('Found unexpected element "%s"' % (name, )), exception=None, locator=self.locator) def endChildHandler(self, name, handler): if name == 'notes': - self.notes = handler.text + dbcurs = self.dbconn.cursor() + dbcurs.add_softwarelistnotes(self.id, handler.text) + dbcurs.close() elif name == 'software': if self.entries >= 1023: self.dbconn.commit() diff --git a/scripts/minimaws/lib/wsgiserve.py b/scripts/minimaws/lib/wsgiserve.py index 3b92f08110d..1158528d954 100644 --- a/scripts/minimaws/lib/wsgiserve.py +++ b/scripts/minimaws/lib/wsgiserve.py @@ -661,6 +661,20 @@ class SoftwareListHandler(QueryPageHandler): unsupported=htmlescape('%d' % (softwarelist_info['unsupported'], )), unsupportedpc=htmlescape('%.1f' % (softwarelist_info['unsupported'] * 100.0 / (softwarelist_info['total'] or 1), ))).encode('utf-8') + if softwarelist_info['notes'] is not None: + yield htmltmpl.SOFTWARELIST_NOTES_PROLOGUE.substitute().encode('utf-8') + first = True + for line in softwarelist_info['notes'].strip().splitlines(): + if line: + yield (('<p>%s' if first else '<br />\n%s') % (htmlescape(line), )).encode('utf-8') + first = False + elif not first: + yield '</p>\n'.encode('utf-8') + first = True + if not first: + yield '</p>\n'.encode('utf-8') + yield htmltmpl.SOFTWARELIST_NOTES_EPILOGUE.substitute().encode('utf-8') + first = True for machine_info in self.dbcurs.get_softwarelist_machines(softwarelist_info['id']): if first: @@ -689,9 +703,6 @@ class SoftwareListHandler(QueryPageHandler): yield htmltmpl.SORTABLE_TABLE_EPILOGUE.substitute(id='tbl-software').encode('utf-8') yield '<script>make_collapsible(document.getElementById("heading-software"), document.getElementById("tbl-software"));</script>\n'.encode('utf-8') - if (softwarelist_info['notes']): - yield htmltmpl.SOFTWARELIST_EPILOGUE.substitute(notes=htmlescape(softwarelist_info['notes'])).encode('utf-8') - yield '</body>\n</html>\n'.encode('utf-8') def software_page(self, software_info): @@ -722,22 +733,35 @@ class SoftwareListHandler(QueryPageHandler): yield htmltmpl.SORTABLE_TABLE_EPILOGUE.substitute(id='tbl-clones').encode('utf-8') yield '<script>make_collapsible(document.getElementById("heading-clones"), document.getElementById("tbl-clones"));</script>\n'.encode('utf-8') + if software_info['notes'] is not None: + yield htmltmpl.SOFTWARE_NOTES_PROLOGUE.substitute().encode('utf-8') + first = True + for line in software_info['notes'].strip().splitlines(): + if line: + yield (('<p>%s' if first else '<br />\n%s') % (htmlescape(line), )).encode('utf-8') + first = False + elif not first: + yield '</p>\n'.encode('utf-8') + first = True + if not first: + yield '</p>\n'.encode('utf-8') + yield htmltmpl.SOFTWARE_NOTES_EPILOGUE.substitute().encode('utf-8') + parts = self.dbcurs.get_software_parts(software_info['id']).fetchall() first = True for id, partname, interface, part_id in parts: if first: - yield '<h2>Parts</h2>\n'.encode('utf-8') + yield htmltmpl.SOFTWARE_PARTS_PROLOGUE.substitute().encode('utf-8') first = False yield htmltmpl.SOFTWARE_PART_PROLOGUE.substitute( heading=htmlescape(('%s (%s)' % (part_id, partname)) if part_id is not None else partname), shortname=htmlescape(partname), interface=htmlescape(interface)).encode('utf-8') for name, value in self.dbcurs.get_softwarepart_features(id): - yield (' <tr><th>%s:</th><td>%s</td>\n' % (htmlescape(name), htmlescape(value))).encode('utf-8') - yield '</table>\n\n'.encode('utf-8') - - if (software_info['notes']): - yield htmltmpl.SOFTWARE_EPILOGUE.substitute(notes=htmlescape(software_info['notes'])).encode('utf-8') + yield (' <tr><th>%s:</th><td>%s</td>\n' % (htmlescape(name), htmlescape(value))).encode('utf-8') + yield ' </table>\n\n'.encode('utf-8') + if not first: + yield htmltmpl.SOFTWARE_PARTS_EPILOGUE.substitute().encode('utf-8') yield '</body>\n</html>\n'.encode('utf-8') |