-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add front page and legacy Via URL support #443
Conversation
via/templates/proxy.html.jinja2
Outdated
body { | ||
margin: 0; | ||
padding: 0; | ||
} | ||
|
||
.iframe { | ||
position:fixed; | ||
top:0; | ||
left:0; | ||
bottom:0; | ||
right:0; | ||
width:100%; | ||
height:100%; | ||
border:none; | ||
margin:0; | ||
padding:0; | ||
overflow:hidden; | ||
z-index:999999; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@robertknight @lyzadanger What's the right way to create an invisible "full-screen" iframe? This seems to work
def test_get_front_page(self, test_app): | ||
response = test_app.get("/", status=404) | ||
|
||
assert dict(response.headers) == Any.dict.containing( | ||
{"Content-Type": Any.string.containing("text/plain")} | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The front page is no longer a 404. Also it's not served as static content anymore
<style> | ||
body { | ||
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; | ||
height: 100vh; | ||
padding: 0; | ||
margin: 0; | ||
} | ||
|
||
.content { | ||
align-items: center; | ||
display: flex; | ||
flex-direction: column; | ||
height: 100%; | ||
justify-content: center; | ||
max-height: 70vh; | ||
} | ||
|
||
.url-form { | ||
align-items: center; | ||
display: flex; | ||
flex-direction: column; | ||
max-width: 400px; | ||
width: 95%; | ||
} | ||
|
||
/* Input field for URL to annotate. */ | ||
.url-field { | ||
align-self: stretch; | ||
border-radius: 3px; | ||
border: 1px solid #ccc; | ||
font-size: 20px; | ||
margin-bottom: 20px; | ||
margin-top: 20px; | ||
min-height: 45px; | ||
padding-bottom: 5px; | ||
padding-left: 16px; | ||
padding-right: 16px; | ||
padding-top: 5px; | ||
} | ||
|
||
.url-field:focus { | ||
border-color: #3f3f3f; | ||
} | ||
|
||
/* Button that takes the user to the proxied page. */ | ||
.annotate-btn { | ||
background-color: #3f3f3f; | ||
border-radius: 3px; | ||
border: none; | ||
color: #fff; | ||
cursor: pointer; | ||
font-size: 20px; | ||
font-weight: 700; | ||
padding-bottom: 10px; | ||
padding-left: 15px; | ||
padding-right: 15px; | ||
padding-top: 10px; | ||
} | ||
|
||
.annotate-btn:hover { | ||
background-color: #d00032; | ||
} | ||
</style> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This CSS is all as-in legacy Via
<a href="https://hypothes.is"> | ||
<svg xmlns="http://www.w3.org/2000/svg" | ||
width="100" | ||
height="100" | ||
viewBox="0 0 24 28" | ||
aria-labelledby="logo-title"> | ||
<title id="logo-title">Hypothesis homepage</title> | ||
<g fill="none" fill-rule="evenodd"><path fill="#FFF" fill-rule="nonzero" d="M3.886 3.945H21.03v16.047H3.886z"/><path d="M0 2.005C0 .898.897 0 2.005 0h19.99C23.102 0 24 .897 24 2.005v19.99A2.005 2.005 0 0 1 21.995 24H2.005A2.005 2.005 0 0 1 0 21.995V2.005zM9 24h6l-3 4-3-4zM7.008 4H4v16h3.008v-4.997C7.008 12.005 8.168 12.01 9 12c1 .007 2.019.06 2.019 2.003V20h3.008v-6.891C14.027 10 12 9.003 10 9.003c-1.99 0-2 0-2.992 1.999V4zM19 19.987c1.105 0 2-.893 2-1.994A1.997 1.997 0 0 0 19 16c-1.105 0-2 .892-2 1.993s.895 1.994 2 1.994z" fill="#3F3F3F"/></g> | ||
</svg> | ||
</a> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logo as in legacy Via
<p> | ||
Via is a closed proxy that lets you annotate web pages and PDFs with | ||
Hypothesis. Only a small number of known sites can be annotated. If you'd | ||
like to annotate a site that isn't allowed please | ||
<a href="https://web.hypothes.is/via-request/">ask us to add it to the allowed list.</a> | ||
See our | ||
<a href="https://web.hypothes.is/help/what-is-the-via-proxy/">help article</a> | ||
for more information. | ||
</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same exact notice as from legacy Via
renderer="via:templates/exception.html.jinja2", | ||
# Match any page *except* the front page ("/"). | ||
# We don't want our fancy error page to be used on the front page. | ||
path_info=not_(r"^\/$"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We actually do want to apply the exception view to the front page now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you clarify when this would be used in the context of the front page?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I don't think that it can be used, since the views for the front page never raise anything, but the the exception was put here originally when we removed Via 3's front page (to hide Via 3 from abusers because we didn't want the resulting 404 for via3.hypothes.is requests to cause the fancy error page to kick in. Now that we're putting the front page back it's no longer needed
@view_config(route_name="proxy", renderer="via:templates/proxy.html.jinja2") | ||
def proxy(request): | ||
url = request.path[1:] # Strip the leading "/" from the path. | ||
|
||
# Let people just type in "example.com" or link to | ||
# via.hypothes.is/example.com and have that proxy https://example.com. | ||
if not (url.startswith("http://") or url.startswith("https://")): | ||
url = "https://" + url | ||
|
||
return {"src": request.route_url("route_by_content", _query={"url": url})} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the view that implements the legacy Via-style URLs. It accepts requests to via.hypothes.is/<URL_TO_BE_PROXIED>
and renders a page containing an iframe whose src
is via.hypothes.is/route?url=<URL_TO_BE_PROXIED>
. That iframe will then get redirect to either /pdf
or to Via HTML as appropriate, but the user isn't seeing the iframe's URL in the location bar so the /route
, /pdf
and Via HTML URLs are hidden from the user
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to save that extra redirect from the flow, since that involves an extra roundtrip between the user's browser and Via.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe caching?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, the new view can also do the same PDF-or-HTML check that the /route
view does and inject the /pdf
or Via HTML URL directly, so we should be able to remove the extra round trip
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made an issue for this #451
via/views/index.py
Outdated
@staticmethod | ||
@view_config(request_method="GET", renderer="via:templates/index.html.jinja2") | ||
def get(): | ||
return {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The front page. Renders the form where you can enter a URL that you want to annotate
via/views/index.py
Outdated
@view_config(request_method="POST") | ||
def post(self): | ||
return HTTPFound( | ||
self.request.route_url( | ||
route_name="proxy", url=self.request.params.get("url", "") | ||
) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the view for POST requests to the front page. Accepts form submissions and redirects to the legacy Via-style URL for proxying the URL that was submitted in the form.
If there is no url
param or if it's an empty string this ends up redirecting back to the front page.
If url
isn't a valid URL that'll trigger the existing nice error page when we try to proxy it. There's no need for this view to validate URLs.
For PDFs this was addressed by #427. For HTML documents this is handled by a |
Yes, something like the following in the viahtml iframe: // Is this a top-level iframe embedded inside Via?
if (window.top !== window && window.top === window.parent) {
window.top.postMessage({
type: 'via:urlChange',
url: window.location.href,
}, '*');
} And then corresponding code in the Via 3 frame that uses the history API to update the URL. The most obvious and immediate deficiency from a user's point of view though is that the document title is not set. We could notify Via about that in a similar way. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with some minor feedback and queries on the CSS.
From the user's perspective the most obvious issue with the iframe approach from initial testing is that the proxied document's title, favicon and loading status are not reflected in the tab state. Reflecting basic document metadata (or some variant of it) is something that can be solved. I'm not sure about the loading status. We might want to consider displaying some kind of placeholder in the blank frame until it has loaded.
<meta charset="utf-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<title>via.hypothes.is</title> | ||
<link rel="icon" href="favicon.ico" type="image/x-icon" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're going the iframe route I do think we'll need to work on updating at least some of the parent page metadata (eg. title) to make tabs distinguishable from one another. A bonus here is that we can easily add some indicator that the frame is being proxied through Via to make it easily distinguishable from the original page in bookmarks etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah, that's nice. I think we probably actually want the favicon to be the Hypothesis one not the third-party one. But we could set the tab title to something like Via - <title of third-party page>
(or perhaps Hypothesis -
?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made an issue for this: hypothesis/viahtml#154
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that I don't think we want the favicon to change (even though it does with legacy Via)
autofocus | ||
class="url-field" | ||
name="url" | ||
placeholder="Paste a link to annotate" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Legacy Via has a slightly different placeholder which reads "Paste a link to create or view annotations".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I know, I thought I'd sneak this change in :) "Create or view annotations" is pretty awkward, typical Hypothesis-speak. Maybe it should say "Create or view annotations, highlights and page notes" :)
via/templates/proxy.html.jinja2
Outdated
margin: 0; | ||
padding: 0; | ||
overflow: hidden; | ||
z-index: 999999; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the z-index for? There is nothing that the iframe needs to be positioned on top of.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure, it doesn't seem to be necessary so I'll try removing it
via/templates/proxy.html.jinja2
Outdated
border: none; | ||
margin: 0; | ||
padding: 0; | ||
overflow: hidden; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is overflow
for? An iframe can't overflow its container AFAIK so there is no need for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again not sure, I'll try removing it
via/templates/proxy.html.jinja2
Outdated
padding: 0; | ||
} | ||
|
||
.iframe { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you give this class a more meaningful name. Say proxied-content-iframe
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
renderer="via:templates/exception.html.jinja2", | ||
# Match any page *except* the front page ("/"). | ||
# We don't want our fancy error page to be used on the front page. | ||
path_info=not_(r"^\/$"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you clarify when this would be used in the context of the front page?
# Let people just type in "example.com" or link to | ||
# via.hypothes.is/example.com and have that proxy https://example.com. | ||
if not (url.startswith("http://") or url.startswith("https://")): | ||
url = "https://" + url |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC legacy via used to default to http://
but I think https://
is the right choice in the modern era. We'll have to keep an eye out for this.
@view_config(route_name="proxy", renderer="via:templates/proxy.html.jinja2") | ||
def proxy(request): | ||
url = request.path[1:] # Strip the leading "/" from the path. | ||
|
||
# Let people just type in "example.com" or link to | ||
# via.hypothes.is/example.com and have that proxy https://example.com. | ||
if not (url.startswith("http://") or url.startswith("https://")): | ||
url = "https://" + url | ||
|
||
return {"src": request.route_url("route_by_content", _query={"url": url})} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to save that extra redirect from the flow, since that involves an extra roundtrip between the user's browser and Via.
That might actually be quite a nice UX, as it can signal to the user that via.hypothes.is has loaded and they're now waiting for example.com to load/proxy. Created an issue for this: hypothesis/viahtml#155 |
Ok, sounds like this is handled for both Via 3 and Via HTML, so nothing to do. |
Opened an issue for this: hypothesis/viahtml#156 |
See #424
TODO:
Known issues:
The URL in the location bar won't change if the iframe is navigated. For example if the third-party URL returns a redirect. I think this is different from how legacy Via behaves. But I'm not completely sure it's actually a problem. I might propose to open an issue to track this but not fix it unless we decide we have to.
In theory I think this is fixable by adding a bit of JavaScript to either poll or get notified of changes to the iframe's URL and push new URLs onto the location bar without triggering page reloads.