| 41 |
41 |
|
//! and every one of the twelve is a POST to our own route that answers with a
|
| 42 |
42 |
|
//! redirect. Filed against quasicoherent rather than worked around with a
|
| 43 |
43 |
|
//! hand-written attribute inside a described form.
|
|
44 |
+ |
//!
|
|
45 |
+ |
//! # The visitor's sentence carries `nofollow`, and should not
|
|
46 |
+ |
//!
|
|
47 |
+ |
//! `Node::rich` renders through `docengine::render_strict`, the preset written
|
|
48 |
+ |
//! for user-generated content, so the two links in that sentence come out with
|
|
49 |
+ |
//! `rel="noopener noreferrer nofollow"`. They point at `/join` and `/login`:
|
|
50 |
+ |
//! our own pages, telling crawlers not to follow them. quasi has one `Rich` and
|
|
51 |
+ |
//! treats every source as untrusted, which is right for a forum post and wrong
|
|
52 |
+ |
//! for a page's own copy. quasicoherent `24a3b1df`.
|
| 44 |
53 |
|
|
| 45 |
54 |
|
use makeover_layout as layout;
|
| 46 |
55 |
|
use quasi_router::screen::{Figure, Row};
|
| 151 |
160 |
|
// Fan+ needs an account, so a visitor gets both paths: the one for
|
| 152 |
161 |
|
// people who already have one and the one for people who do not.
|
| 153 |
162 |
|
// Without the second this page is a dead end for exactly the
|
| 154 |
|
- |
// visitor it is written for.
|
| 155 |
|
- |
pitch(page)
|
| 156 |
|
- |
.with(Node::act(
|
| 157 |
|
- |
"Create an account",
|
| 158 |
|
- |
Action::get("/join").navigating(),
|
| 159 |
|
- |
))
|
| 160 |
|
- |
.with(Node::act("Log in", Action::get("/login").navigating()))
|
|
163 |
+ |
// visitor it is written for (`loose-wire g1-23`, and
|
|
164 |
+ |
// `fan_plus_page_renders_for_anonymous` is the seal).
|
|
165 |
+ |
//
|
|
166 |
+ |
// One sentence with two inline links, not two buttons. The sentence
|
|
167 |
+ |
// says which link is for whom and a pair of buttons does not, and
|
|
168 |
+ |
// that distinction is the whole point of the finding above. It is
|
|
169 |
+ |
// prose, so it is `Node::rich`, on `/policy`'s rule.
|
|
170 |
+ |
pitch(page).with(Node::rich(
|
|
171 |
+ |
"[Create an account](/join) to join, or [log in](/login) if you already have one.",
|
|
172 |
+ |
))
|
| 161 |
173 |
|
}
|
| 162 |
174 |
|
};
|
| 163 |
175 |
|
|
| 242 |
254 |
|
fn a_visitor_is_offered_an_account_rather_than_a_dead_end() {
|
| 243 |
255 |
|
let html = html(&Standing::Visitor, false);
|
| 244 |
256 |
|
|
|
257 |
+ |
// Asserted on each link's own copy rather than on the bare hrefs: the
|
|
258 |
+ |
// site header carries `/join` and `/login` on every page, so an href
|
|
259 |
+ |
// alone would pass whatever this block said.
|
|
260 |
+ |
//
|
|
261 |
+ |
// Matched loosely across the anchor's attributes because `Node::rich`
|
|
262 |
+ |
// hardens links as untrusted content and adds
|
|
263 |
+ |
// `rel="noopener noreferrer nofollow"` (quasicoherent `24a3b1df`). The
|
|
264 |
+ |
// exact-markup form belongs back here when a screen can say its prose
|
|
265 |
+ |
// is its own.
|
| 245 |
266 |
|
assert!(html.contains(r#"href="/join""#), "{html}");
|
|
267 |
+ |
assert!(html.contains("Create an account</a> to join"), "{html}");
|
| 246 |
268 |
|
assert!(html.contains(r#"href="/login""#), "{html}");
|
|
269 |
+ |
assert!(
|
|
270 |
+ |
html.contains("log in</a> if you already have one"),
|
|
271 |
+ |
"{html}"
|
|
272 |
+ |
);
|
| 247 |
273 |
|
assert!(
|
| 248 |
274 |
|
!html.contains(SUBSCRIBE),
|
| 249 |
275 |
|
"a visitor cannot subscribe, so the control must not be drawn: {html}"
|