mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
truncate_cells_html now affects URLs too, refs #1805
This commit is contained in:
parent
ff9c87197d
commit
d0737e4de5
8 changed files with 68 additions and 14 deletions
|
|
@ -1167,3 +1167,13 @@ def resolve_routes(routes, path):
|
||||||
if match is not None:
|
if match is not None:
|
||||||
return match, view
|
return match, view
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
|
def truncate_url(url, length):
|
||||||
|
if (not length) or (len(url) <= length):
|
||||||
|
return url
|
||||||
|
bits = url.rsplit(".", 1)
|
||||||
|
if len(bits) == 2 and 1 <= len(bits[1]) <= 4 and "/" not in bits[1]:
|
||||||
|
rest, ext = bits
|
||||||
|
return rest[: length - 1 - len(ext)] + "…." + ext
|
||||||
|
return url[: length - 1] + "…"
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ from datasette.utils import (
|
||||||
path_with_format,
|
path_with_format,
|
||||||
path_with_removed_args,
|
path_with_removed_args,
|
||||||
sqlite3,
|
sqlite3,
|
||||||
|
truncate_url,
|
||||||
InvalidSql,
|
InvalidSql,
|
||||||
)
|
)
|
||||||
from datasette.utils.asgi import AsgiFileDownload, NotFound, Response, Forbidden
|
from datasette.utils.asgi import AsgiFileDownload, NotFound, Response, Forbidden
|
||||||
|
|
@ -371,6 +372,7 @@ class QueryView(DataView):
|
||||||
|
|
||||||
async def extra_template():
|
async def extra_template():
|
||||||
display_rows = []
|
display_rows = []
|
||||||
|
truncate_cells = self.ds.setting("truncate_cells_html")
|
||||||
for row in results.rows if results else []:
|
for row in results.rows if results else []:
|
||||||
display_row = []
|
display_row = []
|
||||||
for column, value in zip(results.columns, row):
|
for column, value in zip(results.columns, row):
|
||||||
|
|
@ -396,9 +398,12 @@ class QueryView(DataView):
|
||||||
if value in ("", None):
|
if value in ("", None):
|
||||||
display_value = Markup(" ")
|
display_value = Markup(" ")
|
||||||
elif is_url(str(display_value).strip()):
|
elif is_url(str(display_value).strip()):
|
||||||
display_value = Markup(
|
display_value = markupsafe.Markup(
|
||||||
'<a href="{url}">{url}</a>'.format(
|
'<a href="{url}">{truncated_url}</a>'.format(
|
||||||
url=escape(value.strip())
|
url=markupsafe.escape(value.strip()),
|
||||||
|
truncated_url=markupsafe.escape(
|
||||||
|
truncate_url(value.strip(), truncate_cells)
|
||||||
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif isinstance(display_value, bytes):
|
elif isinstance(display_value, bytes):
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ from datasette.utils import (
|
||||||
path_with_removed_args,
|
path_with_removed_args,
|
||||||
path_with_replaced_args,
|
path_with_replaced_args,
|
||||||
to_css_class,
|
to_css_class,
|
||||||
|
truncate_url,
|
||||||
urlsafe_components,
|
urlsafe_components,
|
||||||
value_as_boolean,
|
value_as_boolean,
|
||||||
)
|
)
|
||||||
|
|
@ -966,8 +967,11 @@ async def display_columns_and_rows(
|
||||||
display_value = markupsafe.Markup(" ")
|
display_value = markupsafe.Markup(" ")
|
||||||
elif is_url(str(value).strip()):
|
elif is_url(str(value).strip()):
|
||||||
display_value = markupsafe.Markup(
|
display_value = markupsafe.Markup(
|
||||||
'<a href="{url}">{url}</a>'.format(
|
'<a href="{url}">{truncated_url}</a>'.format(
|
||||||
url=markupsafe.escape(value.strip())
|
url=markupsafe.escape(value.strip()),
|
||||||
|
truncated_url=markupsafe.escape(
|
||||||
|
truncate_url(value.strip(), truncate_cells)
|
||||||
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif column in table_metadata.get("units", {}) and value != "":
|
elif column in table_metadata.get("units", {}) and value != "":
|
||||||
|
|
|
||||||
|
|
@ -598,23 +598,24 @@ CREATE TABLE roadside_attractions (
|
||||||
pk integer primary key,
|
pk integer primary key,
|
||||||
name text,
|
name text,
|
||||||
address text,
|
address text,
|
||||||
|
url text,
|
||||||
latitude real,
|
latitude real,
|
||||||
longitude real
|
longitude real
|
||||||
);
|
);
|
||||||
INSERT INTO roadside_attractions VALUES (
|
INSERT INTO roadside_attractions VALUES (
|
||||||
1, "The Mystery Spot", "465 Mystery Spot Road, Santa Cruz, CA 95065",
|
1, "The Mystery Spot", "465 Mystery Spot Road, Santa Cruz, CA 95065", "https://www.mysteryspot.com/",
|
||||||
37.0167, -122.0024
|
37.0167, -122.0024
|
||||||
);
|
);
|
||||||
INSERT INTO roadside_attractions VALUES (
|
INSERT INTO roadside_attractions VALUES (
|
||||||
2, "Winchester Mystery House", "525 South Winchester Boulevard, San Jose, CA 95128",
|
2, "Winchester Mystery House", "525 South Winchester Boulevard, San Jose, CA 95128", "https://winchestermysteryhouse.com/",
|
||||||
37.3184, -121.9511
|
37.3184, -121.9511
|
||||||
);
|
);
|
||||||
INSERT INTO roadside_attractions VALUES (
|
INSERT INTO roadside_attractions VALUES (
|
||||||
3, "Burlingame Museum of PEZ Memorabilia", "214 California Drive, Burlingame, CA 94010",
|
3, "Burlingame Museum of PEZ Memorabilia", "214 California Drive, Burlingame, CA 94010", null,
|
||||||
37.5793, -122.3442
|
37.5793, -122.3442
|
||||||
);
|
);
|
||||||
INSERT INTO roadside_attractions VALUES (
|
INSERT INTO roadside_attractions VALUES (
|
||||||
4, "Bigfoot Discovery Museum", "5497 Highway 9, Felton, CA 95018",
|
4, "Bigfoot Discovery Museum", "5497 Highway 9, Felton, CA 95018", "https://www.bigfootdiscoveryproject.com/",
|
||||||
37.0414, -122.0725
|
37.0414, -122.0725
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -339,7 +339,7 @@ def test_database_page(app_client):
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "roadside_attractions",
|
"name": "roadside_attractions",
|
||||||
"columns": ["pk", "name", "address", "latitude", "longitude"],
|
"columns": ["pk", "name", "address", "url", "latitude", "longitude"],
|
||||||
"primary_keys": ["pk"],
|
"primary_keys": ["pk"],
|
||||||
"count": 4,
|
"count": 4,
|
||||||
"hidden": False,
|
"hidden": False,
|
||||||
|
|
|
||||||
|
|
@ -615,11 +615,12 @@ def test_table_through(app_client):
|
||||||
response = app_client.get(
|
response = app_client.get(
|
||||||
'/fixtures/roadside_attractions.json?_through={"table":"roadside_attraction_characteristics","column":"characteristic_id","value":"1"}'
|
'/fixtures/roadside_attractions.json?_through={"table":"roadside_attraction_characteristics","column":"characteristic_id","value":"1"}'
|
||||||
)
|
)
|
||||||
assert [
|
assert response.json["rows"] == [
|
||||||
[
|
[
|
||||||
3,
|
3,
|
||||||
"Burlingame Museum of PEZ Memorabilia",
|
"Burlingame Museum of PEZ Memorabilia",
|
||||||
"214 California Drive, Burlingame, CA 94010",
|
"214 California Drive, Burlingame, CA 94010",
|
||||||
|
None,
|
||||||
37.5793,
|
37.5793,
|
||||||
-122.3442,
|
-122.3442,
|
||||||
],
|
],
|
||||||
|
|
@ -627,13 +628,15 @@ def test_table_through(app_client):
|
||||||
4,
|
4,
|
||||||
"Bigfoot Discovery Museum",
|
"Bigfoot Discovery Museum",
|
||||||
"5497 Highway 9, Felton, CA 95018",
|
"5497 Highway 9, Felton, CA 95018",
|
||||||
|
"https://www.bigfootdiscoveryproject.com/",
|
||||||
37.0414,
|
37.0414,
|
||||||
-122.0725,
|
-122.0725,
|
||||||
],
|
],
|
||||||
] == response.json["rows"]
|
]
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
'where roadside_attraction_characteristics.characteristic_id = "1"'
|
response.json["human_description_en"]
|
||||||
== response.json["human_description_en"]
|
== 'where roadside_attraction_characteristics.characteristic_id = "1"'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,17 @@ def test_table_cell_truncation():
|
||||||
td.string
|
td.string
|
||||||
for td in table.findAll("td", {"class": "col-neighborhood-b352a7"})
|
for td in table.findAll("td", {"class": "col-neighborhood-b352a7"})
|
||||||
]
|
]
|
||||||
|
# URLs should be truncated too
|
||||||
|
response2 = client.get("/fixtures/roadside_attractions")
|
||||||
|
assert response2.status == 200
|
||||||
|
table = Soup(response2.body, "html.parser").find("table")
|
||||||
|
tds = table.findAll("td", {"class": "col-url"})
|
||||||
|
assert [str(td) for td in tds] == [
|
||||||
|
'<td class="col-url type-str"><a href="https://www.mysteryspot.com/">http…</a></td>',
|
||||||
|
'<td class="col-url type-str"><a href="https://winchestermysteryhouse.com/">http…</a></td>',
|
||||||
|
'<td class="col-url type-none">\xa0</td>',
|
||||||
|
'<td class="col-url type-str"><a href="https://www.bigfootdiscoveryproject.com/">http…</a></td>',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def test_add_filter_redirects(app_client):
|
def test_add_filter_redirects(app_client):
|
||||||
|
|
|
||||||
|
|
@ -626,3 +626,23 @@ def test_tilde_encoding(original, expected):
|
||||||
assert actual == expected
|
assert actual == expected
|
||||||
# And test round-trip
|
# And test round-trip
|
||||||
assert original == utils.tilde_decode(actual)
|
assert original == utils.tilde_decode(actual)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"url,length,expected",
|
||||||
|
(
|
||||||
|
("https://example.com/", 5, "http…"),
|
||||||
|
("https://example.com/foo/bar", 15, "https://exampl…"),
|
||||||
|
("https://example.com/foo/bar/baz.jpg", 30, "https://example.com/foo/ba….jpg"),
|
||||||
|
# Extensions longer than 4 characters are not treated specially:
|
||||||
|
("https://example.com/foo/bar/baz.jpeg2", 30, "https://example.com/foo/bar/b…"),
|
||||||
|
(
|
||||||
|
"https://example.com/foo/bar/baz.jpeg2",
|
||||||
|
None,
|
||||||
|
"https://example.com/foo/bar/baz.jpeg2",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
def test_truncate_url(url, length, expected):
|
||||||
|
actual = utils.truncate_url(url, length)
|
||||||
|
assert actual == expected
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue