├── .github └── FUNDING.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── build-docs.sh ├── demo ├── demo.png └── demo.rkt ├── docs ├── index.html ├── manual-fonts.css ├── manual-racket.css ├── manual-racket.js ├── manual-style.css ├── racket.css ├── scribble-common.js └── scribble.css ├── info.rkt ├── main.rkt ├── private ├── web-view.rkt ├── webkit.rkt └── wkwebview.rkt └── scribblings └── web-view.scrbl /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | \#* 3 | .\#* 4 | .DS_Store 5 | compiled/ 6 | /doc/ 7 | *.dmg -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | # Based on: https://github.com/greghendershott/travis-racket 4 | 5 | env: 6 | global: 7 | # Supply a global RACKET_DIR environment variable. This is where 8 | # Racket will be installed. A good idea is to use ~/racket because 9 | # that doesn't require sudo to install. 10 | - RACKET_DIR=~/racket 11 | matrix: 12 | # Supply at least one RACKET_VERSION environment variable. This is 13 | # used by the install-racket.sh script (run at before_install, 14 | # below) to select the version of Racket to download and install. 15 | # 16 | # Supply more than one RACKET_VERSION (as in the example below) to 17 | # create a Travis-CI build matrix to test against multiple Racket 18 | # versions. 19 | - RACKET_VERSION=6.12 20 | - RACKET_VERSION=7.0 21 | - RACKET_VERSION=7.1 22 | - RACKET_VERSION=7.2 23 | - RACKET_VERSION=HEAD 24 | 25 | matrix: 26 | allow_failures: 27 | # - env: RACKET_VERSION=HEAD 28 | fast_finish: true 29 | 30 | before_install: 31 | - git clone https://github.com/greghendershott/travis-racket.git ~/travis-racket 32 | - cat ~/travis-racket/install-racket.sh | bash # pipe to bash not sh! 33 | - export PATH="${RACKET_DIR}/bin:${PATH}" #install-racket.sh can't set for us 34 | 35 | install: 36 | - raco pkg install --auto --name web-view 37 | 38 | before_script: 39 | 40 | # Here supply steps such as raco make, raco test, etc. You can run 41 | # `raco pkg install --deps search-auto` to install any required 42 | # packages without it getting stuck on a confirmation prompt. 43 | script: 44 | - raco test -x -p web-view 45 | 46 | after_success: 47 | - raco setup --check-pkg-deps --pkgs web-view 48 | - raco pkg install --auto cover cover-coveralls 49 | - raco cover -b -f coveralls -d $TRAVIS_BUILD_DIR/coverage . 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | web-view 2 | 3 | MIT License 4 | 5 | Copyright (c) 2019 agarzia 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | web-view% 2 | ======== 3 | 4 | ![Screenshot: web-view% in action](https://github.com/soapdog/racket-web-view/raw/master/demo/demo.png) 5 | 6 | A Racket package to provide a `web-view%` control to applications based on Racket GUI Toolkit. 7 | 8 | There is some minimal [documentation available](https://soapdog.github.io/racket-web-view/). 9 | 10 | This repo is also available at [sourcehut](https://git.sr.ht/~soapdog/racket-web-view). 11 | 12 | ## What works 13 | 14 | You can create a `web-view%`, set its URL and the page loads. You can navigate as well. 15 | 16 | ## What doesn't work 17 | 18 | Everything else. 19 | 20 | Also, at the moment it is macOS only. It wraps around WKWebView. 21 | 22 | # Demo 23 | 24 | Install the package with the following command on the checkout folder for this repo: 25 | 26 | ``` 27 | $ raco pkg install 28 | ``` 29 | 30 | You can run a demo with by loading `demo/demo.rkt`. 31 | 32 | # Sample code: 33 | 34 | ``` 35 | (define web-view 36 | (new web-view% 37 | [parent panel])) 38 | 39 | (send web-view set-url "https://racket-lang.org") 40 | ``` 41 | 42 | --- 43 | 44 | -------------------------------------------------------------------------------- /build-docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd ./scribblings 4 | scribble --htmls ++main-xref-in --redirect-main http://docs.racket-lang.org/ --dest ../docs/ ./web-view.scrbl 5 | cd ../docs 6 | mv ./web-view/* ./ 7 | rm -rf ./web-view 8 | cd .. -------------------------------------------------------------------------------- /demo/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soapdog/racket-web-view/fa16e0c31b5a3e75c543df3107d8c8a230a10934/demo/demo.png -------------------------------------------------------------------------------- /demo/demo.rkt: -------------------------------------------------------------------------------- 1 | #lang at-exp racket/gui 2 | 3 | (require web-view) 4 | 5 | (define frame 6 | (new frame% 7 | [label "Demo Browser"] 8 | [width 800] 9 | [height 600] 10 | [x 100] 11 | [y 100])) 12 | 13 | (define toolbar 14 | (new horizontal-panel% 15 | [parent frame] 16 | [min-height 40] 17 | [stretchable-height #f])) 18 | 19 | (define (go-to-url button event) 20 | (send web-view set-url (send address-bar get-value))) 21 | 22 | (define test-html @string-append{ 23 |

It Works

24 |

This is a test of setting the HTML text of the browser to a string 25 | instead of a URL.

26 | }) 27 | 28 | (define (test-text button event) 29 | (send web-view set-html-text test-html "")) 30 | 31 | (define (go-forward button event) 32 | (send web-view go-forward)) 33 | 34 | (define (go-back button event) 35 | (send web-view go-back)) 36 | 37 | (define (reload button event) 38 | (send web-view reload)) 39 | 40 | (define address-bar 41 | (new text-field% 42 | [parent toolbar] 43 | [label "URL"])) 44 | 45 | (define go-button 46 | (new button% 47 | [parent toolbar] 48 | [label "Go"] 49 | [callback go-to-url])) 50 | 51 | 52 | (define go-back-button 53 | (new button% 54 | [parent toolbar] 55 | [label "<"] 56 | [callback go-back])) 57 | 58 | (define go-forward-button 59 | (new button% 60 | [parent toolbar] 61 | [label ">"] 62 | [callback go-forward])) 63 | 64 | (define reload-button 65 | (new button% 66 | [parent toolbar] 67 | [label "reload"] 68 | [callback reload])) 69 | 70 | (define test-text-button 71 | (new button% 72 | [parent toolbar] 73 | [label "text"] 74 | [callback test-text])) 75 | 76 | (define (resize-browser w h) 77 | (send web-view on-size w h)) 78 | 79 | (send frame show #t) 80 | (send frame create-status-line) 81 | 82 | (define (status-change status) 83 | (begin0 84 | (send frame set-status-text status))) 85 | 86 | ; needs to be after parent show so that we have parents dimensions 87 | (define web-view 88 | (new web-view% 89 | [parent frame] 90 | [on-status-change status-change])) 91 | 92 | (send web-view set-url "https://racket-lang.org") 93 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | A Racket GUI widget to display web pages
On this page:
A Racket GUI widget to display web pages
web-view%
new
set-url
get-url
go-forward
go-back
reload
set-html-text
7.4

A Racket GUI widget to display web pages

Andre Alves Garzia

 (require web-view) package: web-view

This module contains a Web View to be used with Racket GUI Toolkit. At the moment it works only with macOS because it wraps WKWebView from WebKit.

There is a Demo Browser available on the Github Repository.

class

web-view% : class?

  superclass: object%

A widget to display web pages.

constructor

(new web-view% 
    [parent parent] 
    [[on-status-change on-status-change]]) 
  (is-a?/c web-view%)
  parent : 
(or/c (is-a?/c frame%)
      (is-a?/c dialog%)
      (is-a?/c panel%)
      (is-a?/c pane%))
  on-status-change : ((is-a?/c button%) (is-a?/c control-event%) . -> . any)
   = (lambda (b e) (void))
Construct a new widget.

The on-status-change procedure is used to receive navigation events from the web view.

method

(send a-web-view set-url url)  any/c

  url : string?
Set the URL for the web view.

method

(send a-web-view get-url)  string?

Get the current URL loaded in the web view.

method

(send a-web-view go-forward)  any/c

Navigates forward.

method

(send a-web-view go-back)  any/c

Navigates backward.

method

(send a-web-view reload)  any/c

Reloads the current page.

method

(send a-web-view set-html-text text    
  base-url)  any/c
  text : string?
  base-url : string?
Sets the HTML text being used by the web view. Any relative url will be relative to the specified base url.

 
-------------------------------------------------------------------------------- /docs/manual-racket.css: -------------------------------------------------------------------------------- 1 | /* See the beginning of "manual.css". */ 2 | 3 | /* Monospace: */ 4 | 5 | .RktIn, .RktRdr, .RktPn, .RktMeta, 6 | .RktMod, .RktKw, .RktVar, .RktSym, 7 | .RktRes, .RktOut, .RktCmt, .RktVal, 8 | .RktBlk, .RktErr { 9 | font-family: 'Fira-Mono', monospace; 10 | white-space: inherit; 11 | font-size: 1rem; 12 | line-height: 1.5; 13 | 14 | } 15 | 16 | /* this selctor grabs the first linked Racket symbol 17 | in a definition box (i.e., the symbol being defined) */ 18 | a.RktValDef, a.RktStxDef, a.RktSymDef, 19 | span.RktValDef, span.RktStxDef, span.RktSymDef 20 | { 21 | font-size: 1.1rem; 22 | color: black; 23 | font-weight: 500; 24 | } 25 | 26 | 27 | .inheritedlbl { 28 | font-family: 'Fira', sans-serif; 29 | } 30 | 31 | .RBackgroundLabelInner { 32 | font-family: inherit; 33 | } 34 | 35 | /* ---------------------------------------- */ 36 | /* Inherited methods, left margin */ 37 | 38 | .inherited { 39 | width: 95%; 40 | margin-top: 0.5em; 41 | text-align: left; 42 | background-color: inherit; 43 | } 44 | 45 | .inherited td { 46 | font-size: 82%; 47 | padding-left: 0.5rem; 48 | line-height: 1.3; 49 | text-indent: 0; 50 | padding-right: 0; 51 | } 52 | 53 | .inheritedlbl { 54 | font-style: normal; 55 | } 56 | 57 | /* ---------------------------------------- */ 58 | /* Racket text styles */ 59 | 60 | .RktIn { 61 | color: #cc6633; 62 | background-color: #eee; 63 | } 64 | 65 | .RktInBG { 66 | background-color: #eee; 67 | } 68 | 69 | 70 | .refcolumn .RktInBG { 71 | background-color: white; 72 | } 73 | 74 | .RktRdr { 75 | } 76 | 77 | .RktPn { 78 | color: #843c24; 79 | } 80 | 81 | .RktMeta { 82 | color: black; 83 | } 84 | 85 | .RktMod { 86 | color: inherit; 87 | } 88 | 89 | .RktOpt { 90 | color: black; 91 | } 92 | 93 | .RktKw { 94 | color: black; 95 | } 96 | 97 | .RktErr { 98 | color: red; 99 | font-style: italic; 100 | font-weight: 400; 101 | } 102 | 103 | .RktVar { 104 | position: relative; 105 | left: -1px; font-style: italic; 106 | color: #444; 107 | } 108 | 109 | .SVInsetFlow .RktVar { 110 | font-weight: 400; 111 | color: #444; 112 | } 113 | 114 | 115 | .RktSym { 116 | color: inherit; 117 | } 118 | 119 | 120 | 121 | .RktValLink, .RktStxLink, .RktModLink { 122 | text-decoration: none; 123 | color: #07A; 124 | font-size: 1rem; 125 | } 126 | 127 | /* for syntax links within headings */ 128 | h2 a.RktStxLink, h3 a.RktStxLink, h4 a.RktStxLink, h5 a.RktStxLink, 129 | h2 a.RktValLink, h3 a.RktValLink, h4 a.RktValLink, h5 a.RktValLink, 130 | h2 .RktSym, h3 .RktSym, h4 .RktSym, h5 .RktSym, 131 | h2 .RktMod, h3 .RktMod, h4 .RktMod, h5 .RktMod, 132 | h2 .RktVal, h3 .RktVal, h4 .RktVal, h5 .RktVal, 133 | h2 .RktPn, h3 .RktPn, h4 .RktPn, h5 .RktPn { 134 | color: #333; 135 | font-size: 1.50rem; 136 | font-weight: 400; 137 | } 138 | 139 | .toptoclink .RktStxLink, .toclink .RktStxLink, 140 | .toptoclink .RktValLink, .toclink .RktValLink, 141 | .toptoclink .RktModLink, .toclink .RktModLink { 142 | color: inherit; 143 | } 144 | 145 | .tocset .RktValLink, .tocset .RktStxLink, .tocset .RktModLink, .tocset .RktSym { 146 | color: black; 147 | font-weight: 400; 148 | font-size: 0.9rem; 149 | } 150 | 151 | .tocset td a.tocviewselflink .RktValLink, 152 | .tocset td a.tocviewselflink .RktStxLink, 153 | .tocset td a.tocviewselflink .RktMod, 154 | .tocset td a.tocviewselflink .RktSym { 155 | font-weight: lighter; 156 | color: white; 157 | } 158 | 159 | 160 | .RktRes { 161 | color: #0000af; 162 | } 163 | 164 | .RktOut { 165 | color: #960096; 166 | } 167 | 168 | .RktCmt { 169 | color: #c2741f; 170 | } 171 | 172 | .RktVal { 173 | color: #228b22; 174 | } 175 | 176 | /* ---------------------------------------- */ 177 | /* Some inline styles */ 178 | 179 | .together { /* for definitions grouped together in one box */ 180 | width: 100%; 181 | border-top: 2px solid white; 182 | } 183 | 184 | tbody > tr:first-child > td > .together { 185 | border-top: 0px; /* erase border on first instance of together */ 186 | } 187 | 188 | .RktBlk { 189 | white-space: pre; 190 | text-align: left; 191 | } 192 | 193 | .highlighted { 194 | font-size: 1rem; 195 | background-color: #fee; 196 | } 197 | 198 | .defmodule { 199 | font-family: 'Fira-Mono', monospace; 200 | padding: 0.25rem 0.75rem 0.25rem 0.5rem; 201 | margin-bottom: 1rem; 202 | width: 100%; 203 | background-color: #ebf0f4; 204 | } 205 | 206 | .defmodule a { 207 | color: #444; 208 | } 209 | 210 | 211 | .defmodule td span.hspace:first-child { 212 | position: absolute; 213 | width: 0; 214 | display: inline-block; 215 | } 216 | 217 | .defmodule .RpackageSpec .Smaller, 218 | .defmodule .RpackageSpec .stt { 219 | font-size: 1rem; 220 | } 221 | 222 | /* make parens ordinary color in defmodule */ 223 | .defmodule .RktPn { 224 | color: inherit; 225 | } 226 | 227 | .specgrammar { 228 | float: none; 229 | padding-left: 1em; 230 | } 231 | 232 | 233 | .RBibliography td { 234 | vertical-align: text-top; 235 | padding-top: 1em; 236 | } 237 | 238 | .leftindent { 239 | margin-left: 2rem; 240 | margin-right: 0em; 241 | } 242 | 243 | .insetpara { 244 | margin-left: 1em; 245 | margin-right: 1em; 246 | } 247 | 248 | .SCodeFlow .Rfilebox { 249 | margin-left: -1em; /* see 17.2 of guide, module languages */ 250 | } 251 | 252 | .Rfiletitle { 253 | text-align: right; 254 | background-color: #eee; 255 | } 256 | 257 | .SCodeFlow .Rfiletitle { 258 | border-top: 1px dotted gray; 259 | border-right: 1px dotted gray; 260 | } 261 | 262 | 263 | .Rfilename { 264 | border-top: 0; 265 | border-right: 0; 266 | padding-left: 0.5em; 267 | padding-right: 0.5em; 268 | background-color: inherit; 269 | } 270 | 271 | .Rfilecontent { 272 | margin: 0.5em; 273 | } 274 | 275 | .RpackageSpec { 276 | padding-right: 0; 277 | } 278 | 279 | /* ---------------------------------------- */ 280 | /* For background labels */ 281 | 282 | .RBackgroundLabel { 283 | float: right; 284 | width: 0px; 285 | height: 0px; 286 | } 287 | 288 | .RBackgroundLabelInner { 289 | position: relative; 290 | width: 25em; 291 | left: -25.5em; 292 | top: 0.20rem; /* sensitive to monospaced font choice */ 293 | text-align: right; 294 | z-index: 0; 295 | font-weight: 300; 296 | font-family: 'Fira-Mono', monospace; 297 | font-size: 0.9rem; 298 | color: gray; 299 | } 300 | 301 | 302 | .RpackageSpec .Smaller { 303 | font-weight: 300; 304 | font-family: 'Fira-Mono', monospace; 305 | font-size: 0.9rem; 306 | } 307 | 308 | .RForeground { 309 | position: relative; 310 | left: 0px; 311 | top: 0px; 312 | z-index: 1; 313 | } 314 | 315 | /* ---------------------------------------- */ 316 | /* For section source modules & tags */ 317 | 318 | .RPartExplain { 319 | background: #eee; 320 | font-size: 0.9rem; 321 | margin-top: 0.2rem; 322 | padding: 0.2rem; 323 | text-align: left; 324 | } 325 | -------------------------------------------------------------------------------- /docs/manual-racket.js: -------------------------------------------------------------------------------- 1 | /* For the Racket manual style */ 2 | 3 | AddOnLoad(function() { 4 | /* Look for header elements that have x-source-module and x-part tag. 5 | For those elements, add a hidden element that explains how to 6 | link to the section, and set the element's onclick() to display 7 | the explanation. */ 8 | var tag_names = ["h1", "h2", "h3", "h4", "h5"]; 9 | for (var j = 0; j < tag_names.length; j++) { 10 | elems = document.getElementsByTagName(tag_names[j]); 11 | for (var i = 0; i < elems.length; i++) { 12 | var elem = elems.item(i); 13 | AddPartTitleOnClick(elem); 14 | } 15 | } 16 | }) 17 | 18 | function AddPartTitleOnClick(elem) { 19 | var mod_path = elem.getAttribute("x-source-module"); 20 | var tag = elem.getAttribute("x-part-tag"); 21 | if (mod_path && tag) { 22 | // Might not be present: 23 | var prefixes = elem.getAttribute("x-part-prefixes"); 24 | 25 | var info = document.createElement("div"); 26 | info.className = "RPartExplain"; 27 | 28 | /* The "top" tag refers to a whole document: */ 29 | var is_top = (tag == "\"top\""); 30 | info.appendChild(document.createTextNode("Link to this " 31 | + (is_top ? "document" : "section") 32 | + " with ")); 33 | 34 | /* Break `secref` into two lines if the module path and tag 35 | are long enough: */ 36 | var is_long = (is_top ? false : ((mod_path.length 37 | + tag.length 38 | + (prefixes ? (16 + prefixes.length) : 0)) 39 | > 60)); 40 | 41 | var line1 = document.createElement("div"); 42 | var line1x = ((is_long && prefixes) ? document.createElement("div") : line1); 43 | var line2 = (is_long ? document.createElement("div") : line1); 44 | 45 | function add(dest, str, cn) { 46 | var s = document.createElement("span"); 47 | s.className = cn; 48 | s.style.whiteSpace = "nowrap"; 49 | s.appendChild(document.createTextNode(str)); 50 | dest.appendChild(s); 51 | } 52 | /* Construct a `secref` call with suitable syntax coloring: */ 53 | add(line1, "\xA0@", "RktRdr"); 54 | add(line1, (is_top ? "other-doc" : "secref"), "RktSym"); 55 | add(line1, "[", "RktPn"); 56 | if (!is_top) 57 | add(line1, tag, "RktVal"); 58 | if (is_long) { 59 | /* indent additional lines: */ 60 | if (prefixes) 61 | add(line1x, "\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0", "RktPn"); 62 | add(line2, "\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0", "RktPn"); 63 | } 64 | if (prefixes) { 65 | add(line1x, " #:tag-prefixes ", "RktPn"); 66 | add(line1x, "'", "RktVal"); 67 | add(line1x, prefixes, "RktVal"); 68 | } 69 | if (!is_top) 70 | add(line2, " #:doc ", "RktPn"); 71 | add(line2, "'", "RktVal"); 72 | add(line2, mod_path, "RktVal"); 73 | add(line2, "]", "RktPn"); 74 | 75 | info.appendChild(line1); 76 | if (is_long) 77 | info.appendChild(line1x); 78 | if (is_long) 79 | info.appendChild(line2); 80 | 81 | info.style.display = "none"; 82 | 83 | /* Add the new element afterthe header: */ 84 | var n = elem.nextSibling; 85 | if (n) 86 | elem.parentNode.insertBefore(info, n); 87 | else 88 | elem.parentNode.appendChild(info); 89 | 90 | /* Clicking the header shows the explanation element: */ 91 | elem.onclick = function () { 92 | if (info.style.display == "none") 93 | info.style.display = "block"; 94 | else 95 | info.style.display = "none"; 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /docs/manual-style.css: -------------------------------------------------------------------------------- 1 | 2 | /* See the beginning of "scribble.css". 3 | This file is used by the `scribble/manual` language, along with 4 | "manual-racket.css". */ 5 | 6 | @import url("manual-fonts.css"); 7 | 8 | * { 9 | margin: 0; 10 | padding: 0; 11 | } 12 | 13 | @media all {html {font-size: 15px;}} 14 | @media all and (max-width:940px){html {font-size: 14px;}} 15 | @media all and (max-width:850px){html {font-size: 13px;}} 16 | @media all and (max-width:830px){html {font-size: 12px;}} 17 | @media all and (max-width:740px){html {font-size: 11px;}} 18 | 19 | /* CSS seems backward: List all the classes for which we want a 20 | particular font, so that the font can be changed in one place. (It 21 | would be nicer to reference a font definition from all the places 22 | that we want it.) 23 | 24 | As you read the rest of the file, remember to double-check here to 25 | see if any font is set. */ 26 | 27 | /* Monospace: */ 28 | .maincolumn, .refpara, .refelem, .tocset, .stt, .hspace, .refparaleft, .refelemleft { 29 | font-family: 'Fira-Mono', monospace; 30 | white-space: inherit; 31 | font-size: 1rem; 32 | } 33 | 34 | /* embolden the "Racket Guide" and "Racket Reference" links on the TOC */ 35 | /* there isn't an obvious tag in the markup that designates the top TOC page, which is called "start.scrbl" */ 36 | /* nor a tag that designates these two links as special */ 37 | /* so we'll use this slightly tortured sibling selector that hooks onto the h2 tag */ 38 | h2[x-source-module='(lib "scribblings/main/start.scrbl")'] ~ table a[href="guide/index.html"], 39 | h2[x-source-module='(lib "scribblings/main/start.scrbl")'] ~ table a[href="reference/index.html"] { 40 | font-weight: bold; 41 | } 42 | 43 | 44 | h2 .stt { 45 | font-size: 2.3rem; 46 | /* prevent automatic bolding from h2 */ 47 | font-weight: 400; 48 | } 49 | 50 | .toptoclink .stt { 51 | font-size: inherit; 52 | } 53 | .toclink .stt { 54 | font-size: 90%; 55 | } 56 | 57 | .RpackageSpec .stt { 58 | font-weight: 300; 59 | font-family: 'Fira-Mono', monospace; 60 | font-size: 0.9rem; 61 | } 62 | 63 | h3 .stt, h4 .stt, h5 .stt { 64 | color: #333; 65 | font-size: 1.65rem; 66 | font-weight: 400; 67 | } 68 | 69 | 70 | /* Serif: */ 71 | .main, .refcontent, .tocview, .tocsub, .sroman, i { 72 | font-family: 'Charter-Racket', serif; 73 | font-size: 1.18rem; 74 | /* Don't use font-feature-settings with Charter, 75 | it fouls up loading for reasons mysterious */ 76 | /* font-feature-settings: 'tnum' 1, 'liga' 0; */ 77 | } 78 | 79 | 80 | /* Sans-serif: */ 81 | .version, .versionNoNav, .ssansserif { 82 | font-family: 'Fira', sans-serif; 83 | } 84 | 85 | /* used mostly for DrRacket menu commands */ 86 | .ssansserif { 87 | font-family: 'Fira', sans-serif; 88 | font-size: 0.9em; 89 | } 90 | 91 | .tocset .ssansserif { 92 | font-size: 100%; 93 | } 94 | 95 | /* ---------------------------------------- */ 96 | 97 | p, .SIntrapara { 98 | display: block; 99 | margin: 0 0 1em 0; 100 | line-height: 1.4; 101 | } 102 | 103 | .compact { 104 | padding: 0 0 1em 0; 105 | } 106 | 107 | li { 108 | list-style-position: outside; 109 | margin-left: 1.2em; 110 | } 111 | 112 | h1, h2, h3, h4, h5, h6, h7, h8 { 113 | font-family: 'Fira', sans-serif; 114 | font-weight: 300; 115 | font-size: 1.6rem; 116 | color: #333; 117 | margin-top: inherit; 118 | margin-bottom: 1rem; 119 | line-height: 1.25; 120 | 121 | } 122 | 123 | h3, h4, h5, h6, h7, h8 { 124 | border-top: 1px solid black; 125 | } 126 | 127 | 128 | 129 | h2 { /* per-page main title */ 130 | font-family: 'Cooper-Hewitt'; 131 | margin-top: 4rem; 132 | font-size: 2.3rem; 133 | font-weight: bold; 134 | line-height: 1.2; 135 | width: 90%; 136 | /* a little nudge to make text visually lower than 4rem rule in left margin */ 137 | position: relative; 138 | top: 6px; 139 | } 140 | 141 | h3, h4, h5, h6, h7, h8 { 142 | margin-top: 2em; 143 | padding-top: 0.1em; 144 | margin-bottom: 0.75em; 145 | } 146 | 147 | /* ---------------------------------------- */ 148 | /* Main */ 149 | 150 | body { 151 | color: black; 152 | background-color: white; 153 | } 154 | 155 | .maincolumn { 156 | width: auto; 157 | margin-top: 4rem; 158 | margin-left: 17rem; 159 | margin-right: 2rem; 160 | margin-bottom: 10rem; /* to avoid fixed bottom nav bar */ 161 | max-width: 700px; 162 | min-width: 370px; /* below this size, code samples don't fit */ 163 | } 164 | 165 | a { 166 | text-decoration: inherit; 167 | } 168 | 169 | a, .toclink, .toptoclink, .tocviewlink, .tocviewselflink, .tocviewtoggle, .plainlink, 170 | .techinside, .techoutside:hover, .techinside:hover { 171 | color: #07A; 172 | } 173 | 174 | a:hover { 175 | text-decoration: underline; 176 | } 177 | 178 | 179 | /* ---------------------------------------- */ 180 | /* Navigation */ 181 | 182 | .navsettop, .navsetbottom { 183 | left: 0; 184 | width: 15rem; 185 | height: 6rem; 186 | font-family: 'Fira', sans-serif; 187 | font-size: 0.9rem; 188 | border-bottom: 0px solid hsl(216, 15%, 70%); 189 | background-color: inherit; 190 | padding: 0; 191 | } 192 | 193 | .navsettop { 194 | position: absolute; 195 | top: 0; 196 | left: 0; 197 | margin-bottom: 0; 198 | border-bottom: 0; 199 | } 200 | 201 | .navsettop a, .navsetbottom a { 202 | color: black; 203 | } 204 | 205 | .navsettop a:hover, .navsetbottom a:hover { 206 | background: hsl(216, 78%, 95%); 207 | text-decoration: none; 208 | } 209 | 210 | .navleft, .navright { 211 | position: static; 212 | float: none; 213 | margin: 0; 214 | white-space: normal; 215 | } 216 | 217 | 218 | .navleft a { 219 | display: inline-block; 220 | } 221 | 222 | .navright a { 223 | display: inline-block; 224 | text-align: center; 225 | } 226 | 227 | .navleft a, .navright a, .navright span { 228 | display: inline-block; 229 | padding: 0.5rem; 230 | min-width: 1rem; 231 | } 232 | 233 | 234 | .navright { 235 | height: 2rem; 236 | white-space: nowrap; 237 | } 238 | 239 | 240 | .navsetbottom { 241 | display: none; 242 | } 243 | 244 | .nonavigation { 245 | color: #889; 246 | } 247 | 248 | .searchform { 249 | display: block; 250 | margin: 0; 251 | padding: 0; 252 | border-bottom: 1px solid #eee; 253 | height: 4rem; 254 | } 255 | 256 | .nosearchform { 257 | margin: 0; 258 | padding: 0; 259 | height: 4rem; 260 | } 261 | 262 | .searchbox { 263 | font-size: 0.9rem; 264 | width: 12rem; 265 | margin: 1rem; 266 | padding: 0.25rem 0.4rem ; 267 | vertical-align: middle; 268 | background-color: white; 269 | font-family: 'Fira-Mono', monospace; 270 | } 271 | 272 | 273 | #search_box { 274 | font-family: 'Fira-Mono', monospace; 275 | font-size: 1rem; 276 | padding: 0.25rem 0.3rem ; 277 | } 278 | 279 | /* Default to local view. Global will specialize */ 280 | .plt_global_only { display: none; } 281 | .plt_local_only { display: block; } 282 | 283 | /* ---------------------------------------- */ 284 | /* Version */ 285 | 286 | .versionbox { 287 | position: absolute; 288 | float: none; 289 | top: 0.25rem; 290 | left: 17rem; 291 | z-index: 11000; 292 | height: 2em; 293 | font-size: 70%; 294 | font-weight: lighter; 295 | width: inherit; 296 | margin: 0; 297 | } 298 | .version, .versionNoNav { 299 | font-size: inherit; 300 | } 301 | .version:before, .versionNoNav:before { 302 | content: "v."; 303 | } 304 | 305 | 306 | /* ---------------------------------------- */ 307 | /* Margin notes */ 308 | 309 | /* cancel scribble.css styles: */ 310 | .refpara, .refelem { 311 | position: static; 312 | float: none; 313 | height: auto; 314 | width: auto; 315 | margin: 0; 316 | } 317 | 318 | .refcolumn { 319 | position: static; 320 | display: block; 321 | width: auto; 322 | font-size: inherit; 323 | margin: 2rem; 324 | margin-left: 2rem; 325 | padding: 0.5em; 326 | padding-left: 0.75em; 327 | padding-right: 1em; 328 | background: hsl(60, 29%, 94%); 329 | border: 1px solid #ccb; 330 | border-left: 0.4rem solid #ccb; 331 | } 332 | 333 | 334 | /* slightly different handling for margin-note* on narrow screens */ 335 | @media all and (max-width:1340px) { 336 | span.refcolumn { 337 | float: right; 338 | width: 50%; 339 | margin-left: 1rem; 340 | margin-bottom: 0.8rem; 341 | margin-top: 1.2rem; 342 | } 343 | 344 | } 345 | 346 | .refcontent, .refcontent p { 347 | line-height: 1.5; 348 | margin: 0; 349 | } 350 | 351 | .refcontent p + p { 352 | margin-top: 1em; 353 | } 354 | 355 | .refcontent a { 356 | font-weight: 400; 357 | } 358 | 359 | .refpara, .refparaleft { 360 | top: -1em; 361 | } 362 | 363 | 364 | @media all and (max-width:600px) { 365 | .refcolumn { 366 | margin-left: 0; 367 | margin-right: 0; 368 | } 369 | } 370 | 371 | 372 | @media all and (min-width:1340px) { 373 | .refcolumn { 374 | margin: 0 -22.5rem 1rem 0; 375 | float: right; 376 | clear: right; 377 | width: 18rem; 378 | } 379 | } 380 | 381 | .refcontent { 382 | font-family: 'Fira', sans-serif; 383 | font-size: 1rem; 384 | line-height: 1.6; 385 | margin: 0 0 0 0; 386 | } 387 | 388 | 389 | .refparaleft, .refelemleft { 390 | position: relative; 391 | float: left; 392 | right: 2em; 393 | height: 0em; 394 | width: 13em; 395 | margin: 0em 0em 0em -13em; 396 | } 397 | 398 | .refcolumnleft { 399 | background-color: hsl(60, 29%, 94%); 400 | display: block; 401 | position: relative; 402 | width: 13em; 403 | font-size: 85%; 404 | border: 0.5em solid hsl(60, 29%, 94%); 405 | margin: 0 0 0 0; 406 | } 407 | 408 | 409 | /* ---------------------------------------- */ 410 | /* Table of contents, left margin */ 411 | 412 | .tocset { 413 | position: absolute; 414 | float: none; 415 | left: 0; 416 | top: 0rem; 417 | width: 14rem; 418 | padding: 7rem 0.5rem 0.5rem 0.5rem; 419 | background-color: hsl(216, 15%, 70%); 420 | margin: 0; 421 | 422 | } 423 | 424 | .tocset td { 425 | vertical-align: text-top; 426 | padding-bottom: 0.4rem; 427 | padding-left: 0.2rem; 428 | line-height: 1.1; 429 | font-family: 'Fira', sans-serif; 430 | } 431 | 432 | .tocset td a { 433 | color: black; 434 | font-weight: 400; 435 | } 436 | 437 | 438 | .tocview { 439 | text-align: left; 440 | background-color: inherit; 441 | } 442 | 443 | 444 | .tocview td, .tocsub td { 445 | line-height: 1.3; 446 | } 447 | 448 | 449 | .tocview table, .tocsub table { 450 | width: 90%; 451 | } 452 | 453 | .tocset td a.tocviewselflink { 454 | font-weight: lighter; 455 | font-size: 110%; /* monospaced styles below don't need to enlarge */ 456 | color: white; 457 | } 458 | 459 | .tocviewselflink { 460 | text-decoration: none; 461 | } 462 | 463 | .tocsub { 464 | text-align: left; 465 | margin-top: 0.5em; 466 | background-color: inherit; 467 | } 468 | 469 | .tocviewlist, .tocsublist { 470 | margin-left: 0.2em; 471 | margin-right: 0.2em; 472 | padding-top: 0.2em; 473 | padding-bottom: 0.2em; 474 | } 475 | .tocviewlist table { 476 | font-size: 82%; 477 | } 478 | 479 | .tocviewlisttopspace { 480 | margin-bottom: 1em; 481 | } 482 | 483 | .tocviewsublist, .tocviewsublistonly, .tocviewsublisttop, .tocviewsublistbottom { 484 | margin-left: 0.4em; 485 | border-left: 1px solid #99a; 486 | padding-left: 0.8em; 487 | } 488 | .tocviewsublist { 489 | margin-bottom: 1em; 490 | } 491 | .tocviewsublist table, 492 | .tocviewsublistonly table, 493 | .tocviewsublisttop table, 494 | .tocviewsublistbottom table, 495 | table.tocsublist { 496 | font-size: 1rem; 497 | } 498 | 499 | .tocviewsublist td, 500 | .tocviewsublistbottom td, 501 | .tocviewsublisttop td, 502 | .tocsub td, 503 | .tocviewsublistonly td { 504 | font-size: 90%; 505 | } 506 | 507 | /* shrink the monospaced text (`stt`) within nav */ 508 | .tocviewsublist td .stt, 509 | .tocviewsublistbottom td .stt, 510 | .tocviewsublisttop td .stt, 511 | .tocsub td .stt, 512 | .tocviewsublistonly td .stt { 513 | font-size: 95%; 514 | } 515 | 516 | 517 | .tocviewtoggle { 518 | font-size: 75%; /* looks better, and avoids bounce when toggling sub-sections due to font alignments */ 519 | } 520 | 521 | .tocsublist td { 522 | padding-left: 0.5rem; 523 | padding-top: 0.25rem; 524 | text-indent: 0; 525 | } 526 | 527 | .tocsublinknumber { 528 | font-size: 100%; 529 | } 530 | 531 | .tocsublink { 532 | font-size: 82%; 533 | text-decoration: none; 534 | } 535 | 536 | .tocsubseclink { 537 | font-size: 100%; 538 | text-decoration: none; 539 | } 540 | 541 | .tocsubnonseclink { 542 | font-size: 82%; 543 | text-decoration: none; 544 | margin-left: 1rem; 545 | padding-left: 0; 546 | display: inline-block; 547 | } 548 | 549 | /* the label "on this page" */ 550 | .tocsubtitle { 551 | display: block; 552 | font-size: 62%; 553 | font-family: 'Fira', sans-serif; 554 | font-weight: bolder; 555 | font-style: normal; 556 | letter-spacing: 2px; 557 | text-transform: uppercase; 558 | margin: 0.5em; 559 | } 560 | 561 | .toptoclink { 562 | font-weight: bold; 563 | font-size: 110%; 564 | margin-bottom: 0.5rem; 565 | margin-top: 1.5rem; 566 | display: inline-block; 567 | } 568 | 569 | .toclink { 570 | font-size: inherit; 571 | } 572 | 573 | /* ---------------------------------------- */ 574 | /* Some inline styles */ 575 | 576 | .indexlink { 577 | text-decoration: none; 578 | } 579 | 580 | pre { 581 | margin-left: 2em; 582 | } 583 | 584 | blockquote { 585 | margin-left: 2em; 586 | margin-right: 2em; 587 | margin-bottom: 1em; 588 | } 589 | 590 | .SCodeFlow { 591 | border-left: 1px dotted black; 592 | padding-left: 1em; 593 | padding-right: 1em; 594 | margin-top: 1em; 595 | margin-bottom: 1em; 596 | margin-left: 0em; 597 | margin-right: 2em; 598 | white-space: nowrap; 599 | line-height: 1.5; 600 | } 601 | 602 | .SCodeFlow img { 603 | margin-top: 0.5em; 604 | margin-bottom: 0.5em; 605 | } 606 | 607 | /* put a little air between lines of code sample */ 608 | /* Fira Mono appears taller than Source Code Pro */ 609 | .SCodeFlow td { 610 | padding-bottom: 1px; 611 | } 612 | 613 | .boxed { 614 | margin: 0; 615 | margin-top: 2em; 616 | padding: 0.25em; 617 | padding-top: 0.3em; 618 | padding-bottom: 0.4em; 619 | background: #f3f3f3; 620 | box-sizing:border-box; 621 | border-top: 1px solid #99b; 622 | background: hsl(216, 78%, 95%); 623 | background: -moz-linear-gradient(to bottom left, hsl(0, 0%, 99%) 0%, hsl(216, 62%, 95%) 100%); 624 | background: -webkit-linear-gradient(to bottom left, hsl(0, 0%, 99%) 0%, hsl(216, 62%, 95%) 100%); 625 | background: -o-linear-gradient(to bottom left, hsl(0, 0%, 99%) 0%, hsl(216, 62%, 95%) 100%); 626 | background: -ms-linear-gradient(to bottom left, hsl(0, 0%, 99%) 0%, hsl(216, 62%, 95%) 100%); 627 | background: linear-gradient(to bottom left, hsl(0, 0%, 99%) 0%, hsl(216, 62%, 95%) 100%); 628 | } 629 | 630 | blockquote > blockquote.SVInsetFlow { 631 | /* resolves issue in e.g. /reference/notation.html */ 632 | margin-top: 0em; 633 | } 634 | 635 | .leftindent .SVInsetFlow { /* see e.g. section 4.5 of Racket Guide */ 636 | margin-top: 1em; 637 | margin-bottom: 1em; 638 | } 639 | 640 | .SVInsetFlow a, .SCodeFlow a { 641 | color: #07A; 642 | } 643 | 644 | .SubFlow { 645 | display: block; 646 | margin: 0em; 647 | } 648 | 649 | .boxed { 650 | width: 100%; 651 | background-color: inherit; 652 | } 653 | 654 | .techoutside { text-decoration: none; } 655 | 656 | .SAuthorListBox { 657 | position: static; 658 | float: none; 659 | font-family: 'Fira', sans-serif; 660 | font-weight: 300; 661 | font-size: 110%; 662 | margin-top: 1rem; 663 | margin-bottom: 2rem; 664 | width: 30rem; 665 | height: auto; 666 | } 667 | 668 | .author > a { /* email links within author block */ 669 | font-weight: inherit; 670 | color: inherit; 671 | } 672 | 673 | .SAuthorList { 674 | font-size: 82%; 675 | } 676 | .SAuthorList:before { 677 | content: "by "; 678 | } 679 | .author { 680 | display: inline; 681 | white-space: nowrap; 682 | } 683 | 684 | /* phone + tablet styles */ 685 | 686 | @media all and (max-width:720px){ 687 | 688 | 689 | @media all and (max-width:720px){ 690 | 691 | @media all {html {font-size: 15px;}} 692 | @media all and (max-width:700px){html {font-size: 14px;}} 693 | @media all and (max-width:630px){html {font-size: 13px;}} 694 | @media all and (max-width:610px){html {font-size: 12px;}} 695 | @media all and (max-width:550px){html {font-size: 11px;}} 696 | @media all and (max-width:520px){html {font-size: 10px;}} 697 | 698 | .navsettop, .navsetbottom { 699 | display: block; 700 | position: absolute; 701 | width: 100%; 702 | height: 4rem; 703 | border: 0; 704 | background-color: hsl(216, 15%, 70%); 705 | } 706 | 707 | .searchform { 708 | display: inline; 709 | border: 0; 710 | } 711 | 712 | .navright { 713 | position: absolute; 714 | right: 1.5rem; 715 | margin-top: 1rem; 716 | border: 0px solid red; 717 | } 718 | 719 | .navsetbottom { 720 | display: block; 721 | margin-top: 8rem; 722 | } 723 | 724 | .tocset { 725 | display: none; 726 | } 727 | 728 | .tocset table, .tocset tbody, .tocset tr, .tocset td { 729 | display: inline; 730 | } 731 | 732 | .tocview { 733 | display: none; 734 | } 735 | 736 | .tocsub .tocsubtitle { 737 | display: none; 738 | } 739 | 740 | .versionbox { 741 | top: 4.5rem; 742 | left: 1rem; /* same distance as main-column */ 743 | z-index: 11000; 744 | height: 2em; 745 | font-size: 70%; 746 | font-weight: lighter; 747 | } 748 | 749 | 750 | .maincolumn { 751 | margin-left: 1em; 752 | margin-top: 7rem; 753 | margin-bottom: 0rem; 754 | } 755 | 756 | } 757 | 758 | } 759 | 760 | /* print styles : hide the navigation elements */ 761 | @media print { 762 | .tocset, 763 | .navsettop, 764 | .navsetbottom { display: none; } 765 | .maincolumn { 766 | width: auto; 767 | margin-right: 13em; 768 | margin-left: 0; 769 | } 770 | } 771 | -------------------------------------------------------------------------------- /docs/racket.css: -------------------------------------------------------------------------------- 1 | 2 | /* See the beginning of "scribble.css". */ 3 | 4 | /* Monospace: */ 5 | .RktIn, .RktRdr, .RktPn, .RktMeta, 6 | .RktMod, .RktKw, .RktVar, .RktSym, 7 | .RktRes, .RktOut, .RktCmt, .RktVal, 8 | .RktBlk { 9 | font-family: monospace; 10 | white-space: inherit; 11 | } 12 | 13 | /* Serif: */ 14 | .inheritedlbl { 15 | font-family: serif; 16 | } 17 | 18 | /* Sans-serif: */ 19 | .RBackgroundLabelInner { 20 | font-family: sans-serif; 21 | } 22 | 23 | /* ---------------------------------------- */ 24 | /* Inherited methods, left margin */ 25 | 26 | .inherited { 27 | width: 100%; 28 | margin-top: 0.5em; 29 | text-align: left; 30 | background-color: #ECF5F5; 31 | } 32 | 33 | .inherited td { 34 | font-size: 82%; 35 | padding-left: 1em; 36 | text-indent: -0.8em; 37 | padding-right: 0.2em; 38 | } 39 | 40 | .inheritedlbl { 41 | font-style: italic; 42 | } 43 | 44 | /* ---------------------------------------- */ 45 | /* Racket text styles */ 46 | 47 | .RktIn { 48 | color: #cc6633; 49 | background-color: #eeeeee; 50 | } 51 | 52 | .RktInBG { 53 | background-color: #eeeeee; 54 | } 55 | 56 | .RktRdr { 57 | } 58 | 59 | .RktPn { 60 | color: #843c24; 61 | } 62 | 63 | .RktMeta { 64 | color: black; 65 | } 66 | 67 | .RktMod { 68 | color: black; 69 | } 70 | 71 | .RktOpt { 72 | color: black; 73 | } 74 | 75 | .RktKw { 76 | color: black; 77 | } 78 | 79 | .RktErr { 80 | color: red; 81 | font-style: italic; 82 | } 83 | 84 | .RktVar { 85 | color: #262680; 86 | font-style: italic; 87 | } 88 | 89 | .RktSym { 90 | color: #262680; 91 | } 92 | 93 | .RktSymDef { /* used with RktSym at def site */ 94 | } 95 | 96 | .RktValLink { 97 | text-decoration: none; 98 | color: blue; 99 | } 100 | 101 | .RktValDef { /* used with RktValLink at def site */ 102 | } 103 | 104 | .RktModLink { 105 | text-decoration: none; 106 | color: blue; 107 | } 108 | 109 | .RktStxLink { 110 | text-decoration: none; 111 | color: black; 112 | } 113 | 114 | .RktStxDef { /* used with RktStxLink at def site */ 115 | } 116 | 117 | .RktRes { 118 | color: #0000af; 119 | } 120 | 121 | .RktOut { 122 | color: #960096; 123 | } 124 | 125 | .RktCmt { 126 | color: #c2741f; 127 | } 128 | 129 | .RktVal { 130 | color: #228b22; 131 | } 132 | 133 | /* ---------------------------------------- */ 134 | /* Some inline styles */ 135 | 136 | .together { 137 | width: 100%; 138 | } 139 | 140 | .prototype, .argcontract, .RBoxed { 141 | white-space: nowrap; 142 | } 143 | 144 | .prototype td { 145 | vertical-align: text-top; 146 | } 147 | 148 | .RktBlk { 149 | white-space: inherit; 150 | text-align: left; 151 | } 152 | 153 | .RktBlk tr { 154 | white-space: inherit; 155 | } 156 | 157 | .RktBlk td { 158 | vertical-align: baseline; 159 | white-space: inherit; 160 | } 161 | 162 | .argcontract td { 163 | vertical-align: text-top; 164 | } 165 | 166 | .highlighted { 167 | background-color: #ddddff; 168 | } 169 | 170 | .defmodule { 171 | width: 100%; 172 | background-color: #F5F5DC; 173 | } 174 | 175 | .specgrammar { 176 | float: right; 177 | } 178 | 179 | .RBibliography td { 180 | vertical-align: text-top; 181 | } 182 | 183 | .leftindent { 184 | margin-left: 1em; 185 | margin-right: 0em; 186 | } 187 | 188 | .insetpara { 189 | margin-left: 1em; 190 | margin-right: 1em; 191 | } 192 | 193 | .Rfilebox { 194 | } 195 | 196 | .Rfiletitle { 197 | text-align: right; 198 | margin: 0em 0em 0em 0em; 199 | } 200 | 201 | .Rfilename { 202 | border-top: 1px solid #6C8585; 203 | border-right: 1px solid #6C8585; 204 | padding-left: 0.5em; 205 | padding-right: 0.5em; 206 | background-color: #ECF5F5; 207 | } 208 | 209 | .Rfilecontent { 210 | margin: 0em 0em 0em 0em; 211 | } 212 | 213 | .RpackageSpec { 214 | padding-right: 0.5em; 215 | } 216 | 217 | /* ---------------------------------------- */ 218 | /* For background labels */ 219 | 220 | .RBackgroundLabel { 221 | float: right; 222 | width: 0px; 223 | height: 0px; 224 | } 225 | 226 | .RBackgroundLabelInner { 227 | position: relative; 228 | width: 25em; 229 | left: -25.5em; 230 | top: 0px; 231 | text-align: right; 232 | color: white; 233 | z-index: 0; 234 | font-weight: bold; 235 | } 236 | 237 | .RForeground { 238 | position: relative; 239 | left: 0px; 240 | top: 0px; 241 | z-index: 1; 242 | } 243 | 244 | /* ---------------------------------------- */ 245 | /* History */ 246 | 247 | .SHistory { 248 | font-size: 82%; 249 | } 250 | -------------------------------------------------------------------------------- /docs/scribble-common.js: -------------------------------------------------------------------------------- 1 | // Common functionality for PLT documentation pages 2 | 3 | // Page Parameters ------------------------------------------------------------ 4 | 5 | var page_query_string = location.search.substring(1); 6 | 7 | var page_args = 8 | ((function(){ 9 | if (!page_query_string) return []; 10 | var args = page_query_string.split(/[&;]/); 11 | for (var i=0; i= 0) args[i] = [a.substring(0,p), a.substring(p+1)]; 15 | else args[i] = [a, false]; 16 | } 17 | return args; 18 | })()); 19 | 20 | function GetPageArg(key, def) { 21 | for (var i=0; i= 0 && cur.substring(0,eql) == key) 78 | return unescape(cur.substring(eql+1)); 79 | } 80 | return def; 81 | } 82 | } 83 | 84 | function SetCookie(key, val) { 85 | try { 86 | localStorage[key] = val; 87 | } catch(e) { 88 | var d = new Date(); 89 | d.setTime(d.getTime()+(365*24*60*60*1000)); 90 | try { 91 | document.cookie = 92 | key + "=" + escape(val) + "; expires="+ d.toGMTString() + "; path=/"; 93 | } catch (e) {} 94 | } 95 | } 96 | 97 | // note that this always stores a directory name, ending with a "/" 98 | function SetPLTRoot(ver, relative) { 99 | var root = location.protocol + "//" + location.host 100 | + NormalizePath(location.pathname.replace(/[^\/]*$/, relative)); 101 | SetCookie("PLT_Root."+ver, root); 102 | } 103 | 104 | // adding index.html works because of the above 105 | function GotoPLTRoot(ver, relative) { 106 | var u = GetCookie("PLT_Root."+ver, null); 107 | if (u == null) return true; // no cookie: use plain up link 108 | // the relative path is optional, default goes to the toplevel start page 109 | if (!relative) relative = "index.html"; 110 | location = u + relative; 111 | return false; 112 | } 113 | 114 | // Utilities ------------------------------------------------------------------ 115 | 116 | var normalize_rxs = [/\/\/+/g, /\/\.(\/|$)/, /\/[^\/]*\/\.\.(\/|$)/]; 117 | function NormalizePath(path) { 118 | var tmp, i; 119 | for (i = 0; i < normalize_rxs.length; i++) 120 | while ((tmp = path.replace(normalize_rxs[i], "/")) != path) path = tmp; 121 | return path; 122 | } 123 | 124 | // `noscript' is problematic in some browsers (always renders as a 125 | // block), use this hack instead (does not always work!) 126 | // document.write(""); 127 | 128 | // Interactions --------------------------------------------------------------- 129 | 130 | function DoSearchKey(event, field, ver, top_path) { 131 | var val = field.value; 132 | if (event && event.keyCode == 13) { 133 | var u = GetCookie("PLT_Root."+ver, null); 134 | if (u == null) u = top_path; // default: go to the top path 135 | u += "search/index.html?q=" + encodeURIComponent(val); 136 | u = MergePageArgsIntoUrl(u); 137 | location = u; 138 | return false; 139 | } 140 | return true; 141 | } 142 | 143 | function TocviewToggle(glyph, id) { 144 | var s = document.getElementById(id).style; 145 | var expand = s.display == "none"; 146 | s.display = expand ? "block" : "none"; 147 | glyph.innerHTML = expand ? "▼" : "►"; 148 | } 149 | 150 | // Page Init ------------------------------------------------------------------ 151 | 152 | // Note: could make a function that inspects and uses window.onload to chain to 153 | // a previous one, but this file needs to be required first anyway, since it 154 | // contains utilities for all other files. 155 | var on_load_funcs = []; 156 | function AddOnLoad(fun) { on_load_funcs.push(fun); } 157 | window.onload = function() { 158 | for (var i=0; i 415 | .techinside doesn't work with IE, so use both (and IE doesn't 416 | work with inherit in the second one, so use blue directly) */ 417 | .techinside { color: black; } 418 | .techinside:hover { color: blue; } 419 | .techoutside:hover>.techinside { color: inherit; } 420 | 421 | .SCentered { 422 | text-align: center; 423 | } 424 | 425 | .imageleft { 426 | float: left; 427 | margin-right: 0.3em; 428 | } 429 | 430 | .Smaller { 431 | font-size: 82%; 432 | } 433 | 434 | .Larger { 435 | font-size: 122%; 436 | } 437 | 438 | /* A hack, inserted to break some Scheme ids: */ 439 | .mywbr { 440 | display: inline-block; 441 | height: 0; 442 | width: 0; 443 | font-size: 1px; 444 | } 445 | 446 | .compact li p { 447 | margin: 0em; 448 | padding: 0em; 449 | } 450 | 451 | .noborder img { 452 | border: 0; 453 | } 454 | 455 | .SVerbatim { 456 | white-space: nowrap; 457 | } 458 | 459 | .SAuthorListBox { 460 | position: relative; 461 | float: right; 462 | left: 2em; 463 | top: -2.5em; 464 | height: 0em; 465 | width: 13em; 466 | margin: 0em -13em 0em 0em; 467 | } 468 | .SAuthorList { 469 | font-size: 82%; 470 | } 471 | .SAuthorList:before { 472 | content: "by "; 473 | } 474 | .author { 475 | display: inline; 476 | white-space: nowrap; 477 | } 478 | 479 | /* print styles : hide the navigation elements */ 480 | @media print { 481 | .tocset, 482 | .navsettop, 483 | .navsetbottom { display: none; } 484 | .maincolumn { 485 | width: auto; 486 | margin-right: 13em; 487 | margin-left: 0; 488 | } 489 | } 490 | -------------------------------------------------------------------------------- /info.rkt: -------------------------------------------------------------------------------- 1 | #lang info 2 | (define collection "web-view") 3 | (define deps '("gui-lib" 4 | "base")) 5 | (define build-deps '("at-exp-lib" 6 | "gui-doc" 7 | "scribble-lib" "racket-doc" "rackunit-lib")) 8 | (define scribblings '(("scribblings/web-view.scrbl" ()))) 9 | (define pkg-desc "A web-view control to be used with Racket GUI toolkit applications") 10 | (define version "0.1") 11 | (define pkg-authors '(agarzia)) 12 | -------------------------------------------------------------------------------- /main.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | (module+ test 4 | (require rackunit)) 5 | 6 | ;; Notice 7 | ;; To install (from within the package directory): 8 | ;; $ raco pkg install 9 | ;; To install (once uploaded to pkgs.racket-lang.org): 10 | ;; $ raco pkg install <> 11 | ;; To uninstall: 12 | ;; $ raco pkg remove <> 13 | ;; To view documentation: 14 | ;; $ raco docs <> 15 | ;; 16 | ;; For your convenience, we have included LICENSE-MIT and LICENSE-APACHE files. 17 | ;; If you would prefer to use a different license, replace those files with the 18 | ;; desired license. 19 | ;; 20 | ;; Some users like to add a `private/` directory, place auxiliary files there, 21 | ;; and require them in `main.rkt`. 22 | ;; 23 | ;; See the current version of the racket style guide here: 24 | ;; http://docs.racket-lang.org/style/index.html 25 | 26 | ;; Code here 27 | 28 | (require "private/web-view.rkt") 29 | 30 | (provide web-view%) 31 | 32 | 33 | (module+ test 34 | ;; Any code in this `test` submodule runs when this file is run using DrRacket 35 | ;; or with `raco test`. The code here does not run when this file is 36 | ;; required by another module. 37 | 38 | ) 39 | 40 | (module+ main 41 | ;; (Optional) main submodule. Put code here if you need it to be executed when 42 | ;; this file is run using DrRacket or the `racket` executable. The code here 43 | ;; does not run when this file is required by another module. Documentation: 44 | ;; http://docs.racket-lang.org/guide/Module_Syntax.html#%28part._main-and-test%29 45 | 46 | ) 47 | -------------------------------------------------------------------------------- /private/web-view.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require 4 | racket/class 5 | racket/gui 6 | "webkit.rkt" 7 | "wkwebview.rkt") 8 | 9 | (define web-view% 10 | (class panel% 11 | (init parent [on-status-change #f]) 12 | 13 | (super-new [parent parent]) 14 | 15 | (define current-operating-system (system-type 'os)) 16 | 17 | (if (not (member current-operating-system (list 'macosx))) 18 | (error 'not-implemented "web-view% not implemented for ~a" current-operating-system) 19 | #t) 20 | 21 | (define webview 22 | (new wk-web-view% 23 | [parent this] 24 | [on-status-change on-status-change])) 25 | 26 | (define/public (get-debug-info) 27 | current-operating-system) 28 | 29 | (define/public (set-url url) 30 | (send webview set-url url)) 31 | 32 | (define/override (on-size w h) 33 | (send webview on-size w h)) 34 | 35 | (define/public (get-url) 36 | (send webview get-url)) 37 | 38 | (define/public (can-handle-url? url) 39 | (send webview can-handle-url? url)) 40 | 41 | (define/public (go-forward) 42 | (send webview go-forward)) 43 | 44 | (define/public (go-back) 45 | (send webview go-back)) 46 | 47 | (define/public (reload) 48 | (send webview reload)) 49 | 50 | (define/public (set-html-text text base-url) 51 | (send webview set-html-text text base-url)) 52 | 53 | )) 54 | 55 | (provide web-view%) -------------------------------------------------------------------------------- /private/webkit.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/gui 2 | 3 | ; This was my initial version. It is based on deprecated WebView from code found on: 4 | ; https://gist.github.com/nickmain/5136923 5 | ; 6 | ; I've switched to WKWebView. Check wkwebkit.rkt 7 | 8 | (require framework) 9 | (require ffi/unsafe) 10 | (require ffi/unsafe/objc) 11 | (require racket/class) 12 | 13 | (ffi-lib "/System/Library/Frameworks/WebKit.framework/WebKit") 14 | (import-class WebView) 15 | (import-class NSURLRequest) 16 | (import-class NSURL) 17 | (import-class NSString) 18 | (import-class NSObject) 19 | 20 | 21 | (define webkit-view% 22 | (class object% 23 | (super-new) 24 | 25 | (init parent) 26 | 27 | (define current-url #f) 28 | 29 | (define-objc-class MyWebFrameLoadDelegate NSObject 30 | [] 31 | (- _void (webView: [_id wv] didFinishLoadForFrame: [_id wf]) 32 | (print "page loaded"))) 33 | 34 | (define-cstruct _NSPoint ([x _double*] 35 | [y _double*])) 36 | 37 | (define-cstruct _NSSize ([width _double*] 38 | [height _double*])) 39 | 40 | (define-cstruct _NSRect ([origin _NSPoint] 41 | [size _NSSize])) 42 | 43 | 44 | (define webview-x (send parent get-x)) 45 | (define webview-y (send parent get-y)) 46 | (define webview-width (send parent get-width)) 47 | (define webview-height (send parent get-height)) 48 | 49 | ;(print (format "creating webkit-view x:~a, y:~a, height:~a, width:~a ~%" webview-x webview-y webview-height webview-width)) 50 | 51 | (define webview 52 | (tell (tell WebView alloc) 53 | initWithFrame: #:type _NSRect (make-NSRect (make-NSPoint webview-x webview-y) (make-NSSize webview-width webview-height)) 54 | frameName: #f 55 | groupName: #f)) 56 | 57 | (define client-view (send parent get-client-handle)) 58 | (tell client-view addSubview: webview) 59 | 60 | (define (release id-ptr) (tell id-ptr release)) 61 | 62 | (define main-frame 63 | (tell webview mainFrame)) 64 | 65 | (define delegate 66 | (tell (tell MyWebFrameLoadDelegate alloc) init)) 67 | 68 | (tell webview setFrameLoadDelegate: delegate) 69 | 70 | (define/public (get-url) 71 | current-url) 72 | 73 | (define/public (set-url given-url) 74 | (set! current-url given-url) 75 | (let* ([url-string (tell (tell NSString alloc) 76 | initWithUTF8String: #:type _string given-url)] 77 | [url (tell NSURL URLWithString: url-string)] 78 | [req (tell NSURLRequest requestWithURL: url)]) 79 | (tell main-frame loadRequest: req) 80 | (release url-string))) 81 | 82 | (define/public (on-status-change status) 83 | (displayln (format "webkit-view status change: ~a" status))) 84 | 85 | )) 86 | 87 | (provide webkit-view%) -------------------------------------------------------------------------------- /private/wkwebview.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/gui 2 | (require framework) 3 | (require ffi/unsafe) 4 | (require ffi/unsafe/objc) 5 | (require ffi/unsafe/nsstring) 6 | (require racket/class) 7 | 8 | (ffi-lib "/System/Library/Frameworks/WebKit.framework/WebKit") 9 | (import-class WKWebView) 10 | (import-class WKWebViewConfiguration) 11 | (import-class NSURLRequest) 12 | (import-class NSURL) 13 | (import-class NSView) 14 | (import-class NSString) 15 | (import-class NSObject) 16 | (import-protocol WKNavigationDelegate) 17 | 18 | 19 | (define wk-web-view% 20 | (class object% 21 | (super-new) 22 | 23 | (init parent [on-status-change #f]) 24 | 25 | (define-cstruct _NSPoint ([x _double*] 26 | [y _double*])) 27 | 28 | (define-cstruct _NSSize ([width _double*] 29 | [height _double*])) 30 | 31 | (define-cstruct _CGRect ([origin _NSPoint] 32 | [size _NSSize])) 33 | 34 | (define webview-x (send parent get-x)) 35 | 36 | (define webview-y (send parent get-y)) 37 | 38 | (define webview-width (send parent get-width)) 39 | 40 | (define webview-height (send parent get-height)) 41 | 42 | (define configuration 43 | (tell (tell WKWebViewConfiguration alloc) init)) 44 | 45 | (define (release id-ptr) (tell id-ptr release)) 46 | 47 | (define (make-rect) 48 | (make-CGRect (make-NSPoint webview-x webview-y) (make-NSSize webview-width webview-height))) 49 | 50 | (define webview 51 | (tell (tell WKWebView alloc) 52 | initWithFrame: #:type _CGRect (make-rect) 53 | configuration: configuration)) 54 | 55 | (define-objc-class WebViewDelegate NSObject 56 | #:protocols (WKNavigationDelegate) 57 | [] 58 | (- _void (webView: [_id view] didCommitNavigation: [_id navigation]) 59 | (if (not (false? on-status-change)) (on-status-change "loading...") #f)) 60 | (- _void (webView: [_id view] didFinishNavigation: [_id navigation]) 61 | (if (not (false? on-status-change)) (on-status-change "page loaded" ) #f))) 62 | 63 | (define delegate 64 | (tell (tell WebViewDelegate alloc) init)) 65 | 66 | (tell (send parent get-client-handle) addSubview: webview) 67 | 68 | (tellv webview setNavigationDelegate: delegate) 69 | 70 | (define/public (get-title) 71 | (tell #:type _NSString webview title)) 72 | 73 | (define/public (get-url) 74 | (define url 75 | (tell webview URL)) 76 | (tell #:type _NSString url absoluteString)) 77 | 78 | (define/public (set-url given-url) 79 | (let* ([url-string (tell (tell NSString alloc) 80 | initWithUTF8String: #:type _string given-url)] 81 | [url (tell NSURL URLWithString: url-string)] 82 | [req (tell NSURLRequest requestWithURL: url)]) 83 | (tell webview loadRequest: req) 84 | (release url-string))) 85 | 86 | (define/public (can-handle-url? given-url) 87 | (let* ([url-string (tell (tell NSString alloc) 88 | initWithUTF8String: #:type _string given-url)]) 89 | (define ret (tell webview handlesURLScheme: url-string )) 90 | (release url-string) 91 | ret)) 92 | 93 | (define/public (go-forward) 94 | (tell webview goForward)) 95 | 96 | (define/public (go-back) 97 | (tell webview goBack)) 98 | 99 | (define/public (reload) 100 | (tell webview reload)) 101 | 102 | (define/public (set-html-text text base-url) 103 | (let* ([url-string (tell (tell NSString alloc) 104 | initWithUTF8String: #:type _string base-url)] 105 | [url (tell NSURL URLWithString: url-string)] 106 | [html (tell (tell NSString alloc) 107 | initWithUTF8String: #:type _string text)]) 108 | (tell webview loadHTMLString: html baseURL: url))) 109 | 110 | (define/public (on-size w h) 111 | (tellv webview setFrame: 112 | #:type _CGRect (make-CGRect (make-NSPoint 0 0) 113 | (make-NSSize w h)))) 114 | 115 | )) 116 | 117 | (provide wk-web-view%) -------------------------------------------------------------------------------- /scribblings/web-view.scrbl: -------------------------------------------------------------------------------- 1 | #lang scribble/manual 2 | @require[@for-label[web-view 3 | racket/class 4 | racket/base 5 | racket/gui]] 6 | 7 | @title{A Racket GUI widget to display web pages} 8 | @author{Andre Alves Garzia} 9 | 10 | @defmodule[web-view] 11 | 12 | This module contains a Web View to be used with Racket GUI Toolkit. At the moment it works only with macOS because it wraps @hyperlink["https://developer.apple.com/documentation/webkit/wkwebview?language=objc"]{WKWebView} from WebKit. 13 | 14 | There is a @hyperlink["https://github.com/soapdog/racket-web-view/blob/master/demo/demo.rkt"]{Demo Browser available on the Github Repository}. 15 | 16 | @defclass[web-view% object% ()]{ 17 | 18 | A widget to display web pages. 19 | 20 | @defconstructor[([parent (or/c (is-a?/c frame%) 21 | (is-a?/c dialog%) 22 | (is-a?/c panel%) 23 | (is-a?/c pane%))] 24 | [on-status-change ((is-a?/c button%) (is-a?/c control-event%) . -> . any) (lambda (b e) (void))])]{ 25 | 26 | Construct a new widget. 27 | 28 | The @racket[on-status-change] procedure is used to receive navigation events from the web view. 29 | 30 | } 31 | 32 | @defmethod*[([(set-url [url string?]) any/c])]{ 33 | 34 | Set the URL for the web view. 35 | 36 | } 37 | 38 | @defmethod*[([(get-url) string?])]{ 39 | 40 | Get the current URL loaded in the web view. 41 | 42 | } 43 | 44 | 45 | @defmethod*[([(go-forward) any/c])]{ 46 | 47 | Navigates forward. 48 | 49 | } 50 | 51 | 52 | @defmethod*[([(go-back) any/c])]{ 53 | 54 | Navigates backward. 55 | 56 | } 57 | 58 | 59 | @defmethod*[([(reload) any/c])]{ 60 | 61 | Reloads the current page. 62 | 63 | } 64 | 65 | @defmethod*[([(set-html-text [text string?] [base-url string?]) any/c])]{ 66 | 67 | Sets the HTML text being used by the web view. Any relative url will be relative to the specified base url. 68 | 69 | } 70 | 71 | } 72 | --------------------------------------------------------------------------------