Wikipedia viewer

Here we have three pages: one that sources a wikipedia page, and two that can point to a hyperlink and follow it. I have added a text box at the top where the topic can be switched. This demo was inspired by this video.

Topic:

The most interesting new feature here is that we have an async fetch of a webpage triggered by page rules. When a page declares that some web content needs to be accessed, how do we handle waiting for that to be fetched? We probably want to avoid everything becomes unresponsive or update cycles to overlap. Since we don't have access to async/await in Scheme (though perhaps we do, see Hoot docs), I decided to handle this in Javascript.

const cache = new Map(); function getCachedUrl(url) { return cache.get(url) || null; } function getUrl(url) { const ans = getCachedUrl(url) if (ans === null) { fetchAndCacheUrl(url) return "" } return ans } async function fetchAndCacheUrl(url) { if (cache.has(url)) return; // already fetched or in progress try { const response = await fetch(url); if (!response.ok) throw new Error('Failed to fetch url'); const data = await response.text(); cache.set(url, data); const event = new Event("urlfetched"); window.dispatchEvent(event); } catch (err) { console.error('Fetch error:', err); } }

The getUrl function is registered to be accessible by Scheme. It attempts to get the contents from a cache and kicks of an async function to retrieve it through the fetch API if the cache does not contain it. Crucially, the resulting promise is not awaited. At some later point, after the promise is resolved, the cache may now contain the content we were looking for. In order to notify RealTalk that content has arrived, we can simply dispatch an event and have that trigger another update cycle:

(add-event-listener! (window) "urlfetched" (procedure->external (lambda (e) (recalculate-pages))))

Pointing at links requires only a small modification to our previous code for whiskers. The main logic is in declaring a page to be a 'wiki': for ease of coding we will include a page's dimensions in that one fact. Pages that are wikis retrieve a wikipedia page on the topic and project the first paragraph to their right. All <a> elements within that paragraph have their geometry asserted.

(When ((wiki ,?p (,?x ,?y ,?w ,?topic))) do (let* ((text-div (make-element "div")) (table-div (get-element-by-id "table")) (p (make-element "p")) (url (string-append urlpref ?topic)) (parsed (parse-dom (wiki-html url))) ; this is the first paragraph when returned by wiki REST API (dom (query-selector parsed "style ~ p:not([class])" )) (html (if (external-null? dom) "" (get-property dom "innerHTML")))) (set-attribute! text-div "class" "text-projection") (set-style-left! text-div (format #f "~apx" (+ ?x ?w 10))) (set-style-top! text-div (format #f "~apx" ?y)) (set-property! p "innerHTML" html) (append-child! text-div p) (append-child! table-div text-div) ; find all <a> elements and assert their geometry (if (not (external-null? dom)) (for-each (lambda (link) (claim-link-dimensions link)) (arr->list (query-selector-all text-div "a"))))))

Page #1 is always declared as a wiki; the other pages are wikis when they point at a link, and their topic is the link's inner HTML text:

(When ((points-at ,?p ,?link) ((page left) ,?p ,?x) ((page top) ,?p ,?y) ((page width) ,?p ,?w)) do (let ((topic (get-property ?link "innerHTML"))) (set-background! ?link "hotpink") (Claim ?p 'wiki `(,?x ,?y ,?w ,topic))))

Home