-minimaws: Made table sort widgets (and the code behind them) less ugly.

-util/delegate.cpp: Added a couple of comments about assumptions.
This commit is contained in:
Vas Crabb 2021-09-23 17:03:20 +10:00
parent 5c447ee722
commit d35ff4bca6
10 changed files with 106 additions and 47 deletions

View File

@ -1,55 +1,82 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
function sort_table(tbl, col, dir, numeric)
{
var tbody = tbl.tBodies[0];
var trows = Array.prototype.slice.call(tbody.rows, 0).sort(
function (x, y)
{
if (numeric)
return dir * (parseFloat(x.cells[col].textContent) - parseFloat(y.cells[col].textContent));
else
return dir * x.cells[col].textContent.localeCompare(y.cells[col].textContent);
})
trows.forEach(function (row) { tbody.appendChild(row); });
}
function make_table_sortable(tbl)
{
var headers = tbl.tHead.rows[0].cells;
for (var i = 0; i < headers.length; i++)
var sorticons = new Array(tbl.tHead.rows[0].cells.length);
function TableSortHelper(i)
{
(function (col)
{
var dir = 1;
var sorticon = document.createElement('img');
sorticon.setAttribute('src', assetsurl + '/sortind.png');
sorticon.style.cssFloat = 'right';
sorticon.style.marginLeft = '0.5em';
headers[col].appendChild(sorticon);
headers[col].addEventListener(
'click',
function (event)
{
var imgsrc = sorticon.getAttribute('src');
imgsrc = imgsrc.substr(imgsrc.lastIndexOf('/') + 1);
if (imgsrc != 'sortind.png')
dir = -dir;
if (dir < 0)
sorticon.setAttribute('src', assetsurl + '/sortdesc.png');
else
sorticon.setAttribute('src', assetsurl + '/sortasc.png');
for (var i = 0; i < headers.length; i++)
{
if (i != col)
headers[i].lastChild.setAttribute('src', assetsurl + '/sortind.png');
}
sort_table(tbl, col, dir, headers[col].getAttribute('class') == 'numeric');
});
}(i));
this.column = i;
this.header = tbl.tHead.rows[0].cells[i]
this.sorted = false;
this.direction = 1;
this.icon = document.createElement('img');
this.icon.setAttribute('src', assetsurl + '/sortind.svg');
this.icon.addEventListener('click', this.icon_click.bind(this));
var container = document.createElement('div');
container.setAttribute('class', 'sorticon');
container.appendChild(this.icon);
this.header.appendChild(container);
}
TableSortHelper.prototype = (function ()
{
function set_unsorted(obj)
{
obj.sorted = false;
obj.icon.setAttribute('src', assetsurl + '/sortind.svg');
}
function sort_table(obj)
{
var c = obj.header.cellIndex;
var numeric = obj.header.getAttribute('class') == 'numeric';
var tbody = tbl.tBodies[0];
var trows;
if (numeric)
{
trows = Array.prototype.slice.call(tbody.rows, 0).sort(
function (x, y)
{
return obj.direction * (parseFloat(x.cells[c].textContent) - parseFloat(y.cells[c].textContent));
});
}
else
{
trows = Array.prototype.slice.call(tbody.rows, 0).sort(
function (x, y)
{
return obj.direction * x.cells[c].textContent.localeCompare(y.cells[c].textContent);
});
}
trows.forEach(function (row) { tbody.appendChild(row); });
}
return {
icon_click : function (event)
{
if (this.sorted)
this.direction = -this.direction;
if (this.direction < 0)
this.icon.setAttribute('src', assetsurl + '/sortdesc.svg');
else
this.icon.setAttribute('src', assetsurl + '/sortasc.svg');
this.sorted = true;
for (var i = 0; i < sorticons.length; i++)
{
if (i != this.column)
set_unsorted(sorticons[i]);
}
sort_table(this);
}
};
})();
for (var i = 0; i < sorticons.length; i++)
sorticons[i] = new TableSortHelper(i);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +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="30">
<path d="m 14,16 h 16 l -8,-16 z" />
</svg>

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +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="30">
<path d="m 14,0 h 16 l -8,16 z" />
</svg>

After

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="16" width="30">
<path d="m 0,16 h 16 l -8,-16 z" />
<path d="m 14,0 h 16 l -8,16 z" />
</svg>

After

Width:  |  Height:  |  Size: 213 B

View File

@ -5,6 +5,9 @@
th { text-align: left; background-color: #ddd; padding: 0.25em }
td { padding-left: 0.25em; padding-right: 0.25em }
div[class=sorticon] { float: right; height: 100%; margin-left: 0.5em }
div[class=sorticon] img { height: 0.7em; vertical-align: baseline }
table[class=sysinfo] th { text-align: right }
div[class=dropzone] { padding: 0 1em; border-width: 2px; border-radius: 1em; border-style: dashed }

View File

@ -67,6 +67,8 @@ class ErrorPageHandler(HandlerBase):
class AssetHandler(HandlerBase):
EXTENSIONMAP = { '.js': 'application/javascript', '.svg': 'image/svg+xml' }
def __init__(self, directory, app, application_uri, environ, start_response, **kwargs):
super(AssetHandler, self).__init__(app=app, application_uri=application_uri, environ=environ, start_response=start_response, **kwargs)
self.directory = directory
@ -90,8 +92,11 @@ class AssetHandler(HandlerBase):
else:
try:
f = open(path, 'rb')
type, encoding = mimetypes.guess_type(path)
self.start_response('200 OK', [('Content-type', type or 'application/octet-stream'), ('Cache-Control', 'public, max-age=3600')])
base, extension = os.path.splitext(path)
mimetype = self.EXTENSIONMAP.get(extension)
if mimetype is None:
mimetype, encoding = mimetypes.guess_type(path)
self.start_response('200 OK', [('Content-type', mimetype or 'application/octet-stream'), ('Cache-Control', 'public, max-age=3600')])
return wsgiref.util.FileWrapper(f)
except:
self.start_response('500 %s' % (self.STATUS_MESSAGE[500], ), [('Content-type', 'text/html; charset=utf-8'), ('Cache-Control', 'public, max-age=3600')])

View File

@ -156,6 +156,14 @@ delegate_generic_function delegate_mfp_msvc::adjust_this_pointer(delegate_generi
else if ((0x48 == func[0]) && (0x8b == func[1]) && (0x01 == func[2]) && (0xff == func[3]) && ((0x20 == func[4]) || (0x60 == func[4]) || (0xa0 == func[4])))
{
// virtual function call thunk - mov rax,QWORD PTR [rcx] ; jmp QWORD PTR [rax+...]
// Assumes Windows calling convention, and doesn't consider
// that the "this" pointer could be in RDX if RCX is a
// pointer to space for an oversize scalar result. Since
// the result area is uninitialised on entry, you won't see
// something that looks like a vtable dispatch through RCX
// in this case - it won't behave badly, it just won't
// bypass virtual call thunks in the rare situations where
// the return type is an oversize scalar.
LOG("Found virtual member function thunk at %p ", func);
std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object);
if (0x20 == func[4]) // no displacement
@ -177,6 +185,9 @@ delegate_generic_function delegate_mfp_msvc::adjust_this_pointer(delegate_generi
std::uint32_t const *func = reinterpret_cast<std::uint32_t const *>(m_function);
while (true)
{
// Assumes little Endian mode. Instructions are always stored
// in little Endian format on AArch64, so if big Endian mode is
// to be supported, the values need to be swapped.
if ((0xf9400010 == func[0]) && (0xf9400210 == (func[1] & 0xffc003ff)) && (0xd61f0200 == func[2]))
{
// virtual function call thunk - ldr xip0,[x0] ; ldr xip0,[x0,#...] ; br xip0