├── .gitignore ├── LICENSE ├── README.md ├── anderson-cv.Rmd ├── anderson-cv.Rproj ├── anderson-cv.css ├── anderson-cv.html ├── anderson-cv.pdf ├── anderson-cv_files ├── accessible-code-block-0.0.1 │ └── empty-anchor.js ├── header-attrs-2.11 │ └── header-attrs.js ├── header-attrs-2.4 │ └── header-attrs.js ├── header-attrs-2.6 │ └── header-attrs.js ├── header-attrs-2.7.4 │ └── header-attrs.js ├── header-attrs-2.7 │ └── header-attrs.js ├── paged-0.12 │ └── js │ │ ├── config.js │ │ ├── hooks.js │ │ └── paged.js ├── paged-0.13 │ └── js │ │ ├── config.js │ │ ├── hooks.js │ │ └── paged.js ├── paged-0.14 │ └── js │ │ ├── config.js │ │ ├── hooks.js │ │ └── paged.js ├── paged-0.15 │ └── js │ │ ├── config.js │ │ ├── hooks.js │ │ └── paged.js ├── paged-0.19 │ └── js │ │ ├── config.js │ │ ├── hooks.js │ │ └── paged.js ├── paged-0.5 │ └── js │ │ ├── config.js │ │ ├── hooks.js │ │ └── paged.js └── paged-0.7.1 │ └── js │ ├── config.js │ ├── hooks.js │ └── paged.js ├── content ├── contact-info.Rmd └── summary.Rmd ├── data ├── courses.xlsx ├── cv_entries.numbers ├── cv_entries.xlsx ├── grants.xlsx ├── in-progress.xlsx ├── pubs.numbers └── pubs.xlsx └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .Rapp.history 3 | .Rproj.user/* 4 | data/~* 5 | .Rproj.user 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Daniel Anderson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # My CV 2 | This is a repo for my CV, which uses a data-driven approach. In other words, entries are stored as data, which are then read into R and can be rendered in various ways. The entire CV is built with a combination of [pagedown](https://github.com/rstudio/pagedown) with custom HTML and CSS. Basically, this allows PDFs to be generated using HTML and CSS code, as opposed something like LaTeX. 3 | 4 | Please feel free to fork/modify as much as you'd like, and get in touch if you have any questions. 5 | -------------------------------------------------------------------------------- /anderson-cv.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | -------------------------------------------------------------------------------- /anderson-cv.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Roboto:100,300,500,900|Roboto+Slab&display=swap'); 2 | @import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.css"); 3 | 4 | @page { 5 | @bottom-center { 6 | content: element(footer); 7 | } 8 | @bottom-right { 9 | content: counter(page); 10 | } 11 | @bottom-left { 12 | content: element(date); 13 | } 14 | } 15 | @page:first { 16 | @top-right { 17 | content: element(download); 18 | } 19 | @bottom-center { 20 | content: none; 21 | } 22 | @bottom-right { 23 | content: none; 24 | } 25 | @bottom-left { 26 | content: none; 27 | } 28 | } 29 | 30 | .pagedjs_margin.pagedjs_margin-bottom-right.hasContent 31 | .pagedjs_margin.pagedjs_margin-bottom-center.hasContent 32 | .pagedjs_margin.pagedjs_margin-bottom-left.hasContent { 33 | align-items: baseline; 34 | } 35 | 36 | div.footer { 37 | position: running(footer); 38 | } 39 | 40 | div.download { 41 | position: running(download); 42 | } 43 | 44 | h2.date { 45 | position: running(date); 46 | font-size: 0.8em; 47 | color: #454545; 48 | border-bottom: none; 49 | } 50 | 51 | .fafooter { 52 | color: gray; 53 | text-align: right; 54 | padding-left: 5px; 55 | padding-right: 5px; 56 | } 57 | 58 | .fafooter:hover { 59 | color: #FF95FD; 60 | } 61 | 62 | .title { 63 | display: none; 64 | } 65 | 66 | .date { 67 | display: none; 68 | } 69 | 70 | @page{ 71 | size: A4 portrait; 72 | } 73 | 74 | body { 75 | font-family: 'Roboto', sans-serif; 76 | font-weight: 300; 77 | } 78 | 79 | :root{ 80 | --page-width: 8.5in; 81 | --pagedjs-margin-right: 0.7in; 82 | --pagedjs-margin-left: 0.7in; 83 | --pagedjs-margin-top: 0.7in; 84 | --pagedjs-margin-bottom: 0.7in; 85 | --root-font-size: 12pt; 86 | --viewer-pages-spacing: 12px; 87 | --viewer-shadow-color: #313131; /* this marks the pages */ 88 | } 89 | 90 | /* Paged.js viewer */ 91 | @media screen { 92 | body { 93 | background-color: var(--viewer-background-color); 94 | margin: 0; /* for mobile */ 95 | width: calc(var(--pagedjs-width) + 2 * var(--viewer-pages-spacing)); /* for mobile */ 96 | } 97 | .pagedjs_pages { 98 | max-width: var(--pagedjs-width); 99 | margin: 0 auto; 100 | display: flex; 101 | flex-direction: column; 102 | } 103 | .pagedjs_page { 104 | box-shadow: 0 0 calc(0.66667 * var(--viewer-pages-spacing)) var(--viewer-shadow-color); 105 | margin: var(--viewer-pages-spacing) 0; 106 | } 107 | } 108 | @media screen and (min-width: 8.5in) { 109 | /* not a mobile */ 110 | body { 111 | margin: auto; 112 | width: unset; 113 | } 114 | } 115 | 116 | .blocks { 117 | break-inside: avoid; 118 | } 119 | 120 | /* create ability to insert pagebreaks with br.pagebreak */ 121 | br.pageBreak { 122 | page-break-after: always; 123 | } 124 | 125 | br.flow-top { 126 | display: block; 127 | content: ""; 128 | margin-top: 1px; 129 | } 130 | 131 | .info-box a { 132 | color: black; 133 | text-decoration: none; 134 | } 135 | 136 | p, li { 137 | font-size: var(--root-font-size); 138 | line-height: 125%; 139 | } 140 | 141 | 142 | /* title */ 143 | #block_container { 144 | text-align:center; 145 | margin-bottom: 0px; 146 | } 147 | #bloc1, #bloc2 { 148 | display:inline; 149 | } 150 | 151 | .first { 152 | color: gray; 153 | text-align: center; 154 | font-size: 32pt; 155 | line-height: 110%; 156 | } 157 | .last { 158 | text-align: center; 159 | font-weight: 900; 160 | font-size: 32pt; 161 | line-height: 110%; 162 | } 163 | .position { 164 | text-align: center; 165 | color: #000; 166 | } 167 | .sub { 168 | font-family: 'Roboto Slab', serif; 169 | color: #454545; 170 | background-color: #DEF2FF; 171 | padding-top: 10px; 172 | margin-top: 15px; 173 | padding-bottom: 10px; 174 | margin-bottom: 15px; 175 | text-align: center; 176 | font-weight: normal; 177 | font-size: 1.2em; 178 | } 179 | 180 | .extratrain td { 181 | padding-top: 3px; 182 | padding-bottom: 3px; 183 | } 184 | 185 | .inote { 186 | text-align: center; 187 | margin-top: -15px; 188 | font-weight: 100; 189 | font-style: italic; 190 | margin-bottom: 0px; 191 | color: #5F6A6A; 192 | } 193 | 194 | .tch td { 195 | padding-top: 3px; 196 | padding-bottom: 3px; 197 | } 198 | 199 | .hangingindent td { 200 | padding-left: 24px ; 201 | text-indent: -24px ; 202 | } 203 | 204 | h1 { 205 | font-family: 'Roboto Slab', serif; 206 | text-align: center; 207 | color: #5F6A6A; 208 | font-size: 1.6em; 209 | font-weight: normal; 210 | margin-bottom: 0px; 211 | /*border-bottom: 2px solid #486CAC;*/ 212 | } 213 | 214 | /* section headers */ 215 | h2 { 216 | color: #649FD3; 217 | border-bottom: 2px solid darkgray; 218 | margin-top: 0.6em; 219 | margin-bottom: 0.3em; 220 | font-size: 1.5em; 221 | font-weight: 300; 222 | } 223 | 224 | /* PAGE 1 */ 225 | h2.summary, 226 | h2.box { 227 | margin-top: -1.8em; 228 | margin-bottom: 0; 229 | } 230 | 231 | .box { 232 | visibility: hidden; 233 | margin-bottom: 0; 234 | } 235 | .info-box { 236 | border-left: 2px solid darkgray; 237 | padding: 10px; 238 | padding-left: 20px; 239 | margin: 10px; 240 | margin-left: -10px; 241 | } 242 | .info-box thead { 243 | display: none; 244 | } 245 | .info-box td:first-child{ 246 | width: 100%; 247 | /*text-align: right; */ 248 | } 249 | 250 | /* if you use links to footnotes*/ 251 | .footnote-ref sup { 252 | vertical-align: top; 253 | margin-left: 1px; 254 | } 255 | 256 | a { 257 | text-decoration: none; 258 | color: #649FD3; 259 | } 260 | 261 | a:hover { 262 | color: #FF95FD; 263 | } 264 | 265 | .falink { 266 | color: #8C9196; 267 | text-align: right; 268 | padding-left: 5px; 269 | } 270 | 271 | .falink:hover { 272 | color: #FF95FD; 273 | } 274 | 275 | .falink2 { 276 | color: #8C9196; 277 | text-align: right; 278 | padding-left: 15px; 279 | } 280 | 281 | .falink2:hover { 282 | color: #FF95FD; 283 | } 284 | 285 | .falink3 { 286 | color: #8C9196; 287 | text-align: right; 288 | padding-left: 20px; 289 | } 290 | 291 | .falink3:hover { 292 | color: #FF95FD; 293 | } 294 | 295 | .grid-container { 296 | display: grid; 297 | grid-template-columns: 49% 49%; 298 | grid-column-gap: 3%; 299 | margin-bottom: -20px; 300 | padding-bottom: -20px; 301 | } 302 | 303 | /* remove header in select table */ 304 | .nohead thead{ 305 | display: none; 306 | } 307 | /* set the width of the first column in the tables */ 308 | 309 | .prpa td { 310 | padding-top: 5px; 311 | padding-bottom: 5px; 312 | } 313 | .prpa td:nth-child(1) { 314 | width: 10%; 315 | text-align:left; 316 | } 317 | 318 | .prpa td:nth-child(2) { 319 | width: 4%; 320 | text-align:left; 321 | } 322 | 323 | .prpa td:nth-child(3) { 324 | text-align:left; 325 | } 326 | 327 | .submitted td { 328 | padding-top: 5px; 329 | padding-bottom: 5px; 330 | } 331 | .submitted td:nth-child(1) { 332 | width: 4%; 333 | text-align:left; 334 | } 335 | 336 | .education { 337 | margin-top: 20px; 338 | } 339 | .education td:first-child { 340 | margin-top: 10px; 341 | padding-top: 0px; 342 | width: 18%; 343 | } 344 | 345 | .history td:first-child { 346 | width: 18%; 347 | } 348 | 349 | .set-width td:first-child { 350 | width: 16%; 351 | text-align: left; 352 | } 353 | 354 | .service td:first-child { 355 | width: 16.5%; 356 | } 357 | 358 | .cv-table td:first-child { 359 | width: 16%; 360 | } 361 | 362 | .publications td, 363 | .talks td { 364 | vertical-align: top; 365 | font-size: 0.9em; 366 | text-align: left; 367 | } 368 | 369 | /* don't make page breaks inside an entry */ 370 | tr { 371 | break-inside: avoid; 372 | } 373 | 374 | .vertical-top td { 375 | vertical-align: top; 376 | } 377 | 378 | .smaller-font { 379 | font-size: 0.9em; 380 | } 381 | 382 | td { 383 | vertical-align: top; 384 | 385 | } 386 | 387 | .web-apps td:nth-child(2) { 388 | padding-left: 20px; 389 | } 390 | 391 | .adhoc table { 392 | margin-top:-10px; 393 | width:100%; 394 | border-bottom: 1px dashed #5F6A6A; 395 | border-top: 1px dashed #5F6A6A; 396 | border-left: none; 397 | border-right: none; 398 | } 399 | 400 | .adhoc tr:nth-child(even) { 401 | background-color: #F6F6F6; 402 | } 403 | 404 | .prof td:nth-child(2) { 405 | padding-left: 15px; 406 | } 407 | 408 | sp { 409 | color: #FFF; 410 | } -------------------------------------------------------------------------------- /anderson-cv.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datalorax/anderson-cv/04e645f9145a8ede014079609f373ca8d349af87/anderson-cv.pdf -------------------------------------------------------------------------------- /anderson-cv_files/accessible-code-block-0.0.1/empty-anchor.js: -------------------------------------------------------------------------------- 1 | // Hide empty tag within highlighted CodeBlock for screen reader accessibility (see https://github.com/jgm/pandoc/issues/6352#issuecomment-626106786) --> 2 | // v0.0.1 3 | // Written by JooYoung Seo (jooyoung@psu.edu) and Atsushi Yasumoto on June 1st, 2020. 4 | 5 | document.addEventListener('DOMContentLoaded', function() { 6 | const codeList = document.getElementsByClassName("sourceCode"); 7 | for (var i = 0; i < codeList.length; i++) { 8 | var linkList = codeList[i].getElementsByTagName('a'); 9 | for (var j = 0; j < linkList.length; j++) { 10 | if (linkList[j].innerHTML === "") { 11 | linkList[j].setAttribute('aria-hidden', 'true'); 12 | } 13 | } 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /anderson-cv_files/header-attrs-2.11/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /anderson-cv_files/header-attrs-2.4/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /anderson-cv_files/header-attrs-2.6/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /anderson-cv_files/header-attrs-2.7.4/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /anderson-cv_files/header-attrs-2.7/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /anderson-cv_files/paged-0.12/js/config.js: -------------------------------------------------------------------------------- 1 | // Configuration script for paged.js 2 | 3 | (function() { 4 | // Retrieve previous config object if defined 5 | window.PagedConfig = window.PagedConfig || {}; 6 | const {before: beforePaged, after: afterPaged} = window.PagedConfig; 7 | 8 | // utils 9 | const insertCSS = text => { 10 | let style = document.createElement('style'); 11 | style.type = 'text/css'; 12 | style.appendChild(document.createTextNode(text)); 13 | document.head.appendChild(style); 14 | }; 15 | 16 | // Util function for front and back covers images 17 | const insertCSSForCover = type => { 18 | const links = document.querySelectorAll('link[id^=' + type + ']'); 19 | if (!links.length) return; 20 | const re = new RegExp(type + '-\\d+'); 21 | let text = ':root {--' + type + ': var(--' + type + '-1);'; 22 | for (const link of links) { 23 | text += '--' + re.exec(link.id)[0] + ': url("' + link.href + '");'; 24 | } 25 | text += '}'; 26 | insertCSS(text); 27 | }; 28 | 29 | const insertPageBreaksCSS = () => { 30 | insertCSS(` 31 | .page-break-after {break-after: page;} 32 | .page-break-before {break-before: page;} 33 | `); 34 | }; 35 | 36 | window.PagedConfig.before = async () => { 37 | // Front and back covers support 38 | let frontCover = document.querySelector('.front-cover'); 39 | let backCover = document.querySelector('.back-cover'); 40 | if (frontCover) document.body.prepend(frontCover); 41 | if (backCover) document.body.append(backCover); 42 | insertCSSForCover('front-cover'); 43 | insertCSSForCover('back-cover'); 44 | insertPageBreaksCSS(); 45 | 46 | if (beforePaged) await beforePaged(); 47 | }; 48 | 49 | // from https://stackoverflow.com/q/21647928 50 | const toUTF16BE = x => { 51 | let res = ''; 52 | for (i=0; i < x.length; i++) { 53 | let hex = x.charCodeAt(i).toString(16); 54 | hex = ('000' + hex).slice(-4); 55 | res += hex 56 | } 57 | res = 'feff' + res ; 58 | return res; 59 | } 60 | 61 | const findPage = el => { 62 | while (el.parentElement) { 63 | el = el.parentElement; 64 | if (el.getAttribute('data-page-number')) { 65 | return parseInt(el.getAttribute('data-page-number')); 66 | } 67 | } 68 | return null; 69 | }; 70 | 71 | const tocEntriesInfos = ul => { 72 | let result = []; // where we store the results 73 | // if there is no element, return an empty array 74 | if (!ul) { 75 | return result; 76 | } 77 | const tocEntries = ul.children; // tocEntries are 'li' elements 78 | 79 | for (const li of tocEntries) { 80 | // get the title and encode it in UTF16BE (pdfmark is encoded in UTF16BE with BOM) 81 | const title = toUTF16BE(li.querySelector('a').textContent); 82 | 83 | // get the page number 84 | const href = li.querySelector('a').getAttribute('href'); 85 | const el = document.querySelector(href); 86 | const page = findPage(el); 87 | 88 | // get the children 89 | children = tocEntriesInfos(li.querySelector('ul')); 90 | 91 | result.push({ 92 | title: title, 93 | page: page, 94 | children: children 95 | }); 96 | } 97 | 98 | return result; 99 | }; 100 | window.PagedConfig.after = (flow) => { 101 | // force redraw, see https://github.com/rstudio/pagedown/issues/35#issuecomment-475905361 102 | // and https://stackoverflow.com/a/24753578/6500804 103 | document.body.style.display = 'none'; 104 | document.body.offsetHeight; 105 | document.body.style.display = ''; 106 | 107 | // run previous PagedConfig.after function if defined 108 | if (afterPaged) afterPaged(flow); 109 | 110 | // pagedownListener is a binding added by the chrome_print function 111 | // this binding exists only when chrome_print opens the html file 112 | if (window.pagedownListener) { 113 | // the html file is opened for printing 114 | // call the binding to signal to the R session that Paged.js has finished 115 | const tocList = flow.source.querySelector('.toc > ul'); 116 | const tocInfos = tocEntriesInfos(tocList); 117 | pagedownListener(JSON.stringify({ 118 | pagedjs: true, 119 | pages: flow.total, 120 | elapsedtime: flow.performance, 121 | tocInfos: tocInfos 122 | })); 123 | return; 124 | } 125 | if (sessionStorage.getItem('pagedown-scroll')) { 126 | // scroll to the last position before the page is reloaded 127 | window.scrollTo(0, sessionStorage.getItem('pagedown-scroll')); 128 | return; 129 | } 130 | if (window.location.hash) { 131 | const id = window.location.hash.replace(/^#/, ''); 132 | document.getElementById(id).scrollIntoView({behavior: 'smooth'}); 133 | } 134 | }; 135 | })(); 136 | -------------------------------------------------------------------------------- /anderson-cv_files/paged-0.12/js/hooks.js: -------------------------------------------------------------------------------- 1 | // Hooks for paged.js 2 | { 3 | // Utils 4 | let pandocMeta, pandocMetaToString; 5 | { 6 | let el = document.getElementById('pandoc-meta'); 7 | pandocMeta = el ? JSON.parse(el.firstChild.data) : {}; 8 | } 9 | 10 | pandocMetaToString = meta => { 11 | let el = document.createElement('div'); 12 | el.innerHTML = meta; 13 | return el.innerText; 14 | }; 15 | 16 | let isString = value => { 17 | return typeof value === 'string' || value instanceof String; 18 | }; 19 | 20 | let isArray = value => { 21 | return value && typeof value === 'object' && value.constructor === Array; 22 | }; 23 | 24 | // This hook is an attempt to fix https://github.com/rstudio/pagedown/issues/131 25 | // Sometimes, the {break-after: avoid;} declaration applied on headers 26 | // lead to duplicated headers. I hate this bug. 27 | // This is linked to the way the HTML source is written 28 | // When we have the \n character like this:
\n

...

29 | // the header may be duplicated. 30 | // But, if we have

...

without any \n, the problem disappear 31 | // I think this handler can fix most of cases 32 | // Obviously, we cannot suppress all the \n in the HTML document 33 | // because carriage returns are important in
 elements.
 34 |   // Tested with Chrome 76.0.3809.100/Windows
 35 |   Paged.registerHandlers(class extends Paged.Handler {
 36 |     constructor(chunker, polisher, caller) {
 37 |       super(chunker, polisher, caller);
 38 |       this.carriageReturn = String.fromCharCode(10);
 39 |     }
 40 | 
 41 |     checkNode(node) {
 42 |       if (!node) return;
 43 |       if (node.nodeType !== 3) return;
 44 |       if (node.textContent === this.carriageReturn) {
 45 |         node.remove();
 46 |       }
 47 |     }
 48 | 
 49 |     afterParsed(parsed) {
 50 |       let template = document.querySelector('template').content;
 51 |       const breakAfterAvoidElements = template.querySelectorAll('[data-break-after="avoid"], [data-break-before="avoid"]');
 52 |       for (let el of breakAfterAvoidElements) {
 53 |         this.checkNode(el.previousSibling);
 54 |         this.checkNode(el.nextSibling);
 55 |       }
 56 |     }
 57 |   });
 58 | 
 59 |   // This hook creates a list of abbreviations
 60 |   // Note: we also could implement this feature using a Pandoc filter
 61 |   Paged.registerHandlers(class extends Paged.Handler {
 62 |     constructor(chunker, polisher, caller) {
 63 |       super(chunker, polisher, caller);
 64 |     }
 65 |     beforeParsed(content) {
 66 |       const abbreviations = content.querySelectorAll('abbr');
 67 |       if(abbreviations.length === 0) return;
 68 |       const loaTitle = 'List of Abbreviations';
 69 |       const loaId = 'LOA';
 70 |       const tocList = content.querySelector('.toc ul');
 71 |       let listOfAbbreviations = document.createElement('div');
 72 |       let descriptionList = document.createElement('dl');
 73 |       content.appendChild(listOfAbbreviations);
 74 |       listOfAbbreviations.id = loaId;
 75 |       listOfAbbreviations.classList.add('section', 'front-matter', 'level1', 'loa');
 76 |       listOfAbbreviations.innerHTML = '

' + loaTitle + '

'; 77 | listOfAbbreviations.appendChild(descriptionList); 78 | for(let abbr of abbreviations) { 79 | if(!abbr.title) continue; 80 | let term = document.createElement('dt'); 81 | let definition = document.createElement('dd'); 82 | descriptionList.appendChild(term); 83 | descriptionList.appendChild(definition); 84 | term.innerHTML = abbr.innerHTML; 85 | definition.innerText = abbr.title; 86 | } 87 | if (tocList) { 88 | const loaTOCItem = document.createElement('li'); 89 | loaTOCItem.innerHTML = '
' + loaTitle + ''; 90 | tocList.appendChild(loaTOCItem); 91 | } 92 | } 93 | }); 94 | 95 | // This hook moves the sections of class front-matter in the div.front-matter-container 96 | Paged.registerHandlers(class extends Paged.Handler { 97 | constructor(chunker, polisher, caller) { 98 | super(chunker, polisher, caller); 99 | } 100 | 101 | beforeParsed(content) { 102 | const frontMatter = content.querySelector('.front-matter-container'); 103 | if (!frontMatter) return; 104 | 105 | // move front matter sections in the front matter container 106 | const frontMatterSections = content.querySelectorAll('.level1.front-matter'); 107 | for (const section of frontMatterSections) { 108 | frontMatter.appendChild(section); 109 | } 110 | 111 | // add the class front-matter-ref to any element 112 | // referring to an entry in the front matter 113 | const anchors = content.querySelectorAll('a[href^="#"]:not([href*=":"])'); 114 | for (const a of anchors) { 115 | const ref = a.getAttribute('href').replace(/^#/, ''); 116 | const element = content.getElementById(ref); 117 | if (frontMatter.contains(element)) a.classList.add('front-matter-ref'); 118 | } 119 | 120 | // update the toc, lof and lot for front matter sections 121 | const frontMatterSectionsLinks = content.querySelectorAll('.toc .front-matter-ref, .lof .front-matter-ref, .lot .front-matter-ref'); 122 | for (let i = frontMatterSectionsLinks.length - 1; i >= 0; i--) { 123 | const listItem = frontMatterSectionsLinks[i].parentNode; 124 | const list = listItem.parentNode; 125 | list.insertBefore(listItem, list.firstChild); 126 | } 127 | } 128 | }); 129 | 130 | // This hook expands the links in the lists of figures and tables 131 | Paged.registerHandlers(class extends Paged.Handler { 132 | constructor(chunker, polisher, caller) { 133 | super(chunker, polisher, caller); 134 | } 135 | 136 | beforeParsed(content) { 137 | const items = content.querySelectorAll('.lof li, .lot li'); 138 | for (const item of items) { 139 | const anchor = item.firstChild; 140 | anchor.innerText = item.innerText; 141 | item.innerText = ''; 142 | item.append(anchor); 143 | } 144 | } 145 | }); 146 | 147 | // This hook adds spans for leading symbols 148 | Paged.registerHandlers(class extends Paged.Handler { 149 | constructor(chunker, polisher, caller) { 150 | super(chunker, polisher, caller); 151 | } 152 | 153 | beforeParsed(content) { 154 | const anchors = content.querySelectorAll('.toc a, .lof a, .lot a'); 155 | for (const a of anchors) { 156 | a.innerHTML = a.innerHTML + ''; 157 | } 158 | } 159 | }); 160 | 161 | // This hook appends short titles spans 162 | Paged.registerHandlers(class extends Paged.Handler { 163 | constructor(chunker, polisher, caller) { 164 | super(chunker, polisher, caller); 165 | } 166 | 167 | beforeParsed(content) { 168 | /* A factory returning a function that appends short titles spans. 169 | The text content of these spans are reused for running titles (see default.css). 170 | Argument: level - An integer between 1 and 6. 171 | */ 172 | function appendShortTitleSpans(level) { 173 | return () => { 174 | const divs = Array.from(content.querySelectorAll('.level' + level)); 175 | 176 | function addSpan(div) { 177 | const mainHeader = div.getElementsByTagName('h' + level)[0]; 178 | if (!mainHeader) return; 179 | const mainTitle = mainHeader.textContent; 180 | const spanSectionNumber = mainHeader.getElementsByClassName('header-section-number')[0]; 181 | const mainNumber = !!spanSectionNumber ? spanSectionNumber.textContent : ''; 182 | const runningTitle = 'shortTitle' in div.dataset ? mainNumber + ' ' + div.dataset.shortTitle : mainTitle; 183 | const span = document.createElement('span'); 184 | span.className = 'shorttitle' + level; 185 | span.innerText = runningTitle; 186 | span.style.display = "none"; 187 | mainHeader.appendChild(span); 188 | if (level == 1 && div.querySelector('.level2') === null) { 189 | let span2 = document.createElement('span'); 190 | span2.className = 'shorttitle2'; 191 | span2.innerText = ' '; 192 | span2.style.display = "none"; 193 | span.insertAdjacentElement('afterend', span2); 194 | } 195 | } 196 | 197 | for (const div of divs) { 198 | addSpan(div); 199 | } 200 | }; 201 | } 202 | 203 | appendShortTitleSpans(1)(); 204 | appendShortTitleSpans(2)(); 205 | } 206 | }); 207 | 208 | // Footnotes support 209 | Paged.registerHandlers(class extends Paged.Handler { 210 | constructor(chunker, polisher, caller) { 211 | super(chunker, polisher, caller); 212 | 213 | this.splittedParagraphRefs = []; 214 | } 215 | 216 | beforeParsed(content) { 217 | // remove footnotes in toc, lof, lot 218 | // see https://github.com/rstudio/pagedown/issues/54 219 | let removeThese = content.querySelectorAll('.toc .footnote, .lof .footnote, .lot .footnote'); 220 | for (const el of removeThese) { 221 | el.remove(); 222 | } 223 | 224 | let footnotes = content.querySelectorAll('.footnote'); 225 | 226 | for (let footnote of footnotes) { 227 | let parentElement = footnote.parentElement; 228 | let footnoteCall = document.createElement('a'); 229 | let footnoteNumber = footnote.dataset.pagedownFootnoteNumber; 230 | 231 | footnoteCall.className = 'footnote-ref'; // same class as Pandoc 232 | footnoteCall.setAttribute('id', 'fnref' + footnoteNumber); // same notation as Pandoc 233 | footnoteCall.setAttribute('href', '#' + footnote.id); 234 | footnoteCall.innerHTML = '' + footnoteNumber +''; 235 | parentElement.insertBefore(footnoteCall, footnote); 236 | 237 | // Here comes a hack. Fortunately, it works with Chrome and FF. 238 | let handler = document.createElement('p'); 239 | handler.className = 'footnoteHandler'; 240 | parentElement.insertBefore(handler, footnote); 241 | handler.appendChild(footnote); 242 | handler.style.display = 'inline-block'; 243 | handler.style.width = '100%'; 244 | handler.style.float = 'right'; 245 | handler.style.pageBreakInside = 'avoid'; 246 | } 247 | } 248 | 249 | afterPageLayout(pageFragment, page, breakToken) { 250 | function hasItemParent(node) { 251 | if (node.parentElement === null) { 252 | return false; 253 | } else { 254 | if (node.parentElement.tagName === 'LI') { 255 | return true; 256 | } else { 257 | return hasItemParent(node.parentElement); 258 | } 259 | } 260 | } 261 | // If a li item is broken, we store the reference of the p child element 262 | // see https://github.com/rstudio/pagedown/issues/23#issue-376548000 263 | if (breakToken !== undefined) { 264 | if (breakToken.node.nodeName === "#text" && hasItemParent(breakToken.node)) { 265 | this.splittedParagraphRefs.push(breakToken.node.parentElement.dataset.ref); 266 | } 267 | } 268 | } 269 | 270 | afterRendered(pages) { 271 | for (let page of pages) { 272 | const footnotes = page.element.querySelectorAll('.footnote'); 273 | if (footnotes.length === 0) { 274 | continue; 275 | } 276 | 277 | const pageContent = page.element.querySelector('.pagedjs_page_content'); 278 | let hr = document.createElement('hr'); 279 | let footnoteArea = document.createElement('div'); 280 | 281 | pageContent.style.display = 'flex'; 282 | pageContent.style.flexDirection = 'column'; 283 | 284 | hr.className = 'footnote-break'; 285 | hr.style.marginTop = 'auto'; 286 | hr.style.marginBottom = 0; 287 | hr.style.marginLeft = 0; 288 | hr.style.marginRight = 'auto'; 289 | pageContent.appendChild(hr); 290 | 291 | footnoteArea.className = 'footnote-area'; 292 | pageContent.appendChild(footnoteArea); 293 | 294 | for (let footnote of footnotes) { 295 | let handler = footnote.parentElement; 296 | 297 | footnoteArea.appendChild(footnote); 298 | handler.parentNode.removeChild(handler); 299 | 300 | footnote.innerHTML = '' + footnote.dataset.pagedownFootnoteNumber + '' + footnote.innerHTML; 301 | footnote.style.fontSize = 'x-small'; 302 | footnote.style.marginTop = 0; 303 | footnote.style.marginBottom = 0; 304 | footnote.style.paddingTop = 0; 305 | footnote.style.paddingBottom = 0; 306 | footnote.style.display = 'block'; 307 | } 308 | } 309 | 310 | for (let ref of this.splittedParagraphRefs) { 311 | let paragraphFirstPage = document.querySelector('[data-split-to="' + ref + '"]'); 312 | // We test whether the paragraph is empty 313 | // see https://github.com/rstudio/pagedown/issues/23#issue-376548000 314 | if (paragraphFirstPage.innerText === "") { 315 | paragraphFirstPage.parentElement.style.display = "none"; 316 | let paragraphSecondPage = document.querySelector('[data-split-from="' + ref + '"]'); 317 | paragraphSecondPage.parentElement.style.setProperty('list-style', 'inherit', 'important'); 318 | } 319 | } 320 | } 321 | }); 322 | 323 | // Support for "Chapter " label on section with class `.chapter` 324 | Paged.registerHandlers(class extends Paged.Handler { 325 | constructor(chunker, polisher, caller) { 326 | super(chunker, polisher, caller); 327 | 328 | this.options = pandocMeta['chapter_name']; 329 | 330 | let styles; 331 | if (isString(this.options)) { 332 | this.options = pandocMetaToString(this.options); 333 | styles = ` 334 | :root { 335 | --chapter-name-before: "${this.options}"; 336 | } 337 | `; 338 | } 339 | if (isArray(this.options)) { 340 | this.options = this.options.map(pandocMetaToString); 341 | styles = ` 342 | :root { 343 | --chapter-name-before: "${this.options[0]}"; 344 | --chapter-name-after: "${this.options[1]}"; 345 | } 346 | `; 347 | } 348 | if (styles) polisher.insert(styles); 349 | } 350 | 351 | beforeParsed(content) { 352 | const tocAnchors = content.querySelectorAll('.toc a[href^="#"]:not([href*=":"]'); 353 | for (const anchor of tocAnchors) { 354 | const ref = anchor.getAttribute('href').replace(/^#/, ''); 355 | const element = content.getElementById(ref); 356 | if (element.classList.contains('chapter')) { 357 | anchor.classList.add('chapter-ref'); 358 | } 359 | } 360 | } 361 | }); 362 | 363 | // Main text line numbering, 364 | // see https://github.com/rstudio/pagedown/issues/115 365 | // Original idea: Julien Taquet, thanks! 366 | Paged.registerHandlers(class extends Paged.Handler { 367 | constructor(chunker, polisher, caller) { 368 | super(chunker, polisher, caller); 369 | 370 | // get the number-lines option from Pandoc metavariables 371 | this.options = pandocMeta['number-lines']; 372 | // quit early if the "number-lines" option is false or missing 373 | if (!this.options) return; 374 | // retrieve the selector if provided, otherwise use the default selector 375 | this.selector = this.options.selector ? pandocMetaToString(this.options.selector) : '.level1:not(.front-matter) h1, .level1 h2, .level1 h3, .level1 p'; 376 | 377 | const styles = ` 378 | :root { 379 | --line-numbers-padding-right: 10px; 380 | --line-numbers-font-size: 8pt; 381 | } 382 | .pagedown-linenumbers-container { 383 | position: absolute; 384 | margin-top: var(--pagedjs-margin-top); 385 | right: calc(var(--pagedjs-width) - var(--pagedjs-margin-left)); 386 | } 387 | .maintextlinenumbers { 388 | position: absolute; 389 | right: 0; 390 | text-align: right; 391 | padding-right: var(--line-numbers-padding-right); 392 | font-size: var(--line-numbers-font-size); 393 | } 394 | `; 395 | polisher.insert(styles); 396 | 397 | this.resetLinesCounter(); 398 | } 399 | 400 | appendLineNumbersContainer(page) { 401 | const pagebox = page.element.querySelector('.pagedjs_pagebox'); 402 | const lineNumbersContainer = document.createElement('div'); 403 | lineNumbersContainer.classList.add('pagedown-linenumbers-container'); 404 | 405 | return pagebox.appendChild(lineNumbersContainer); 406 | } 407 | 408 | lineHeight(element) { 409 | // If the document stylesheet does not define a value for line-height, 410 | // Blink returns "normal". Therefore, parseInt may return NaN. 411 | return parseInt(getComputedStyle(element).lineHeight); 412 | } 413 | 414 | innerHeight(element) { 415 | let outerHeight = element.getBoundingClientRect().height; 416 | let {borderTopWidth, 417 | borderBottomWidth, 418 | paddingTop, 419 | paddingBottom} = getComputedStyle(element); 420 | 421 | borderTopWidth = parseFloat(borderTopWidth); 422 | borderBottomWidth = parseFloat(borderBottomWidth); 423 | paddingTop = parseFloat(paddingTop); 424 | paddingBottom = parseFloat(paddingBottom); 425 | 426 | return Math.round(outerHeight - borderTopWidth - borderBottomWidth - paddingTop - paddingBottom); 427 | } 428 | 429 | arrayOfInt(from, length) { 430 | // adapted from https://stackoverflow.com/a/50234108/6500804 431 | return Array.from(Array(length).keys(), n => n + from); 432 | } 433 | 434 | incrementLinesCounter(value) { 435 | this.linesCounter = this.linesCounter + value; 436 | } 437 | 438 | resetLinesCounter() { 439 | this.linesCounter = 0; 440 | } 441 | 442 | isDisplayMath(element) { 443 | const nodes = element.childNodes; 444 | if (nodes.length != 1) return false; 445 | return (nodes[0].nodeName === 'SPAN') && (nodes[0].classList.value === 'math display'); 446 | } 447 | 448 | afterRendered(pages) { 449 | if (!this.options) return; 450 | 451 | for (let page of pages) { 452 | const lineNumbersContainer = this.appendLineNumbersContainer(page); 453 | const pageAreaY = page.area.getBoundingClientRect().y; 454 | let elementsToNumber = page.area.querySelectorAll(this.selector); 455 | 456 | for (let element of elementsToNumber) { 457 | // Do not add line numbers for display math environment 458 | if (this.isDisplayMath(element)) continue; 459 | 460 | // Try to retrieve line height 461 | const lineHeight = this.lineHeight(element); 462 | // Test against lineHeight method returns NaN 463 | if (!lineHeight) { 464 | console.warn('Failed to compute line height value on "' + page.id + '".'); 465 | continue; 466 | } 467 | 468 | const innerHeight = this.innerHeight(element); 469 | 470 | // Number of lines estimation 471 | // There is no built-in method to detect the number of lines in a block. 472 | // The main caveat is that an actual line height can differ from 473 | // the line-height CSS property. 474 | // Mixed fonts, subscripts, superscripts, inline math... can increase 475 | // the actual line height. 476 | // Here, we divide the inner height of the block by the line-height 477 | // computed property and round to the floor to take into account that 478 | // sometimes the actual line height is greater than its property value. 479 | // This is far from perfect and can be easily broken especially by 480 | // inline math. 481 | const nLines = Math.floor(innerHeight / lineHeight); 482 | 483 | // do not add line numbers for void paragraphs 484 | if (nLines <= 0) continue; 485 | 486 | const linenumbers = document.createElement('div'); 487 | lineNumbersContainer.appendChild(linenumbers); 488 | linenumbers.classList.add('maintextlinenumbers'); 489 | 490 | const elementY = element.getBoundingClientRect().y; 491 | linenumbers.style.top = (elementY - pageAreaY) + 'px'; 492 | 493 | const cs = getComputedStyle(element); 494 | const paddingTop = parseFloat(cs.paddingTop) + parseFloat(cs.borderTopWidth); 495 | linenumbers.style.paddingTop = paddingTop + 'px'; 496 | 497 | linenumbers.style.lineHeight = cs.lineHeight; 498 | 499 | linenumbers.innerHTML = this.arrayOfInt(this.linesCounter + 1, nLines) 500 | .reduce((t, v) => t + '
' + v); 501 | this.incrementLinesCounter(nLines); 502 | } 503 | 504 | if (this.options['reset-page']) { 505 | this.resetLinesCounter(); 506 | } 507 | } 508 | } 509 | }); 510 | } 511 | -------------------------------------------------------------------------------- /anderson-cv_files/paged-0.13/js/config.js: -------------------------------------------------------------------------------- 1 | // Configuration script for paged.js 2 | 3 | (function() { 4 | // Retrieve previous config object if defined 5 | window.PagedConfig = window.PagedConfig || {}; 6 | const {before: beforePaged, after: afterPaged} = window.PagedConfig; 7 | 8 | // utils 9 | const insertCSS = text => { 10 | let style = document.createElement('style'); 11 | style.type = 'text/css'; 12 | style.appendChild(document.createTextNode(text)); 13 | document.head.appendChild(style); 14 | }; 15 | 16 | // Util function for front and back covers images 17 | const insertCSSForCover = type => { 18 | const links = document.querySelectorAll('link[id^=' + type + ']'); 19 | if (!links.length) return; 20 | const re = new RegExp(type + '-\\d+'); 21 | let text = ':root {--' + type + ': var(--' + type + '-1);'; 22 | for (const link of links) { 23 | text += '--' + re.exec(link.id)[0] + ': url("' + link.href + '");'; 24 | } 25 | text += '}'; 26 | insertCSS(text); 27 | }; 28 | 29 | const insertPageBreaksCSS = () => { 30 | insertCSS(` 31 | .page-break-after {break-after: page;} 32 | .page-break-before {break-before: page;} 33 | `); 34 | }; 35 | 36 | window.PagedConfig.before = async () => { 37 | // Front and back covers support 38 | let frontCover = document.querySelector('.front-cover'); 39 | let backCover = document.querySelector('.back-cover'); 40 | if (frontCover) document.body.prepend(frontCover); 41 | if (backCover) document.body.append(backCover); 42 | insertCSSForCover('front-cover'); 43 | insertCSSForCover('back-cover'); 44 | insertPageBreaksCSS(); 45 | 46 | if (beforePaged) await beforePaged(); 47 | }; 48 | 49 | // from https://stackoverflow.com/q/21647928 50 | const toUTF16BE = x => { 51 | let res = ''; 52 | for (i=0; i < x.length; i++) { 53 | let hex = x.charCodeAt(i).toString(16); 54 | hex = ('000' + hex).slice(-4); 55 | res += hex 56 | } 57 | res = 'feff' + res ; 58 | return res; 59 | } 60 | 61 | const findPage = el => { 62 | while (el.parentElement) { 63 | el = el.parentElement; 64 | if (el.getAttribute('data-page-number')) { 65 | return parseInt(el.getAttribute('data-page-number')); 66 | } 67 | } 68 | return null; 69 | }; 70 | 71 | const tocEntriesInfos = ul => { 72 | let result = []; // where we store the results 73 | // if there is no element, return an empty array 74 | if (!ul) { 75 | return result; 76 | } 77 | const tocEntries = ul.children; // tocEntries are 'li' elements 78 | 79 | for (const li of tocEntries) { 80 | // get the title and encode it in UTF16BE (pdfmark is encoded in UTF16BE with BOM) 81 | const title = toUTF16BE(li.querySelector('a').textContent); 82 | 83 | // get the page number 84 | const href = li.querySelector('a').getAttribute('href'); 85 | const el = document.querySelector(href); 86 | const page = findPage(el); 87 | 88 | // get the children 89 | children = tocEntriesInfos(li.querySelector('ul')); 90 | 91 | result.push({ 92 | title: title, 93 | page: page, 94 | children: children 95 | }); 96 | } 97 | 98 | return result; 99 | }; 100 | window.PagedConfig.after = (flow) => { 101 | // force redraw, see https://github.com/rstudio/pagedown/issues/35#issuecomment-475905361 102 | // and https://stackoverflow.com/a/24753578/6500804 103 | document.body.style.display = 'none'; 104 | document.body.offsetHeight; 105 | document.body.style.display = ''; 106 | 107 | // run previous PagedConfig.after function if defined 108 | if (afterPaged) afterPaged(flow); 109 | 110 | // pagedownListener is a binding added by the chrome_print function 111 | // this binding exists only when chrome_print opens the html file 112 | if (window.pagedownListener) { 113 | // the html file is opened for printing 114 | // call the binding to signal to the R session that Paged.js has finished 115 | const tocList = flow.source.querySelector('.toc > ul'); 116 | const tocInfos = tocEntriesInfos(tocList); 117 | pagedownListener(JSON.stringify({ 118 | pagedjs: true, 119 | pages: flow.total, 120 | elapsedtime: flow.performance, 121 | tocInfos: tocInfos 122 | })); 123 | return; 124 | } 125 | if (sessionStorage.getItem('pagedown-scroll')) { 126 | // scroll to the last position before the page is reloaded 127 | window.scrollTo(0, sessionStorage.getItem('pagedown-scroll')); 128 | return; 129 | } 130 | if (window.location.hash) { 131 | const id = window.location.hash.replace(/^#/, ''); 132 | document.getElementById(id).scrollIntoView({behavior: 'smooth'}); 133 | } 134 | }; 135 | })(); 136 | -------------------------------------------------------------------------------- /anderson-cv_files/paged-0.13/js/hooks.js: -------------------------------------------------------------------------------- 1 | // Hooks for paged.js 2 | { 3 | // Utils 4 | let pandocMeta, pandocMetaToString; 5 | { 6 | let el = document.getElementById('pandoc-meta'); 7 | pandocMeta = el ? JSON.parse(el.firstChild.data) : {}; 8 | } 9 | 10 | pandocMetaToString = meta => { 11 | let el = document.createElement('div'); 12 | el.innerHTML = meta; 13 | return el.innerText; 14 | }; 15 | 16 | let isString = value => { 17 | return typeof value === 'string' || value instanceof String; 18 | }; 19 | 20 | let isArray = value => { 21 | return value && typeof value === 'object' && value.constructor === Array; 22 | }; 23 | 24 | // This hook is an attempt to fix https://github.com/rstudio/pagedown/issues/131 25 | // Sometimes, the {break-after: avoid;} declaration applied on headers 26 | // lead to duplicated headers. I hate this bug. 27 | // This is linked to the way the HTML source is written 28 | // When we have the \n character like this:
\n

...

29 | // the header may be duplicated. 30 | // But, if we have

...

without any \n, the problem disappear 31 | // I think this handler can fix most of cases 32 | // Obviously, we cannot suppress all the \n in the HTML document 33 | // because carriage returns are important in
 elements.
 34 |   // Tested with Chrome 76.0.3809.100/Windows
 35 |   Paged.registerHandlers(class extends Paged.Handler {
 36 |     constructor(chunker, polisher, caller) {
 37 |       super(chunker, polisher, caller);
 38 |       this.carriageReturn = String.fromCharCode(10);
 39 |     }
 40 | 
 41 |     checkNode(node) {
 42 |       if (!node) return;
 43 |       if (node.nodeType !== 3) return;
 44 |       if (node.textContent === this.carriageReturn) {
 45 |         node.remove();
 46 |       }
 47 |     }
 48 | 
 49 |     afterParsed(parsed) {
 50 |       let template = document.querySelector('template').content;
 51 |       const breakAfterAvoidElements = template.querySelectorAll('[data-break-after="avoid"], [data-break-before="avoid"]');
 52 |       for (let el of breakAfterAvoidElements) {
 53 |         this.checkNode(el.previousSibling);
 54 |         this.checkNode(el.nextSibling);
 55 |       }
 56 |     }
 57 |   });
 58 | 
 59 |   // This hook creates a list of abbreviations
 60 |   // Note: we also could implement this feature using a Pandoc filter
 61 |   Paged.registerHandlers(class extends Paged.Handler {
 62 |     constructor(chunker, polisher, caller) {
 63 |       super(chunker, polisher, caller);
 64 |     }
 65 |     beforeParsed(content) {
 66 |       const abbreviations = content.querySelectorAll('abbr');
 67 |       if(abbreviations.length === 0) return;
 68 |       const loaTitle = pandocMeta['loa-title'] ? pandocMetaToString(pandocMeta['loa-title']) : 'List of Abbreviations';
 69 |       const loaId = 'LOA';
 70 |       const tocList = content.querySelector('.toc ul');
 71 |       let listOfAbbreviations = document.createElement('div');
 72 |       let descriptionList = document.createElement('dl');
 73 |       content.appendChild(listOfAbbreviations);
 74 |       listOfAbbreviations.id = loaId;
 75 |       listOfAbbreviations.classList.add('section', 'front-matter', 'level1', 'loa');
 76 |       listOfAbbreviations.innerHTML = '

' + loaTitle + '

'; 77 | listOfAbbreviations.appendChild(descriptionList); 78 | for(let abbr of abbreviations) { 79 | if(!abbr.title) continue; 80 | let term = document.createElement('dt'); 81 | let definition = document.createElement('dd'); 82 | descriptionList.appendChild(term); 83 | descriptionList.appendChild(definition); 84 | term.innerHTML = abbr.innerHTML; 85 | definition.innerText = abbr.title; 86 | } 87 | if (tocList) { 88 | const loaTOCItem = document.createElement('li'); 89 | loaTOCItem.innerHTML = '' + loaTitle + ''; 90 | tocList.appendChild(loaTOCItem); 91 | } 92 | } 93 | }); 94 | 95 | // This hook moves the sections of class front-matter in the div.front-matter-container 96 | Paged.registerHandlers(class extends Paged.Handler { 97 | constructor(chunker, polisher, caller) { 98 | super(chunker, polisher, caller); 99 | } 100 | 101 | beforeParsed(content) { 102 | const frontMatter = content.querySelector('.front-matter-container'); 103 | if (!frontMatter) return; 104 | 105 | // move front matter sections in the front matter container 106 | const frontMatterSections = content.querySelectorAll('.level1.front-matter'); 107 | for (const section of frontMatterSections) { 108 | frontMatter.appendChild(section); 109 | } 110 | 111 | // add the class front-matter-ref to any element 112 | // referring to an entry in the front matter 113 | const anchors = content.querySelectorAll('a[href^="#"]:not([href*=":"])'); 114 | for (const a of anchors) { 115 | const ref = a.getAttribute('href').replace(/^#/, ''); 116 | const element = content.getElementById(ref); 117 | if (frontMatter.contains(element)) a.classList.add('front-matter-ref'); 118 | } 119 | 120 | // update the toc, lof and lot for front matter sections 121 | const frontMatterSectionsLinks = content.querySelectorAll('.toc .front-matter-ref, .lof .front-matter-ref, .lot .front-matter-ref'); 122 | for (let i = frontMatterSectionsLinks.length - 1; i >= 0; i--) { 123 | const listItem = frontMatterSectionsLinks[i].parentNode; 124 | const list = listItem.parentNode; 125 | list.insertBefore(listItem, list.firstChild); 126 | } 127 | } 128 | }); 129 | 130 | // This hook expands the links in the lists of figures and tables 131 | Paged.registerHandlers(class extends Paged.Handler { 132 | constructor(chunker, polisher, caller) { 133 | super(chunker, polisher, caller); 134 | } 135 | 136 | beforeParsed(content) { 137 | const items = content.querySelectorAll('.lof li, .lot li'); 138 | for (const item of items) { 139 | const anchor = item.firstChild; 140 | anchor.innerText = item.innerText; 141 | item.innerText = ''; 142 | item.append(anchor); 143 | } 144 | } 145 | }); 146 | 147 | // This hook adds spans for leading symbols 148 | Paged.registerHandlers(class extends Paged.Handler { 149 | constructor(chunker, polisher, caller) { 150 | super(chunker, polisher, caller); 151 | } 152 | 153 | beforeParsed(content) { 154 | const anchors = content.querySelectorAll('.toc a, .lof a, .lot a'); 155 | for (const a of anchors) { 156 | a.innerHTML = a.innerHTML + ''; 157 | } 158 | } 159 | }); 160 | 161 | // This hook appends short titles spans 162 | Paged.registerHandlers(class extends Paged.Handler { 163 | constructor(chunker, polisher, caller) { 164 | super(chunker, polisher, caller); 165 | } 166 | 167 | beforeParsed(content) { 168 | /* A factory returning a function that appends short titles spans. 169 | The text content of these spans are reused for running titles (see default.css). 170 | Argument: level - An integer between 1 and 6. 171 | */ 172 | function appendShortTitleSpans(level) { 173 | return () => { 174 | const divs = Array.from(content.querySelectorAll('.level' + level)); 175 | 176 | function addSpan(div) { 177 | const mainHeader = div.getElementsByTagName('h' + level)[0]; 178 | if (!mainHeader) return; 179 | const mainTitle = mainHeader.textContent; 180 | const spanSectionNumber = mainHeader.getElementsByClassName('header-section-number')[0]; 181 | const mainNumber = !!spanSectionNumber ? spanSectionNumber.textContent : ''; 182 | const runningTitle = 'shortTitle' in div.dataset ? mainNumber + ' ' + div.dataset.shortTitle : mainTitle; 183 | const span = document.createElement('span'); 184 | span.className = 'shorttitle' + level; 185 | span.innerText = runningTitle; 186 | span.style.display = "none"; 187 | mainHeader.appendChild(span); 188 | if (level == 1 && div.querySelector('.level2') === null) { 189 | let span2 = document.createElement('span'); 190 | span2.className = 'shorttitle2'; 191 | span2.innerText = ' '; 192 | span2.style.display = "none"; 193 | span.insertAdjacentElement('afterend', span2); 194 | } 195 | } 196 | 197 | for (const div of divs) { 198 | addSpan(div); 199 | } 200 | }; 201 | } 202 | 203 | appendShortTitleSpans(1)(); 204 | appendShortTitleSpans(2)(); 205 | } 206 | }); 207 | 208 | // Footnotes support 209 | Paged.registerHandlers(class extends Paged.Handler { 210 | constructor(chunker, polisher, caller) { 211 | super(chunker, polisher, caller); 212 | 213 | this.splittedParagraphRefs = []; 214 | } 215 | 216 | beforeParsed(content) { 217 | // remove footnotes in toc, lof, lot 218 | // see https://github.com/rstudio/pagedown/issues/54 219 | let removeThese = content.querySelectorAll('.toc .footnote, .lof .footnote, .lot .footnote'); 220 | for (const el of removeThese) { 221 | el.remove(); 222 | } 223 | 224 | let footnotes = content.querySelectorAll('.footnote'); 225 | 226 | for (let footnote of footnotes) { 227 | let parentElement = footnote.parentElement; 228 | let footnoteCall = document.createElement('a'); 229 | let footnoteNumber = footnote.dataset.pagedownFootnoteNumber; 230 | 231 | footnoteCall.className = 'footnote-ref'; // same class as Pandoc 232 | footnoteCall.setAttribute('id', 'fnref' + footnoteNumber); // same notation as Pandoc 233 | footnoteCall.setAttribute('href', '#' + footnote.id); 234 | footnoteCall.innerHTML = '' + footnoteNumber +''; 235 | parentElement.insertBefore(footnoteCall, footnote); 236 | 237 | // Here comes a hack. Fortunately, it works with Chrome and FF. 238 | let handler = document.createElement('p'); 239 | handler.className = 'footnoteHandler'; 240 | parentElement.insertBefore(handler, footnote); 241 | handler.appendChild(footnote); 242 | handler.style.display = 'inline-block'; 243 | handler.style.width = '100%'; 244 | handler.style.float = 'right'; 245 | handler.style.pageBreakInside = 'avoid'; 246 | } 247 | } 248 | 249 | afterPageLayout(pageFragment, page, breakToken) { 250 | function hasItemParent(node) { 251 | if (node.parentElement === null) { 252 | return false; 253 | } else { 254 | if (node.parentElement.tagName === 'LI') { 255 | return true; 256 | } else { 257 | return hasItemParent(node.parentElement); 258 | } 259 | } 260 | } 261 | // If a li item is broken, we store the reference of the p child element 262 | // see https://github.com/rstudio/pagedown/issues/23#issue-376548000 263 | if (breakToken !== undefined) { 264 | if (breakToken.node.nodeName === "#text" && hasItemParent(breakToken.node)) { 265 | this.splittedParagraphRefs.push(breakToken.node.parentElement.dataset.ref); 266 | } 267 | } 268 | } 269 | 270 | afterRendered(pages) { 271 | for (let page of pages) { 272 | const footnotes = page.element.querySelectorAll('.footnote'); 273 | if (footnotes.length === 0) { 274 | continue; 275 | } 276 | 277 | const pageContent = page.element.querySelector('.pagedjs_page_content'); 278 | let hr = document.createElement('hr'); 279 | let footnoteArea = document.createElement('div'); 280 | 281 | pageContent.style.display = 'flex'; 282 | pageContent.style.flexDirection = 'column'; 283 | 284 | hr.className = 'footnote-break'; 285 | hr.style.marginTop = 'auto'; 286 | hr.style.marginBottom = 0; 287 | hr.style.marginLeft = 0; 288 | hr.style.marginRight = 'auto'; 289 | pageContent.appendChild(hr); 290 | 291 | footnoteArea.className = 'footnote-area'; 292 | pageContent.appendChild(footnoteArea); 293 | 294 | for (let footnote of footnotes) { 295 | let handler = footnote.parentElement; 296 | 297 | footnoteArea.appendChild(footnote); 298 | handler.parentNode.removeChild(handler); 299 | 300 | footnote.innerHTML = '' + footnote.dataset.pagedownFootnoteNumber + '' + footnote.innerHTML; 301 | footnote.style.fontSize = 'x-small'; 302 | footnote.style.marginTop = 0; 303 | footnote.style.marginBottom = 0; 304 | footnote.style.paddingTop = 0; 305 | footnote.style.paddingBottom = 0; 306 | footnote.style.display = 'block'; 307 | } 308 | } 309 | 310 | for (let ref of this.splittedParagraphRefs) { 311 | let paragraphFirstPage = document.querySelector('[data-split-to="' + ref + '"]'); 312 | // We test whether the paragraph is empty 313 | // see https://github.com/rstudio/pagedown/issues/23#issue-376548000 314 | if (paragraphFirstPage.innerText === "") { 315 | paragraphFirstPage.parentElement.style.display = "none"; 316 | let paragraphSecondPage = document.querySelector('[data-split-from="' + ref + '"]'); 317 | paragraphSecondPage.parentElement.style.setProperty('list-style', 'inherit', 'important'); 318 | } 319 | } 320 | } 321 | }); 322 | 323 | // Support for "Chapter " label on section with class `.chapter` 324 | Paged.registerHandlers(class extends Paged.Handler { 325 | constructor(chunker, polisher, caller) { 326 | super(chunker, polisher, caller); 327 | 328 | this.options = pandocMeta['chapter_name']; 329 | 330 | let styles; 331 | if (isString(this.options)) { 332 | this.options = pandocMetaToString(this.options); 333 | styles = ` 334 | :root { 335 | --chapter-name-before: "${this.options}"; 336 | } 337 | `; 338 | } 339 | if (isArray(this.options)) { 340 | this.options = this.options.map(pandocMetaToString); 341 | styles = ` 342 | :root { 343 | --chapter-name-before: "${this.options[0]}"; 344 | --chapter-name-after: "${this.options[1]}"; 345 | } 346 | `; 347 | } 348 | if (styles) polisher.insert(styles); 349 | } 350 | 351 | beforeParsed(content) { 352 | const tocAnchors = content.querySelectorAll('.toc a[href^="#"]:not([href*=":"]'); 353 | for (const anchor of tocAnchors) { 354 | const ref = anchor.getAttribute('href').replace(/^#/, ''); 355 | const element = content.getElementById(ref); 356 | if (element.classList.contains('chapter')) { 357 | anchor.classList.add('chapter-ref'); 358 | } 359 | } 360 | } 361 | }); 362 | 363 | // Main text line numbering, 364 | // see https://github.com/rstudio/pagedown/issues/115 365 | // Original idea: Julien Taquet, thanks! 366 | Paged.registerHandlers(class extends Paged.Handler { 367 | constructor(chunker, polisher, caller) { 368 | super(chunker, polisher, caller); 369 | 370 | // get the number-lines option from Pandoc metavariables 371 | this.options = pandocMeta['number-lines']; 372 | // quit early if the "number-lines" option is false or missing 373 | if (!this.options) return; 374 | // retrieve the selector if provided, otherwise use the default selector 375 | this.selector = this.options.selector ? pandocMetaToString(this.options.selector) : '.level1:not(.front-matter) h1, .level1 h2, .level1 h3, .level1 p'; 376 | 377 | const styles = ` 378 | :root { 379 | --line-numbers-padding-right: 10px; 380 | --line-numbers-font-size: 8pt; 381 | } 382 | .pagedown-linenumbers-container { 383 | position: absolute; 384 | margin-top: var(--pagedjs-margin-top); 385 | right: calc(var(--pagedjs-width) - var(--pagedjs-margin-left)); 386 | } 387 | .maintextlinenumbers { 388 | position: absolute; 389 | right: 0; 390 | text-align: right; 391 | padding-right: var(--line-numbers-padding-right); 392 | font-size: var(--line-numbers-font-size); 393 | } 394 | `; 395 | polisher.insert(styles); 396 | 397 | this.resetLinesCounter(); 398 | } 399 | 400 | appendLineNumbersContainer(page) { 401 | const pagebox = page.element.querySelector('.pagedjs_pagebox'); 402 | const lineNumbersContainer = document.createElement('div'); 403 | lineNumbersContainer.classList.add('pagedown-linenumbers-container'); 404 | 405 | return pagebox.appendChild(lineNumbersContainer); 406 | } 407 | 408 | lineHeight(element) { 409 | // If the document stylesheet does not define a value for line-height, 410 | // Blink returns "normal". Therefore, parseInt may return NaN. 411 | return parseInt(getComputedStyle(element).lineHeight); 412 | } 413 | 414 | innerHeight(element) { 415 | let outerHeight = element.getBoundingClientRect().height; 416 | let {borderTopWidth, 417 | borderBottomWidth, 418 | paddingTop, 419 | paddingBottom} = getComputedStyle(element); 420 | 421 | borderTopWidth = parseFloat(borderTopWidth); 422 | borderBottomWidth = parseFloat(borderBottomWidth); 423 | paddingTop = parseFloat(paddingTop); 424 | paddingBottom = parseFloat(paddingBottom); 425 | 426 | return Math.round(outerHeight - borderTopWidth - borderBottomWidth - paddingTop - paddingBottom); 427 | } 428 | 429 | arrayOfInt(from, length) { 430 | // adapted from https://stackoverflow.com/a/50234108/6500804 431 | return Array.from(Array(length).keys(), n => n + from); 432 | } 433 | 434 | incrementLinesCounter(value) { 435 | this.linesCounter = this.linesCounter + value; 436 | } 437 | 438 | resetLinesCounter() { 439 | this.linesCounter = 0; 440 | } 441 | 442 | isDisplayMath(element) { 443 | const nodes = element.childNodes; 444 | if (nodes.length != 1) return false; 445 | return (nodes[0].nodeName === 'SPAN') && (nodes[0].classList.value === 'math display'); 446 | } 447 | 448 | afterRendered(pages) { 449 | if (!this.options) return; 450 | 451 | for (let page of pages) { 452 | const lineNumbersContainer = this.appendLineNumbersContainer(page); 453 | const pageAreaY = page.area.getBoundingClientRect().y; 454 | let elementsToNumber = page.area.querySelectorAll(this.selector); 455 | 456 | for (let element of elementsToNumber) { 457 | // Do not add line numbers for display math environment 458 | if (this.isDisplayMath(element)) continue; 459 | 460 | // Try to retrieve line height 461 | const lineHeight = this.lineHeight(element); 462 | // Test against lineHeight method returns NaN 463 | if (!lineHeight) { 464 | console.warn('Failed to compute line height value on "' + page.id + '".'); 465 | continue; 466 | } 467 | 468 | const innerHeight = this.innerHeight(element); 469 | 470 | // Number of lines estimation 471 | // There is no built-in method to detect the number of lines in a block. 472 | // The main caveat is that an actual line height can differ from 473 | // the line-height CSS property. 474 | // Mixed fonts, subscripts, superscripts, inline math... can increase 475 | // the actual line height. 476 | // Here, we divide the inner height of the block by the line-height 477 | // computed property and round to the floor to take into account that 478 | // sometimes the actual line height is greater than its property value. 479 | // This is far from perfect and can be easily broken especially by 480 | // inline math. 481 | const nLines = Math.floor(innerHeight / lineHeight); 482 | 483 | // do not add line numbers for void paragraphs 484 | if (nLines <= 0) continue; 485 | 486 | const linenumbers = document.createElement('div'); 487 | lineNumbersContainer.appendChild(linenumbers); 488 | linenumbers.classList.add('maintextlinenumbers'); 489 | 490 | const elementY = element.getBoundingClientRect().y; 491 | linenumbers.style.top = (elementY - pageAreaY) + 'px'; 492 | 493 | const cs = getComputedStyle(element); 494 | const paddingTop = parseFloat(cs.paddingTop) + parseFloat(cs.borderTopWidth); 495 | linenumbers.style.paddingTop = paddingTop + 'px'; 496 | 497 | linenumbers.style.lineHeight = cs.lineHeight; 498 | 499 | linenumbers.innerHTML = this.arrayOfInt(this.linesCounter + 1, nLines) 500 | .reduce((t, v) => t + '
' + v); 501 | this.incrementLinesCounter(nLines); 502 | } 503 | 504 | if (this.options['reset-page']) { 505 | this.resetLinesCounter(); 506 | } 507 | } 508 | } 509 | }); 510 | } 511 | -------------------------------------------------------------------------------- /anderson-cv_files/paged-0.14/js/config.js: -------------------------------------------------------------------------------- 1 | // Configuration script for paged.js 2 | 3 | (function() { 4 | // Retrieve previous config object if defined 5 | window.PagedConfig = window.PagedConfig || {}; 6 | const {before: beforePaged, after: afterPaged} = window.PagedConfig; 7 | 8 | // utils 9 | const insertCSS = text => { 10 | let style = document.createElement('style'); 11 | style.type = 'text/css'; 12 | style.appendChild(document.createTextNode(text)); 13 | document.head.appendChild(style); 14 | }; 15 | 16 | // Util function for front and back covers images 17 | const insertCSSForCover = type => { 18 | const links = document.querySelectorAll('link[id^=' + type + ']'); 19 | if (!links.length) return; 20 | const re = new RegExp(type + '-\\d+'); 21 | let text = ':root {--' + type + ': var(--' + type + '-1);'; 22 | for (const link of links) { 23 | text += '--' + re.exec(link.id)[0] + ': url("' + link.href + '");'; 24 | } 25 | text += '}'; 26 | insertCSS(text); 27 | }; 28 | 29 | const insertPageBreaksCSS = () => { 30 | insertCSS(` 31 | .page-break-after {break-after: page;} 32 | .page-break-before {break-before: page;} 33 | `); 34 | }; 35 | 36 | window.PagedConfig.before = async () => { 37 | // Front and back covers support 38 | let frontCover = document.querySelector('.front-cover'); 39 | let backCover = document.querySelector('.back-cover'); 40 | if (frontCover) document.body.prepend(frontCover); 41 | if (backCover) document.body.append(backCover); 42 | insertCSSForCover('front-cover'); 43 | insertCSSForCover('back-cover'); 44 | insertPageBreaksCSS(); 45 | 46 | if (beforePaged) await beforePaged(); 47 | }; 48 | 49 | // from https://stackoverflow.com/q/21647928 50 | const toUTF16BE = x => { 51 | let res = ''; 52 | for (i=0; i < x.length; i++) { 53 | let hex = x.charCodeAt(i).toString(16); 54 | hex = ('000' + hex).slice(-4); 55 | res += hex 56 | } 57 | res = 'feff' + res ; 58 | return res; 59 | } 60 | 61 | const findPage = el => { 62 | while (el.parentElement) { 63 | el = el.parentElement; 64 | if (el.getAttribute('data-page-number')) { 65 | return parseInt(el.getAttribute('data-page-number')); 66 | } 67 | } 68 | return null; 69 | }; 70 | 71 | const tocEntriesInfos = ul => { 72 | let result = []; // where we store the results 73 | // if there is no element, return an empty array 74 | if (!ul) { 75 | return result; 76 | } 77 | const tocEntries = ul.children; // tocEntries are 'li' elements 78 | 79 | for (const li of tocEntries) { 80 | // Since parts entries in TOC have no anchor, 81 | // do not use them in the PDF outline. 82 | if (li.classList.contains('part')) { 83 | continue; 84 | } 85 | 86 | // get the title and encode it in UTF16BE (pdfmark is encoded in UTF16BE with BOM) 87 | const title = toUTF16BE(li.querySelector('a').textContent); 88 | 89 | // get the page number 90 | const href = li.querySelector('a').getAttribute('href'); 91 | const el = document.getElementById(href.substring(1)); 92 | const page = findPage(el); 93 | 94 | // get the children 95 | children = tocEntriesInfos(li.querySelector('ul')); 96 | 97 | result.push({ 98 | title: title, 99 | page: page, 100 | children: children 101 | }); 102 | } 103 | 104 | return result; 105 | }; 106 | window.PagedConfig.after = (flow) => { 107 | // force redraw, see https://github.com/rstudio/pagedown/issues/35#issuecomment-475905361 108 | // and https://stackoverflow.com/a/24753578/6500804 109 | document.body.style.display = 'none'; 110 | document.body.offsetHeight; 111 | document.body.style.display = ''; 112 | 113 | // run previous PagedConfig.after function if defined 114 | if (afterPaged) afterPaged(flow); 115 | 116 | // pagedownListener is a binding added by the chrome_print function 117 | // this binding exists only when chrome_print opens the html file 118 | if (window.pagedownListener) { 119 | // the html file is opened for printing 120 | // call the binding to signal to the R session that Paged.js has finished 121 | const tocList = flow.source.querySelector('.toc > ul'); 122 | const tocInfos = tocEntriesInfos(tocList); 123 | pagedownListener(JSON.stringify({ 124 | pagedjs: true, 125 | pages: flow.total, 126 | elapsedtime: flow.performance, 127 | tocInfos: tocInfos 128 | })); 129 | return; 130 | } 131 | if (sessionStorage.getItem('pagedown-scroll')) { 132 | // scroll to the last position before the page is reloaded 133 | window.scrollTo(0, sessionStorage.getItem('pagedown-scroll')); 134 | return; 135 | } 136 | if (window.location.hash) { 137 | const id = decodeURIComponent(window.location.hash).replace(/^#/, ''); 138 | document.getElementById(id).scrollIntoView({behavior: 'smooth'}); 139 | } 140 | }; 141 | })(); 142 | -------------------------------------------------------------------------------- /anderson-cv_files/paged-0.14/js/hooks.js: -------------------------------------------------------------------------------- 1 | // Hooks for paged.js 2 | { 3 | // Utils 4 | let pandocMeta, pandocMetaToString; 5 | { 6 | let el = document.getElementById('pandoc-meta'); 7 | pandocMeta = el ? JSON.parse(el.firstChild.data) : {}; 8 | } 9 | 10 | pandocMetaToString = meta => { 11 | let el = document.createElement('div'); 12 | el.innerHTML = meta; 13 | return el.innerText; 14 | }; 15 | 16 | let isString = value => { 17 | return typeof value === 'string' || value instanceof String; 18 | }; 19 | 20 | let isArray = value => { 21 | return value && typeof value === 'object' && value.constructor === Array; 22 | }; 23 | 24 | // This hook is an attempt to fix https://github.com/rstudio/pagedown/issues/131 25 | // Sometimes, the {break-after: avoid;} declaration applied on headers 26 | // lead to duplicated headers. I hate this bug. 27 | // This is linked to the way the HTML source is written 28 | // When we have the \n character like this:
\n

...

29 | // the header may be duplicated. 30 | // But, if we have

...

without any \n, the problem disappear 31 | // I think this handler can fix most of cases 32 | // Obviously, we cannot suppress all the \n in the HTML document 33 | // because carriage returns are important in
 elements.
 34 |   // Tested with Chrome 76.0.3809.100/Windows
 35 |   Paged.registerHandlers(class extends Paged.Handler {
 36 |     constructor(chunker, polisher, caller) {
 37 |       super(chunker, polisher, caller);
 38 |       this.carriageReturn = String.fromCharCode(10);
 39 |     }
 40 | 
 41 |     checkNode(node) {
 42 |       if (!node) return;
 43 |       if (node.nodeType !== 3) return;
 44 |       if (node.textContent === this.carriageReturn) {
 45 |         node.remove();
 46 |       }
 47 |     }
 48 | 
 49 |     afterParsed(parsed) {
 50 |       let template = document.querySelector('template').content;
 51 |       const breakAfterAvoidElements = template.querySelectorAll('[data-break-after="avoid"], [data-break-before="avoid"]');
 52 |       for (let el of breakAfterAvoidElements) {
 53 |         this.checkNode(el.previousSibling);
 54 |         this.checkNode(el.nextSibling);
 55 |       }
 56 |     }
 57 |   });
 58 | 
 59 |   // This hook creates a list of abbreviations
 60 |   // Note: we also could implement this feature using a Pandoc filter
 61 |   Paged.registerHandlers(class extends Paged.Handler {
 62 |     constructor(chunker, polisher, caller) {
 63 |       super(chunker, polisher, caller);
 64 |     }
 65 |     beforeParsed(content) {
 66 |       // Find the abbreviation nodes
 67 |       const abbrNodeList = content.querySelectorAll('abbr');
 68 | 
 69 |       // Return early if there is no abbreviation
 70 |       if (abbrNodeList.length === 0) return;
 71 | 
 72 |       // Store unique values of abbreviations, see https://github.com/rstudio/pagedown/issues/218
 73 |       let abbreviations = [];
 74 |       for (const {title, innerHTML} of abbrNodeList.values()) {
 75 |         if (abbreviations.find(el => el.title === title && el.innerHTML === innerHTML)) {
 76 |           continue;
 77 |         }
 78 |         abbreviations.push({title: title, innerHTML: innerHTML});
 79 |       }
 80 | 
 81 |       const loaTitle = pandocMeta['loa-title'] ? pandocMetaToString(pandocMeta['loa-title']) : 'List of Abbreviations';
 82 |       const loaId = 'LOA';
 83 |       const tocList = content.querySelector('.toc ul');
 84 |       let listOfAbbreviations = document.createElement('div');
 85 |       let descriptionList = document.createElement('dl');
 86 |       content.appendChild(listOfAbbreviations);
 87 |       listOfAbbreviations.id = loaId;
 88 |       listOfAbbreviations.classList.add('section', 'front-matter', 'level1', 'loa');
 89 |       listOfAbbreviations.innerHTML = '

' + loaTitle + '

'; 90 | listOfAbbreviations.appendChild(descriptionList); 91 | for(let abbr of abbreviations) { 92 | if(!abbr.title) continue; 93 | let term = document.createElement('dt'); 94 | let definition = document.createElement('dd'); 95 | descriptionList.appendChild(term); 96 | descriptionList.appendChild(definition); 97 | term.innerHTML = abbr.innerHTML; 98 | definition.innerText = abbr.title; 99 | } 100 | if (tocList) { 101 | const loaTOCItem = document.createElement('li'); 102 | loaTOCItem.innerHTML = '' + loaTitle + ''; 103 | tocList.appendChild(loaTOCItem); 104 | } 105 | } 106 | }); 107 | 108 | // This hook moves the sections of class front-matter in the div.front-matter-container 109 | Paged.registerHandlers(class extends Paged.Handler { 110 | constructor(chunker, polisher, caller) { 111 | super(chunker, polisher, caller); 112 | } 113 | 114 | beforeParsed(content) { 115 | const frontMatter = content.querySelector('.front-matter-container'); 116 | if (!frontMatter) return; 117 | 118 | // move front matter sections in the front matter container 119 | const frontMatterSections = content.querySelectorAll('.level1.front-matter'); 120 | for (const section of frontMatterSections) { 121 | frontMatter.appendChild(section); 122 | } 123 | 124 | // add the class front-matter-ref to any element 125 | // referring to an entry in the front matter 126 | const anchors = content.querySelectorAll('a[href^="#"]:not([href*=":"])'); 127 | for (const a of anchors) { 128 | const ref = a.getAttribute('href').replace(/^#/, ''); 129 | const element = content.getElementById(ref); 130 | if (frontMatter.contains(element)) a.classList.add('front-matter-ref'); 131 | } 132 | 133 | // update the toc, lof and lot for front matter sections 134 | const frontMatterSectionsLinks = content.querySelectorAll('.toc .front-matter-ref, .lof .front-matter-ref, .lot .front-matter-ref'); 135 | for (let i = frontMatterSectionsLinks.length - 1; i >= 0; i--) { 136 | const listItem = frontMatterSectionsLinks[i].parentNode; 137 | const list = listItem.parentNode; 138 | list.insertBefore(listItem, list.firstChild); 139 | } 140 | } 141 | }); 142 | 143 | // This hook expands the links in the lists of figures and tables 144 | Paged.registerHandlers(class extends Paged.Handler { 145 | constructor(chunker, polisher, caller) { 146 | super(chunker, polisher, caller); 147 | } 148 | 149 | beforeParsed(content) { 150 | const items = content.querySelectorAll('.lof li, .lot li'); 151 | for (const item of items) { 152 | const anchor = item.firstChild; 153 | anchor.innerText = item.innerText; 154 | item.innerText = ''; 155 | item.append(anchor); 156 | } 157 | } 158 | }); 159 | 160 | // This hook adds spans for leading symbols 161 | Paged.registerHandlers(class extends Paged.Handler { 162 | constructor(chunker, polisher, caller) { 163 | super(chunker, polisher, caller); 164 | } 165 | 166 | beforeParsed(content) { 167 | const anchors = content.querySelectorAll('.toc a, .lof a, .lot a'); 168 | for (const a of anchors) { 169 | a.innerHTML = a.innerHTML + ''; 170 | } 171 | } 172 | }); 173 | 174 | // This hook appends short titles spans 175 | Paged.registerHandlers(class extends Paged.Handler { 176 | constructor(chunker, polisher, caller) { 177 | super(chunker, polisher, caller); 178 | } 179 | 180 | beforeParsed(content) { 181 | /* A factory returning a function that appends short titles spans. 182 | The text content of these spans are reused for running titles (see default.css). 183 | Argument: level - An integer between 1 and 6. 184 | */ 185 | function appendShortTitleSpans(level) { 186 | return () => { 187 | const divs = Array.from(content.querySelectorAll('.level' + level)); 188 | 189 | function addSpan(div) { 190 | const mainHeader = div.getElementsByTagName('h' + level)[0]; 191 | if (!mainHeader) return; 192 | const mainTitle = mainHeader.textContent; 193 | const spanSectionNumber = mainHeader.getElementsByClassName('header-section-number')[0]; 194 | const mainNumber = !!spanSectionNumber ? spanSectionNumber.textContent : ''; 195 | const runningTitle = 'shortTitle' in div.dataset ? mainNumber + ' ' + div.dataset.shortTitle : mainTitle; 196 | const span = document.createElement('span'); 197 | span.className = 'shorttitle' + level; 198 | span.innerText = runningTitle; 199 | span.style.display = "none"; 200 | mainHeader.appendChild(span); 201 | if (level == 1 && div.querySelector('.level2') === null) { 202 | let span2 = document.createElement('span'); 203 | span2.className = 'shorttitle2'; 204 | span2.innerText = ' '; 205 | span2.style.display = "none"; 206 | span.insertAdjacentElement('afterend', span2); 207 | } 208 | } 209 | 210 | for (const div of divs) { 211 | addSpan(div); 212 | } 213 | }; 214 | } 215 | 216 | appendShortTitleSpans(1)(); 217 | appendShortTitleSpans(2)(); 218 | } 219 | }); 220 | 221 | // Footnotes support 222 | Paged.registerHandlers(class extends Paged.Handler { 223 | constructor(chunker, polisher, caller) { 224 | super(chunker, polisher, caller); 225 | 226 | this.splittedParagraphRefs = []; 227 | } 228 | 229 | beforeParsed(content) { 230 | // remove footnotes in toc, lof, lot 231 | // see https://github.com/rstudio/pagedown/issues/54 232 | let removeThese = content.querySelectorAll('.toc .footnote, .lof .footnote, .lot .footnote'); 233 | for (const el of removeThese) { 234 | el.remove(); 235 | } 236 | 237 | let footnotes = content.querySelectorAll('.footnote'); 238 | 239 | for (let footnote of footnotes) { 240 | let parentElement = footnote.parentElement; 241 | let footnoteCall = document.createElement('a'); 242 | let footnoteNumber = footnote.dataset.pagedownFootnoteNumber; 243 | 244 | footnoteCall.className = 'footnote-ref'; // same class as Pandoc 245 | footnoteCall.setAttribute('id', 'fnref' + footnoteNumber); // same notation as Pandoc 246 | footnoteCall.setAttribute('href', '#' + footnote.id); 247 | footnoteCall.innerHTML = '' + footnoteNumber +''; 248 | parentElement.insertBefore(footnoteCall, footnote); 249 | 250 | // Here comes a hack. Fortunately, it works with Chrome and FF. 251 | let handler = document.createElement('p'); 252 | handler.className = 'footnoteHandler'; 253 | parentElement.insertBefore(handler, footnote); 254 | handler.appendChild(footnote); 255 | handler.style.display = 'inline-block'; 256 | handler.style.width = '100%'; 257 | handler.style.float = 'right'; 258 | handler.style.pageBreakInside = 'avoid'; 259 | } 260 | } 261 | 262 | afterPageLayout(pageFragment, page, breakToken) { 263 | function hasItemParent(node) { 264 | if (node.parentElement === null) { 265 | return false; 266 | } else { 267 | if (node.parentElement.tagName === 'LI') { 268 | return true; 269 | } else { 270 | return hasItemParent(node.parentElement); 271 | } 272 | } 273 | } 274 | // If a li item is broken, we store the reference of the p child element 275 | // see https://github.com/rstudio/pagedown/issues/23#issue-376548000 276 | if (breakToken !== undefined) { 277 | if (breakToken.node.nodeName === "#text" && hasItemParent(breakToken.node)) { 278 | this.splittedParagraphRefs.push(breakToken.node.parentElement.dataset.ref); 279 | } 280 | } 281 | } 282 | 283 | afterRendered(pages) { 284 | for (let page of pages) { 285 | const footnotes = page.element.querySelectorAll('.footnote'); 286 | if (footnotes.length === 0) { 287 | continue; 288 | } 289 | 290 | const pageContent = page.element.querySelector('.pagedjs_page_content'); 291 | let hr = document.createElement('hr'); 292 | let footnoteArea = document.createElement('div'); 293 | 294 | pageContent.style.display = 'flex'; 295 | pageContent.style.flexDirection = 'column'; 296 | 297 | hr.className = 'footnote-break'; 298 | hr.style.marginTop = 'auto'; 299 | hr.style.marginBottom = 0; 300 | hr.style.marginLeft = 0; 301 | hr.style.marginRight = 'auto'; 302 | pageContent.appendChild(hr); 303 | 304 | footnoteArea.className = 'footnote-area'; 305 | pageContent.appendChild(footnoteArea); 306 | 307 | for (let footnote of footnotes) { 308 | let handler = footnote.parentElement; 309 | 310 | footnoteArea.appendChild(footnote); 311 | handler.parentNode.removeChild(handler); 312 | 313 | footnote.innerHTML = '' + footnote.dataset.pagedownFootnoteNumber + '' + footnote.innerHTML; 314 | footnote.style.fontSize = 'x-small'; 315 | footnote.style.marginTop = 0; 316 | footnote.style.marginBottom = 0; 317 | footnote.style.paddingTop = 0; 318 | footnote.style.paddingBottom = 0; 319 | footnote.style.display = 'block'; 320 | } 321 | } 322 | 323 | for (let ref of this.splittedParagraphRefs) { 324 | let paragraphFirstPage = document.querySelector('[data-split-to="' + ref + '"]'); 325 | // We test whether the paragraph is empty 326 | // see https://github.com/rstudio/pagedown/issues/23#issue-376548000 327 | if (paragraphFirstPage.innerText === "") { 328 | paragraphFirstPage.parentElement.style.display = "none"; 329 | let paragraphSecondPage = document.querySelector('[data-split-from="' + ref + '"]'); 330 | paragraphSecondPage.parentElement.style.setProperty('list-style', 'inherit', 'important'); 331 | } 332 | } 333 | } 334 | }); 335 | 336 | // Support for "Chapter " label on section with class `.chapter` 337 | Paged.registerHandlers(class extends Paged.Handler { 338 | constructor(chunker, polisher, caller) { 339 | super(chunker, polisher, caller); 340 | 341 | this.options = pandocMeta['chapter_name']; 342 | 343 | let styles; 344 | if (isString(this.options)) { 345 | this.options = pandocMetaToString(this.options); 346 | styles = ` 347 | :root { 348 | --chapter-name-before: "${this.options}"; 349 | } 350 | `; 351 | } 352 | if (isArray(this.options)) { 353 | this.options = this.options.map(pandocMetaToString); 354 | styles = ` 355 | :root { 356 | --chapter-name-before: "${this.options[0]}"; 357 | --chapter-name-after: "${this.options[1]}"; 358 | } 359 | `; 360 | } 361 | if (styles) polisher.insert(styles); 362 | } 363 | 364 | beforeParsed(content) { 365 | const tocAnchors = content.querySelectorAll('.toc a[href^="#"]:not([href*=":"]'); 366 | for (const anchor of tocAnchors) { 367 | const ref = anchor.getAttribute('href').replace(/^#/, ''); 368 | const element = content.getElementById(ref); 369 | if (element.classList.contains('chapter')) { 370 | anchor.classList.add('chapter-ref'); 371 | } 372 | } 373 | } 374 | }); 375 | 376 | // Main text line numbering, 377 | // see https://github.com/rstudio/pagedown/issues/115 378 | // Original idea: Julien Taquet, thanks! 379 | Paged.registerHandlers(class extends Paged.Handler { 380 | constructor(chunker, polisher, caller) { 381 | super(chunker, polisher, caller); 382 | 383 | // get the number-lines option from Pandoc metavariables 384 | this.options = pandocMeta['number-lines']; 385 | // quit early if the "number-lines" option is false or missing 386 | if (!this.options) return; 387 | // retrieve the selector if provided, otherwise use the default selector 388 | this.selector = this.options.selector ? pandocMetaToString(this.options.selector) : '.level1:not(.front-matter) h1, .level1 h2, .level1 h3, .level1 p'; 389 | 390 | const styles = ` 391 | :root { 392 | --line-numbers-padding-right: 10px; 393 | --line-numbers-font-size: 8pt; 394 | } 395 | .pagedown-linenumbers-container { 396 | position: absolute; 397 | margin-top: var(--pagedjs-margin-top); 398 | right: calc(var(--pagedjs-width) - var(--pagedjs-margin-left)); 399 | } 400 | .maintextlinenumbers { 401 | position: absolute; 402 | right: 0; 403 | text-align: right; 404 | padding-right: var(--line-numbers-padding-right); 405 | font-size: var(--line-numbers-font-size); 406 | } 407 | `; 408 | polisher.insert(styles); 409 | 410 | this.resetLinesCounter(); 411 | } 412 | 413 | appendLineNumbersContainer(page) { 414 | const pagebox = page.element.querySelector('.pagedjs_pagebox'); 415 | const lineNumbersContainer = document.createElement('div'); 416 | lineNumbersContainer.classList.add('pagedown-linenumbers-container'); 417 | 418 | return pagebox.appendChild(lineNumbersContainer); 419 | } 420 | 421 | lineHeight(element) { 422 | // If the document stylesheet does not define a value for line-height, 423 | // Blink returns "normal". Therefore, parseInt may return NaN. 424 | return parseInt(getComputedStyle(element).lineHeight); 425 | } 426 | 427 | innerHeight(element) { 428 | let outerHeight = element.getBoundingClientRect().height; 429 | let {borderTopWidth, 430 | borderBottomWidth, 431 | paddingTop, 432 | paddingBottom} = getComputedStyle(element); 433 | 434 | borderTopWidth = parseFloat(borderTopWidth); 435 | borderBottomWidth = parseFloat(borderBottomWidth); 436 | paddingTop = parseFloat(paddingTop); 437 | paddingBottom = parseFloat(paddingBottom); 438 | 439 | return Math.round(outerHeight - borderTopWidth - borderBottomWidth - paddingTop - paddingBottom); 440 | } 441 | 442 | arrayOfInt(from, length) { 443 | // adapted from https://stackoverflow.com/a/50234108/6500804 444 | return Array.from(Array(length).keys(), n => n + from); 445 | } 446 | 447 | incrementLinesCounter(value) { 448 | this.linesCounter = this.linesCounter + value; 449 | } 450 | 451 | resetLinesCounter() { 452 | this.linesCounter = 0; 453 | } 454 | 455 | isDisplayMath(element) { 456 | const nodes = element.childNodes; 457 | if (nodes.length != 1) return false; 458 | return (nodes[0].nodeName === 'SPAN') && (nodes[0].classList.value === 'math display'); 459 | } 460 | 461 | afterRendered(pages) { 462 | if (!this.options) return; 463 | 464 | for (let page of pages) { 465 | const lineNumbersContainer = this.appendLineNumbersContainer(page); 466 | const pageAreaY = page.area.getBoundingClientRect().y; 467 | let elementsToNumber = page.area.querySelectorAll(this.selector); 468 | 469 | for (let element of elementsToNumber) { 470 | // Do not add line numbers for display math environment 471 | if (this.isDisplayMath(element)) continue; 472 | 473 | // Try to retrieve line height 474 | const lineHeight = this.lineHeight(element); 475 | // Test against lineHeight method returns NaN 476 | if (!lineHeight) { 477 | console.warn('Failed to compute line height value on "' + page.id + '".'); 478 | continue; 479 | } 480 | 481 | const innerHeight = this.innerHeight(element); 482 | 483 | // Number of lines estimation 484 | // There is no built-in method to detect the number of lines in a block. 485 | // The main caveat is that an actual line height can differ from 486 | // the line-height CSS property. 487 | // Mixed fonts, subscripts, superscripts, inline math... can increase 488 | // the actual line height. 489 | // Here, we divide the inner height of the block by the line-height 490 | // computed property and round to the floor to take into account that 491 | // sometimes the actual line height is greater than its property value. 492 | // This is far from perfect and can be easily broken especially by 493 | // inline math. 494 | const nLines = Math.floor(innerHeight / lineHeight); 495 | 496 | // do not add line numbers for void paragraphs 497 | if (nLines <= 0) continue; 498 | 499 | const linenumbers = document.createElement('div'); 500 | lineNumbersContainer.appendChild(linenumbers); 501 | linenumbers.classList.add('maintextlinenumbers'); 502 | 503 | const elementY = element.getBoundingClientRect().y; 504 | linenumbers.style.top = (elementY - pageAreaY) + 'px'; 505 | 506 | const cs = getComputedStyle(element); 507 | const paddingTop = parseFloat(cs.paddingTop) + parseFloat(cs.borderTopWidth); 508 | linenumbers.style.paddingTop = paddingTop + 'px'; 509 | 510 | linenumbers.style.lineHeight = cs.lineHeight; 511 | 512 | linenumbers.innerHTML = this.arrayOfInt(this.linesCounter + 1, nLines) 513 | .reduce((t, v) => t + '
' + v); 514 | this.incrementLinesCounter(nLines); 515 | } 516 | 517 | if (this.options['reset-page']) { 518 | this.resetLinesCounter(); 519 | } 520 | } 521 | } 522 | }); 523 | 524 | // Clean links to avoid impossible line breaking of long urls in a justified text 525 | // Author: Julien Taquet (Paged.js core team) 526 | // see https://github.com/spyrales/gouvdown/issues/37 527 | Paged.registerHandlers(class extends Paged.Handler { 528 | constructor(chunker, polisher, caller) { 529 | super(chunker, polisher, caller); 530 | } 531 | beforeParsed(content) { 532 | // add wbr to / in links 533 | const links = content.querySelectorAll('a[href^="http"], a[href^="www"]'); 534 | links.forEach(link => { 535 | // Rerun to avoid large spaces. 536 | // Break after a colon or a double slash (//) 537 | // or before a single slash (/), a tilde (~), a period, a comma, a hyphen, 538 | // an underline (_), a question mark, a number sign, or a percent symbol. 539 | const content = link.textContent; 540 | let printableUrl = content.replace(/\/\//g, "//\u003Cwbr\u003E"); 541 | printableUrl = printableUrl.replace(/\,/g, ",\u003Cwbr\u003E"); 542 | // put wbr around everything. 543 | printableUrl = printableUrl.replace( 544 | /(\/|\~|\-|\.|\,|\_|\?|\#|\%)/g, 545 | "\u003Cwbr\u003E$1" 546 | ); 547 | // turn hyphen in non breaking hyphen 548 | printableUrl = printableUrl.replace(/\-/g, "\u003Cwbr\u003E‑"); 549 | link.setAttribute("data-print-url", printableUrl); 550 | link.innerHTML = printableUrl; 551 | }); 552 | } 553 | }); 554 | } 555 | -------------------------------------------------------------------------------- /anderson-cv_files/paged-0.15/js/config.js: -------------------------------------------------------------------------------- 1 | // Configuration script for paged.js 2 | 3 | (function() { 4 | // Retrieve previous config object if defined 5 | window.PagedConfig = window.PagedConfig || {}; 6 | const {before: beforePaged, after: afterPaged} = window.PagedConfig; 7 | 8 | // utils 9 | const insertCSS = text => { 10 | let style = document.createElement('style'); 11 | style.type = 'text/css'; 12 | style.appendChild(document.createTextNode(text)); 13 | document.head.appendChild(style); 14 | }; 15 | 16 | // Util function for front and back covers images 17 | const insertCSSForCover = type => { 18 | const links = document.querySelectorAll('link[id^=' + type + ']'); 19 | if (!links.length) return; 20 | const re = new RegExp(type + '-\\d+'); 21 | let text = ':root {--' + type + ': var(--' + type + '-1);'; 22 | for (const link of links) { 23 | text += '--' + re.exec(link.id)[0] + ': url("' + link.href + '");'; 24 | } 25 | text += '}'; 26 | insertCSS(text); 27 | }; 28 | 29 | const insertPageBreaksCSS = () => { 30 | insertCSS(` 31 | .page-break-after {break-after: page;} 32 | .page-break-before {break-before: page;} 33 | `); 34 | }; 35 | 36 | window.PagedConfig.before = async () => { 37 | // Front and back covers support 38 | let frontCover = document.querySelector('.front-cover'); 39 | let backCover = document.querySelector('.back-cover'); 40 | if (frontCover) document.body.prepend(frontCover); 41 | if (backCover) document.body.append(backCover); 42 | insertCSSForCover('front-cover'); 43 | insertCSSForCover('back-cover'); 44 | insertPageBreaksCSS(); 45 | 46 | if (beforePaged) await beforePaged(); 47 | }; 48 | 49 | // from https://stackoverflow.com/q/21647928 50 | const toUTF16BE = x => { 51 | let res = ''; 52 | for (i=0; i < x.length; i++) { 53 | let hex = x.charCodeAt(i).toString(16); 54 | hex = ('000' + hex).slice(-4); 55 | res += hex 56 | } 57 | res = 'feff' + res ; 58 | return res; 59 | } 60 | 61 | const findPage = el => { 62 | while (el.parentElement) { 63 | el = el.parentElement; 64 | if (el.getAttribute('data-page-number')) { 65 | return parseInt(el.getAttribute('data-page-number')); 66 | } 67 | } 68 | return null; 69 | }; 70 | 71 | const tocEntriesInfos = ul => { 72 | let result = []; // where we store the results 73 | // if there is no element, return an empty array 74 | if (!ul) { 75 | return result; 76 | } 77 | const tocEntries = ul.children; // tocEntries are 'li' elements 78 | 79 | for (const li of tocEntries) { 80 | // Since parts entries in TOC have no anchor, 81 | // do not use them in the PDF outline. 82 | if (li.classList.contains('part')) { 83 | continue; 84 | } 85 | 86 | // get the title and encode it in UTF16BE (pdfmark is encoded in UTF16BE with BOM) 87 | const title = toUTF16BE(li.querySelector('a').textContent); 88 | 89 | // get the page number 90 | const href = li.querySelector('a').getAttribute('href'); 91 | const el = document.getElementById(href.substring(1)); 92 | const page = findPage(el); 93 | 94 | // get the children 95 | children = tocEntriesInfos(li.querySelector('ul')); 96 | 97 | result.push({ 98 | title: title, 99 | page: page, 100 | children: children 101 | }); 102 | } 103 | 104 | return result; 105 | }; 106 | window.PagedConfig.after = (flow) => { 107 | // force redraw, see https://github.com/rstudio/pagedown/issues/35#issuecomment-475905361 108 | // and https://stackoverflow.com/a/24753578/6500804 109 | document.body.style.display = 'none'; 110 | document.body.offsetHeight; 111 | document.body.style.display = ''; 112 | 113 | // run previous PagedConfig.after function if defined 114 | if (afterPaged) afterPaged(flow); 115 | 116 | // pagedownListener is a binding added by the chrome_print function 117 | // this binding exists only when chrome_print opens the html file 118 | if (window.pagedownListener) { 119 | // the html file is opened for printing 120 | // call the binding to signal to the R session that Paged.js has finished 121 | const tocList = flow.source.querySelector('.toc > ul'); 122 | const tocInfos = tocEntriesInfos(tocList); 123 | pagedownListener(JSON.stringify({ 124 | pagedjs: true, 125 | pages: flow.total, 126 | elapsedtime: flow.performance, 127 | tocInfos: tocInfos 128 | })); 129 | return; 130 | } 131 | if (sessionStorage.getItem('pagedown-scroll')) { 132 | // scroll to the last position before the page is reloaded 133 | window.scrollTo(0, sessionStorage.getItem('pagedown-scroll')); 134 | return; 135 | } 136 | if (window.location.hash) { 137 | const id = decodeURIComponent(window.location.hash).replace(/^#/, ''); 138 | document.getElementById(id).scrollIntoView({behavior: 'smooth'}); 139 | } 140 | }; 141 | })(); 142 | -------------------------------------------------------------------------------- /anderson-cv_files/paged-0.15/js/hooks.js: -------------------------------------------------------------------------------- 1 | // Hooks for paged.js 2 | { 3 | // Utils 4 | let pandocMeta, pandocMetaToString; 5 | { 6 | let el = document.getElementById('pandoc-meta'); 7 | pandocMeta = el ? JSON.parse(el.firstChild.data) : {}; 8 | } 9 | 10 | pandocMetaToString = meta => { 11 | let el = document.createElement('div'); 12 | el.innerHTML = meta; 13 | return el.innerText; 14 | }; 15 | 16 | let isString = value => { 17 | return typeof value === 'string' || value instanceof String; 18 | }; 19 | 20 | let isArray = value => { 21 | return value && typeof value === 'object' && value.constructor === Array; 22 | }; 23 | 24 | // This hook is an attempt to fix https://github.com/rstudio/pagedown/issues/131 25 | // Sometimes, the {break-after: avoid;} declaration applied on headers 26 | // lead to duplicated headers. I hate this bug. 27 | // This is linked to the way the HTML source is written 28 | // When we have the \n character like this:
\n

...

29 | // the header may be duplicated. 30 | // But, if we have

...

without any \n, the problem disappear 31 | // I think this handler can fix most of cases 32 | // Obviously, we cannot suppress all the \n in the HTML document 33 | // because carriage returns are important in
 elements.
 34 |   // Tested with Chrome 76.0.3809.100/Windows
 35 |   Paged.registerHandlers(class extends Paged.Handler {
 36 |     constructor(chunker, polisher, caller) {
 37 |       super(chunker, polisher, caller);
 38 |       this.carriageReturn = String.fromCharCode(10);
 39 |     }
 40 | 
 41 |     checkNode(node) {
 42 |       if (!node) return;
 43 |       if (node.nodeType !== 3) return;
 44 |       if (node.textContent === this.carriageReturn) {
 45 |         node.remove();
 46 |       }
 47 |     }
 48 | 
 49 |     afterParsed(parsed) {
 50 |       let template = document.querySelector('template').content;
 51 |       const breakAfterAvoidElements = template.querySelectorAll('[data-break-after="avoid"], [data-break-before="avoid"]');
 52 |       for (let el of breakAfterAvoidElements) {
 53 |         this.checkNode(el.previousSibling);
 54 |         this.checkNode(el.nextSibling);
 55 |       }
 56 |     }
 57 |   });
 58 | 
 59 |   // This hook creates a list of abbreviations
 60 |   // Note: we also could implement this feature using a Pandoc filter
 61 |   Paged.registerHandlers(class extends Paged.Handler {
 62 |     constructor(chunker, polisher, caller) {
 63 |       super(chunker, polisher, caller);
 64 |     }
 65 |     beforeParsed(content) {
 66 |       // Find the abbreviation nodes
 67 |       const abbrNodeList = content.querySelectorAll('abbr');
 68 | 
 69 |       // Return early if there is no abbreviation
 70 |       if (abbrNodeList.length === 0) return;
 71 | 
 72 |       // Store unique values of abbreviations, see https://github.com/rstudio/pagedown/issues/218
 73 |       let abbreviations = [];
 74 |       for (const {title, innerHTML} of abbrNodeList.values()) {
 75 |         if (abbreviations.find(el => el.title === title && el.innerHTML === innerHTML)) {
 76 |           continue;
 77 |         }
 78 |         abbreviations.push({title: title, innerHTML: innerHTML});
 79 |       }
 80 | 
 81 |       const loaTitle = pandocMeta['loa-title'] ? pandocMetaToString(pandocMeta['loa-title']) : 'List of Abbreviations';
 82 |       const loaId = 'LOA';
 83 |       const tocList = content.querySelector('.toc ul');
 84 |       let listOfAbbreviations = document.createElement('div');
 85 |       let descriptionList = document.createElement('dl');
 86 |       content.appendChild(listOfAbbreviations);
 87 |       listOfAbbreviations.id = loaId;
 88 |       listOfAbbreviations.classList.add('section', 'front-matter', 'level1', 'loa');
 89 |       listOfAbbreviations.innerHTML = '

' + loaTitle + '

'; 90 | listOfAbbreviations.appendChild(descriptionList); 91 | for(let abbr of abbreviations) { 92 | if(!abbr.title) continue; 93 | let term = document.createElement('dt'); 94 | let definition = document.createElement('dd'); 95 | descriptionList.appendChild(term); 96 | descriptionList.appendChild(definition); 97 | term.innerHTML = abbr.innerHTML; 98 | definition.innerText = abbr.title; 99 | } 100 | if (tocList) { 101 | const loaTOCItem = document.createElement('li'); 102 | loaTOCItem.innerHTML = '' + loaTitle + ''; 103 | tocList.appendChild(loaTOCItem); 104 | } 105 | } 106 | }); 107 | 108 | // This hook moves the sections of class front-matter in the div.front-matter-container 109 | Paged.registerHandlers(class extends Paged.Handler { 110 | constructor(chunker, polisher, caller) { 111 | super(chunker, polisher, caller); 112 | } 113 | 114 | beforeParsed(content) { 115 | const frontMatter = content.querySelector('.front-matter-container'); 116 | if (!frontMatter) return; 117 | 118 | // move front matter sections in the front matter container 119 | const frontMatterSections = content.querySelectorAll('.level1.front-matter'); 120 | for (const section of frontMatterSections) { 121 | frontMatter.appendChild(section); 122 | } 123 | 124 | // add the class front-matter-ref to any element 125 | // referring to an entry in the front matter 126 | const anchors = content.querySelectorAll('a[href^="#"]:not([href*=":"])'); 127 | for (const a of anchors) { 128 | const ref = a.getAttribute('href').replace(/^#/, ''); 129 | const element = content.getElementById(ref); 130 | if (frontMatter.contains(element)) a.classList.add('front-matter-ref'); 131 | } 132 | 133 | // update the toc, lof and lot for front matter sections 134 | const frontMatterSectionsLinks = content.querySelectorAll('.toc .front-matter-ref, .lof .front-matter-ref, .lot .front-matter-ref'); 135 | for (let i = frontMatterSectionsLinks.length - 1; i >= 0; i--) { 136 | const listItem = frontMatterSectionsLinks[i].parentNode; 137 | const list = listItem.parentNode; 138 | list.insertBefore(listItem, list.firstChild); 139 | } 140 | } 141 | }); 142 | 143 | // This hook expands the links in the lists of figures and tables 144 | Paged.registerHandlers(class extends Paged.Handler { 145 | constructor(chunker, polisher, caller) { 146 | super(chunker, polisher, caller); 147 | } 148 | 149 | beforeParsed(content) { 150 | const items = content.querySelectorAll('.lof li, .lot li'); 151 | for (const item of items) { 152 | const anchor = item.firstChild; 153 | anchor.innerText = item.innerText; 154 | item.innerText = ''; 155 | item.append(anchor); 156 | } 157 | } 158 | }); 159 | 160 | // This hook adds spans for leading symbols 161 | Paged.registerHandlers(class extends Paged.Handler { 162 | constructor(chunker, polisher, caller) { 163 | super(chunker, polisher, caller); 164 | } 165 | 166 | beforeParsed(content) { 167 | const anchors = content.querySelectorAll('.toc a, .lof a, .lot a'); 168 | for (const a of anchors) { 169 | a.innerHTML = a.innerHTML + ''; 170 | } 171 | } 172 | }); 173 | 174 | // This hook appends short titles spans 175 | Paged.registerHandlers(class extends Paged.Handler { 176 | constructor(chunker, polisher, caller) { 177 | super(chunker, polisher, caller); 178 | } 179 | 180 | beforeParsed(content) { 181 | /* A factory returning a function that appends short titles spans. 182 | The text content of these spans are reused for running titles (see default.css). 183 | Argument: level - An integer between 1 and 6. 184 | */ 185 | function appendShortTitleSpans(level) { 186 | return () => { 187 | const divs = Array.from(content.querySelectorAll('.level' + level)); 188 | 189 | function addSpan(div) { 190 | const mainHeader = div.getElementsByTagName('h' + level)[0]; 191 | if (!mainHeader) return; 192 | const mainTitle = mainHeader.textContent; 193 | const spanSectionNumber = mainHeader.getElementsByClassName('header-section-number')[0]; 194 | const mainNumber = !!spanSectionNumber ? spanSectionNumber.textContent : ''; 195 | const runningTitle = 'shortTitle' in div.dataset ? mainNumber + ' ' + div.dataset.shortTitle : mainTitle; 196 | const span = document.createElement('span'); 197 | span.className = 'shorttitle' + level; 198 | span.innerText = runningTitle; 199 | span.style.display = "none"; 200 | mainHeader.appendChild(span); 201 | if (level == 1 && div.querySelector('.level2') === null) { 202 | let span2 = document.createElement('span'); 203 | span2.className = 'shorttitle2'; 204 | span2.innerText = ' '; 205 | span2.style.display = "none"; 206 | span.insertAdjacentElement('afterend', span2); 207 | } 208 | } 209 | 210 | for (const div of divs) { 211 | addSpan(div); 212 | } 213 | }; 214 | } 215 | 216 | appendShortTitleSpans(1)(); 217 | appendShortTitleSpans(2)(); 218 | } 219 | }); 220 | 221 | // Footnotes support 222 | Paged.registerHandlers(class extends Paged.Handler { 223 | constructor(chunker, polisher, caller) { 224 | super(chunker, polisher, caller); 225 | 226 | this.splittedParagraphRefs = []; 227 | } 228 | 229 | beforeParsed(content) { 230 | // remove footnotes in toc, lof, lot 231 | // see https://github.com/rstudio/pagedown/issues/54 232 | let removeThese = content.querySelectorAll('.toc .footnote, .lof .footnote, .lot .footnote'); 233 | for (const el of removeThese) { 234 | el.remove(); 235 | } 236 | 237 | let footnotes = content.querySelectorAll('.footnote'); 238 | 239 | for (let footnote of footnotes) { 240 | let parentElement = footnote.parentElement; 241 | let footnoteCall = document.createElement('a'); 242 | let footnoteNumber = footnote.dataset.pagedownFootnoteNumber; 243 | 244 | footnoteCall.className = 'footnote-ref'; // same class as Pandoc 245 | footnoteCall.setAttribute('id', 'fnref' + footnoteNumber); // same notation as Pandoc 246 | footnoteCall.setAttribute('href', '#' + footnote.id); 247 | footnoteCall.innerHTML = '' + footnoteNumber +''; 248 | parentElement.insertBefore(footnoteCall, footnote); 249 | 250 | // Here comes a hack. Fortunately, it works with Chrome and FF. 251 | let handler = document.createElement('p'); 252 | handler.className = 'footnoteHandler'; 253 | parentElement.insertBefore(handler, footnote); 254 | handler.appendChild(footnote); 255 | handler.style.display = 'inline-block'; 256 | handler.style.width = '100%'; 257 | handler.style.float = 'right'; 258 | handler.style.pageBreakInside = 'avoid'; 259 | } 260 | } 261 | 262 | afterPageLayout(pageFragment, page, breakToken) { 263 | function hasItemParent(node) { 264 | if (node.parentElement === null) { 265 | return false; 266 | } else { 267 | if (node.parentElement.tagName === 'LI') { 268 | return true; 269 | } else { 270 | return hasItemParent(node.parentElement); 271 | } 272 | } 273 | } 274 | // If a li item is broken, we store the reference of the p child element 275 | // see https://github.com/rstudio/pagedown/issues/23#issue-376548000 276 | if (breakToken !== undefined) { 277 | if (breakToken.node.nodeName === "#text" && hasItemParent(breakToken.node)) { 278 | this.splittedParagraphRefs.push(breakToken.node.parentElement.dataset.ref); 279 | } 280 | } 281 | } 282 | 283 | afterRendered(pages) { 284 | for (let page of pages) { 285 | const footnotes = page.element.querySelectorAll('.footnote'); 286 | if (footnotes.length === 0) { 287 | continue; 288 | } 289 | 290 | const pageContent = page.element.querySelector('.pagedjs_page_content'); 291 | let hr = document.createElement('hr'); 292 | let footnoteArea = document.createElement('div'); 293 | 294 | pageContent.style.display = 'flex'; 295 | pageContent.style.flexDirection = 'column'; 296 | 297 | hr.className = 'footnote-break'; 298 | hr.style.marginTop = 'auto'; 299 | hr.style.marginBottom = 0; 300 | hr.style.marginLeft = 0; 301 | hr.style.marginRight = 'auto'; 302 | pageContent.appendChild(hr); 303 | 304 | footnoteArea.className = 'footnote-area'; 305 | pageContent.appendChild(footnoteArea); 306 | 307 | for (let footnote of footnotes) { 308 | let handler = footnote.parentElement; 309 | 310 | footnoteArea.appendChild(footnote); 311 | handler.parentNode.removeChild(handler); 312 | 313 | footnote.innerHTML = '' + footnote.dataset.pagedownFootnoteNumber + '' + footnote.innerHTML; 314 | footnote.style.fontSize = 'x-small'; 315 | footnote.style.marginTop = 0; 316 | footnote.style.marginBottom = 0; 317 | footnote.style.paddingTop = 0; 318 | footnote.style.paddingBottom = 0; 319 | footnote.style.display = 'block'; 320 | } 321 | } 322 | 323 | for (let ref of this.splittedParagraphRefs) { 324 | let paragraphFirstPage = document.querySelector('[data-split-to="' + ref + '"]'); 325 | // We test whether the paragraph is empty 326 | // see https://github.com/rstudio/pagedown/issues/23#issue-376548000 327 | if (paragraphFirstPage.innerText === "") { 328 | paragraphFirstPage.parentElement.style.display = "none"; 329 | let paragraphSecondPage = document.querySelector('[data-split-from="' + ref + '"]'); 330 | paragraphSecondPage.parentElement.style.setProperty('list-style', 'inherit', 'important'); 331 | } 332 | } 333 | } 334 | }); 335 | 336 | // Support for "Chapter " label on section with class `.chapter` 337 | Paged.registerHandlers(class extends Paged.Handler { 338 | constructor(chunker, polisher, caller) { 339 | super(chunker, polisher, caller); 340 | 341 | this.options = pandocMeta['chapter_name']; 342 | 343 | let styles; 344 | if (isString(this.options)) { 345 | this.options = pandocMetaToString(this.options); 346 | styles = ` 347 | :root { 348 | --chapter-name-before: "${this.options}"; 349 | } 350 | `; 351 | } 352 | if (isArray(this.options)) { 353 | this.options = this.options.map(pandocMetaToString); 354 | styles = ` 355 | :root { 356 | --chapter-name-before: "${this.options[0]}"; 357 | --chapter-name-after: "${this.options[1]}"; 358 | } 359 | `; 360 | } 361 | if (styles) polisher.insert(styles); 362 | } 363 | 364 | beforeParsed(content) { 365 | const tocAnchors = content.querySelectorAll('.toc a[href^="#"]:not([href*=":"]'); 366 | for (const anchor of tocAnchors) { 367 | const ref = anchor.getAttribute('href').replace(/^#/, ''); 368 | const element = content.getElementById(ref); 369 | if (element.classList.contains('chapter')) { 370 | anchor.classList.add('chapter-ref'); 371 | } 372 | } 373 | } 374 | }); 375 | 376 | // Main text line numbering, 377 | // see https://github.com/rstudio/pagedown/issues/115 378 | // Original idea: Julien Taquet, thanks! 379 | Paged.registerHandlers(class extends Paged.Handler { 380 | constructor(chunker, polisher, caller) { 381 | super(chunker, polisher, caller); 382 | 383 | // get the number-lines option from Pandoc metavariables 384 | this.options = pandocMeta['number-lines']; 385 | // quit early if the "number-lines" option is false or missing 386 | if (!this.options) return; 387 | // retrieve the selector if provided, otherwise use the default selector 388 | this.selector = this.options.selector ? pandocMetaToString(this.options.selector) : '.level1:not(.front-matter) h1, .level1 h2, .level1 h3, .level1 p'; 389 | 390 | const styles = ` 391 | :root { 392 | --line-numbers-padding-right: 10px; 393 | --line-numbers-font-size: 8pt; 394 | } 395 | .pagedown-linenumbers-container { 396 | position: absolute; 397 | margin-top: var(--pagedjs-margin-top); 398 | right: calc(var(--pagedjs-width) - var(--pagedjs-margin-left)); 399 | } 400 | .maintextlinenumbers { 401 | position: absolute; 402 | right: 0; 403 | text-align: right; 404 | padding-right: var(--line-numbers-padding-right); 405 | font-size: var(--line-numbers-font-size); 406 | } 407 | `; 408 | polisher.insert(styles); 409 | 410 | this.resetLinesCounter(); 411 | } 412 | 413 | appendLineNumbersContainer(page) { 414 | const pagebox = page.element.querySelector('.pagedjs_pagebox'); 415 | const lineNumbersContainer = document.createElement('div'); 416 | lineNumbersContainer.classList.add('pagedown-linenumbers-container'); 417 | 418 | return pagebox.appendChild(lineNumbersContainer); 419 | } 420 | 421 | lineHeight(element) { 422 | // If the document stylesheet does not define a value for line-height, 423 | // Blink returns "normal". Therefore, parseInt may return NaN. 424 | return parseInt(getComputedStyle(element).lineHeight); 425 | } 426 | 427 | innerHeight(element) { 428 | let outerHeight = element.getBoundingClientRect().height; 429 | let {borderTopWidth, 430 | borderBottomWidth, 431 | paddingTop, 432 | paddingBottom} = getComputedStyle(element); 433 | 434 | borderTopWidth = parseFloat(borderTopWidth); 435 | borderBottomWidth = parseFloat(borderBottomWidth); 436 | paddingTop = parseFloat(paddingTop); 437 | paddingBottom = parseFloat(paddingBottom); 438 | 439 | return Math.round(outerHeight - borderTopWidth - borderBottomWidth - paddingTop - paddingBottom); 440 | } 441 | 442 | arrayOfInt(from, length) { 443 | // adapted from https://stackoverflow.com/a/50234108/6500804 444 | return Array.from(Array(length).keys(), n => n + from); 445 | } 446 | 447 | incrementLinesCounter(value) { 448 | this.linesCounter = this.linesCounter + value; 449 | } 450 | 451 | resetLinesCounter() { 452 | this.linesCounter = 0; 453 | } 454 | 455 | isDisplayMath(element) { 456 | const nodes = element.childNodes; 457 | if (nodes.length != 1) return false; 458 | return (nodes[0].nodeName === 'SPAN') && (nodes[0].classList.value === 'math display'); 459 | } 460 | 461 | afterRendered(pages) { 462 | if (!this.options) return; 463 | 464 | for (let page of pages) { 465 | const lineNumbersContainer = this.appendLineNumbersContainer(page); 466 | const pageAreaY = page.area.getBoundingClientRect().y; 467 | let elementsToNumber = page.area.querySelectorAll(this.selector); 468 | 469 | for (let element of elementsToNumber) { 470 | // Do not add line numbers for display math environment 471 | if (this.isDisplayMath(element)) continue; 472 | 473 | // Try to retrieve line height 474 | const lineHeight = this.lineHeight(element); 475 | // Test against lineHeight method returns NaN 476 | if (!lineHeight) { 477 | console.warn('Failed to compute line height value on "' + page.id + '".'); 478 | continue; 479 | } 480 | 481 | const innerHeight = this.innerHeight(element); 482 | 483 | // Number of lines estimation 484 | // There is no built-in method to detect the number of lines in a block. 485 | // The main caveat is that an actual line height can differ from 486 | // the line-height CSS property. 487 | // Mixed fonts, subscripts, superscripts, inline math... can increase 488 | // the actual line height. 489 | // Here, we divide the inner height of the block by the line-height 490 | // computed property and round to the floor to take into account that 491 | // sometimes the actual line height is greater than its property value. 492 | // This is far from perfect and can be easily broken especially by 493 | // inline math. 494 | const nLines = Math.floor(innerHeight / lineHeight); 495 | 496 | // do not add line numbers for void paragraphs 497 | if (nLines <= 0) continue; 498 | 499 | const linenumbers = document.createElement('div'); 500 | lineNumbersContainer.appendChild(linenumbers); 501 | linenumbers.classList.add('maintextlinenumbers'); 502 | 503 | const elementY = element.getBoundingClientRect().y; 504 | linenumbers.style.top = (elementY - pageAreaY) + 'px'; 505 | 506 | const cs = getComputedStyle(element); 507 | const paddingTop = parseFloat(cs.paddingTop) + parseFloat(cs.borderTopWidth); 508 | linenumbers.style.paddingTop = paddingTop + 'px'; 509 | 510 | linenumbers.style.lineHeight = cs.lineHeight; 511 | 512 | linenumbers.innerHTML = this.arrayOfInt(this.linesCounter + 1, nLines) 513 | .reduce((t, v) => t + '
' + v); 514 | this.incrementLinesCounter(nLines); 515 | } 516 | 517 | if (this.options['reset-page']) { 518 | this.resetLinesCounter(); 519 | } 520 | } 521 | } 522 | }); 523 | 524 | // Clean links to avoid impossible line breaking of long urls in a justified text 525 | // Author: Julien Taquet (Paged.js core team) 526 | // see https://github.com/spyrales/gouvdown/issues/37 527 | Paged.registerHandlers(class extends Paged.Handler { 528 | constructor(chunker, polisher, caller) { 529 | super(chunker, polisher, caller); 530 | } 531 | beforeParsed(content) { 532 | // add wbr to / in links 533 | const links = content.querySelectorAll('a[href^="http"], a[href^="www"]'); 534 | links.forEach(link => { 535 | // Rerun to avoid large spaces. 536 | // Break after a colon or a double slash (//) 537 | // or before a single slash (/), a tilde (~), a period, a comma, a hyphen, 538 | // an underline (_), a question mark, a number sign, or a percent symbol. 539 | const content = link.textContent; 540 | if (!(link.childElementCount === 0 && content.match(/^http|^www/))) return; 541 | let printableUrl = content.replace(/\/\//g, "//\u003Cwbr\u003E"); 542 | printableUrl = printableUrl.replace(/\,/g, ",\u003Cwbr\u003E"); 543 | // put wbr around everything. 544 | printableUrl = printableUrl.replace( 545 | /(\/|\~|\-|\.|\,|\_|\?|\#|\%)/g, 546 | "\u003Cwbr\u003E$1" 547 | ); 548 | // turn hyphen in non breaking hyphen 549 | printableUrl = printableUrl.replace(/\-/g, "\u003Cwbr\u003E‑"); 550 | link.setAttribute("data-print-url", printableUrl); 551 | link.innerHTML = printableUrl; 552 | }); 553 | } 554 | }); 555 | } 556 | -------------------------------------------------------------------------------- /anderson-cv_files/paged-0.19/js/config.js: -------------------------------------------------------------------------------- 1 | // Configuration script for paged.js 2 | 3 | (function() { 4 | // Retrieve previous config object if defined 5 | window.PagedConfig = window.PagedConfig || {}; 6 | const {before: beforePaged, after: afterPaged} = window.PagedConfig; 7 | 8 | // utils 9 | const insertCSS = text => { 10 | let style = document.createElement('style'); 11 | style.type = 'text/css'; 12 | style.appendChild(document.createTextNode(text)); 13 | document.head.appendChild(style); 14 | }; 15 | 16 | // Util function for front and back covers images 17 | const insertCSSForCover = type => { 18 | const links = document.querySelectorAll('link[id^=' + type + ']'); 19 | if (!links.length) return; 20 | const re = new RegExp(type + '-\\d+'); 21 | let text = ':root {--' + type + ': var(--' + type + '-1);'; 22 | for (const link of links) { 23 | text += '--' + re.exec(link.id)[0] + ': url("' + link.href + '");'; 24 | } 25 | text += '}'; 26 | insertCSS(text); 27 | }; 28 | 29 | const insertPageBreaksCSS = () => { 30 | insertCSS(` 31 | .page-break-after {break-after: page;} 32 | .page-break-before {break-before: page;} 33 | `); 34 | }; 35 | 36 | window.PagedConfig.before = async () => { 37 | // Front and back covers support 38 | let frontCover = document.querySelector('.front-cover'); 39 | let backCover = document.querySelector('.back-cover'); 40 | if (frontCover) document.body.prepend(frontCover); 41 | if (backCover) document.body.append(backCover); 42 | insertCSSForCover('front-cover'); 43 | insertCSSForCover('back-cover'); 44 | insertPageBreaksCSS(); 45 | 46 | if (beforePaged) await beforePaged(); 47 | }; 48 | 49 | // from https://stackoverflow.com/q/21647928 50 | const toUTF16BE = x => { 51 | let res = ''; 52 | for (i=0; i < x.length; i++) { 53 | let hex = x.charCodeAt(i).toString(16); 54 | hex = ('000' + hex).slice(-4); 55 | res += hex 56 | } 57 | res = 'feff' + res ; 58 | return res; 59 | } 60 | 61 | const findPage = el => { 62 | while (el.parentElement) { 63 | el = el.parentElement; 64 | if (el.getAttribute('data-page-number')) { 65 | return parseInt(el.getAttribute('data-page-number')); 66 | } 67 | } 68 | return null; 69 | }; 70 | 71 | const tocEntriesInfos = ul => { 72 | let result = []; // where we store the results 73 | // if there is no element, return an empty array 74 | if (!ul) { 75 | return result; 76 | } 77 | const tocEntries = ul.children; // tocEntries are 'li' elements 78 | 79 | for (const li of tocEntries) { 80 | // Since parts entries in TOC have no anchor, 81 | // do not use them in the PDF outline. 82 | if (li.classList.contains('part')) { 83 | continue; 84 | } 85 | 86 | // get the title and encode it in UTF16BE (pdfmark is encoded in UTF16BE with BOM) 87 | const title = toUTF16BE(li.querySelector('a').textContent); 88 | 89 | // get the page number 90 | const href = li.querySelector('a').getAttribute('href'); 91 | const el = document.getElementById(href.substring(1)); 92 | const page = findPage(el); 93 | 94 | // get the children 95 | children = tocEntriesInfos(li.querySelector('ul')); 96 | 97 | result.push({ 98 | title: title, 99 | page: page, 100 | children: children 101 | }); 102 | } 103 | 104 | return result; 105 | }; 106 | window.PagedConfig.after = (flow) => { 107 | // force redraw, see https://github.com/rstudio/pagedown/issues/35#issuecomment-475905361 108 | // and https://stackoverflow.com/a/24753578/6500804 109 | document.body.style.display = 'none'; 110 | document.body.offsetHeight; 111 | document.body.style.display = ''; 112 | 113 | // run previous PagedConfig.after function if defined 114 | if (afterPaged) afterPaged(flow); 115 | 116 | // pagedownListener is a binding added by the chrome_print function 117 | // this binding exists only when chrome_print opens the html file 118 | if (window.pagedownListener) { 119 | // the html file is opened for printing 120 | // call the binding to signal to the R session that Paged.js has finished 121 | const tocList = flow.source.querySelector('.toc > ul'); 122 | const tocInfos = tocEntriesInfos(tocList); 123 | pagedownListener(JSON.stringify({ 124 | pagedjs: true, 125 | pages: flow.total, 126 | elapsedtime: flow.performance, 127 | tocInfos: tocInfos 128 | })); 129 | return; 130 | } 131 | if (sessionStorage.getItem('pagedown-scroll')) { 132 | // scroll to the last position before the page is reloaded 133 | window.scrollTo(0, sessionStorage.getItem('pagedown-scroll')); 134 | return; 135 | } 136 | if (window.location.hash) { 137 | const id = decodeURIComponent(window.location.hash).replace(/^#/, ''); 138 | document.getElementById(id).scrollIntoView({behavior: 'smooth'}); 139 | } 140 | }; 141 | })(); 142 | -------------------------------------------------------------------------------- /anderson-cv_files/paged-0.19/js/hooks.js: -------------------------------------------------------------------------------- 1 | // Hooks for paged.js 2 | { 3 | // Utils 4 | let pandocMeta, pandocMetaToString; 5 | { 6 | let el = document.getElementById('pandoc-meta'); 7 | pandocMeta = el ? JSON.parse(el.firstChild.data) : {}; 8 | } 9 | 10 | pandocMetaToString = meta => { 11 | let el = document.createElement('div'); 12 | el.innerHTML = meta; 13 | return el.innerText; 14 | }; 15 | 16 | let isString = value => { 17 | return typeof value === 'string' || value instanceof String; 18 | }; 19 | 20 | let isArray = value => { 21 | return value && typeof value === 'object' && value.constructor === Array; 22 | }; 23 | 24 | // This hook is an attempt to fix https://github.com/rstudio/pagedown/issues/131 25 | // Sometimes, the {break-after: avoid;} declaration applied on headers 26 | // lead to duplicated headers. I hate this bug. 27 | // This is linked to the way the HTML source is written 28 | // When we have the \n character like this:
\n

...

29 | // the header may be duplicated. 30 | // But, if we have

...

without any \n, the problem disappear 31 | // I think this handler can fix most of cases 32 | // Obviously, we cannot suppress all the \n in the HTML document 33 | // because carriage returns are important in
 elements.
 34 |   // Tested with Chrome 76.0.3809.100/Windows
 35 |   Paged.registerHandlers(class extends Paged.Handler {
 36 |     constructor(chunker, polisher, caller) {
 37 |       super(chunker, polisher, caller);
 38 |       this.carriageReturn = String.fromCharCode(10);
 39 |     }
 40 | 
 41 |     checkNode(node) {
 42 |       if (!node) return;
 43 |       if (node.nodeType !== 3) return;
 44 |       if (node.textContent === this.carriageReturn) {
 45 |         node.remove();
 46 |       }
 47 |     }
 48 | 
 49 |     afterParsed(parsed) {
 50 |       let template = document.querySelector('template').content;
 51 |       const breakAfterAvoidElements = template.querySelectorAll('[data-break-after="avoid"], [data-break-before="avoid"]');
 52 |       for (let el of breakAfterAvoidElements) {
 53 |         this.checkNode(el.previousSibling);
 54 |         this.checkNode(el.nextSibling);
 55 |       }
 56 |     }
 57 |   });
 58 | 
 59 |   // This hook creates a list of abbreviations
 60 |   // Note: we also could implement this feature using a Pandoc filter
 61 |   Paged.registerHandlers(class extends Paged.Handler {
 62 |     constructor(chunker, polisher, caller) {
 63 |       super(chunker, polisher, caller);
 64 |     }
 65 |     beforeParsed(content) {
 66 |       // Find the abbreviation nodes
 67 |       const abbrNodeList = content.querySelectorAll('abbr');
 68 | 
 69 |       // Return early if there is no abbreviation
 70 |       if (abbrNodeList.length === 0) return;
 71 | 
 72 |       // Store unique values of abbreviations, see https://github.com/rstudio/pagedown/issues/218
 73 |       let abbreviations = [];
 74 |       for (const {title, innerHTML} of abbrNodeList.values()) {
 75 |         if (abbreviations.find(el => el.title === title && el.innerHTML === innerHTML)) {
 76 |           continue;
 77 |         }
 78 |         abbreviations.push({title: title, innerHTML: innerHTML});
 79 |       }
 80 | 
 81 |       const loaTitle = pandocMeta['loa-title'] ? pandocMetaToString(pandocMeta['loa-title']) : 'List of Abbreviations';
 82 |       const loaId = 'LOA';
 83 |       const tocList = content.querySelector('.toc ul');
 84 |       let listOfAbbreviations = document.createElement('div');
 85 |       let descriptionList = document.createElement('dl');
 86 |       content.appendChild(listOfAbbreviations);
 87 |       listOfAbbreviations.id = loaId;
 88 |       listOfAbbreviations.classList.add('section', 'front-matter', 'level1', 'loa');
 89 |       listOfAbbreviations.innerHTML = '

' + loaTitle + '

'; 90 | listOfAbbreviations.appendChild(descriptionList); 91 | for(let abbr of abbreviations) { 92 | if(!abbr.title) continue; 93 | let term = document.createElement('dt'); 94 | let definition = document.createElement('dd'); 95 | descriptionList.appendChild(term); 96 | descriptionList.appendChild(definition); 97 | term.innerHTML = abbr.innerHTML; 98 | definition.innerText = abbr.title; 99 | } 100 | if (tocList) { 101 | const loaTOCItem = document.createElement('li'); 102 | loaTOCItem.innerHTML = '' + loaTitle + ''; 103 | tocList.appendChild(loaTOCItem); 104 | } 105 | } 106 | }); 107 | 108 | // This hook moves the sections of class front-matter in the div.front-matter-container 109 | Paged.registerHandlers(class extends Paged.Handler { 110 | constructor(chunker, polisher, caller) { 111 | super(chunker, polisher, caller); 112 | } 113 | 114 | beforeParsed(content) { 115 | const frontMatter = content.querySelector('.front-matter-container'); 116 | if (!frontMatter) return; 117 | 118 | // move front matter sections in the front matter container 119 | const frontMatterSections = content.querySelectorAll('.level1.front-matter'); 120 | for (const section of frontMatterSections) { 121 | frontMatter.appendChild(section); 122 | } 123 | 124 | // add the class front-matter-ref to any element 125 | // referring to an entry in the front matter 126 | const anchors = content.querySelectorAll('a[href^="#"]:not([href*=":"])'); 127 | for (const a of anchors) { 128 | const ref = a.getAttribute('href').replace(/^#/, ''); 129 | const element = content.getElementById(ref); 130 | if (frontMatter.contains(element)) a.classList.add('front-matter-ref'); 131 | } 132 | 133 | // update the toc, lof and lot for front matter sections 134 | const frontMatterSectionsLinks = content.querySelectorAll('.toc .front-matter-ref, .lof .front-matter-ref, .lot .front-matter-ref'); 135 | for (let i = frontMatterSectionsLinks.length - 1; i >= 0; i--) { 136 | const listItem = frontMatterSectionsLinks[i].parentNode; 137 | const list = listItem.parentNode; 138 | list.insertBefore(listItem, list.firstChild); 139 | } 140 | } 141 | }); 142 | 143 | // This hook expands the links in the lists of figures and tables 144 | Paged.registerHandlers(class extends Paged.Handler { 145 | constructor(chunker, polisher, caller) { 146 | super(chunker, polisher, caller); 147 | } 148 | 149 | beforeParsed(content) { 150 | const items = content.querySelectorAll('.lof li, .lot li'); 151 | for (const item of items) { 152 | const anchor = item.firstChild; 153 | anchor.innerText = item.innerText; 154 | item.innerText = ''; 155 | item.append(anchor); 156 | } 157 | } 158 | }); 159 | 160 | // This hook adds spans for leading symbols 161 | Paged.registerHandlers(class extends Paged.Handler { 162 | constructor(chunker, polisher, caller) { 163 | super(chunker, polisher, caller); 164 | } 165 | 166 | beforeParsed(content) { 167 | const anchors = content.querySelectorAll('.toc a, .lof a, .lot a'); 168 | for (const a of anchors) { 169 | a.innerHTML = a.innerHTML + ''; 170 | } 171 | } 172 | }); 173 | 174 | // This hook appends short titles spans 175 | Paged.registerHandlers(class extends Paged.Handler { 176 | constructor(chunker, polisher, caller) { 177 | super(chunker, polisher, caller); 178 | } 179 | 180 | beforeParsed(content) { 181 | /* A factory returning a function that appends short titles spans. 182 | The text content of these spans are reused for running titles (see default.css). 183 | Argument: level - An integer between 1 and 6. 184 | */ 185 | function appendShortTitleSpans(level) { 186 | return () => { 187 | const divs = Array.from(content.querySelectorAll('.level' + level)); 188 | 189 | function addSpan(div) { 190 | const mainHeader = div.getElementsByTagName('h' + level)[0]; 191 | if (!mainHeader) return; 192 | const mainTitle = mainHeader.textContent; 193 | const spanSectionNumber = mainHeader.getElementsByClassName('header-section-number')[0]; 194 | const mainNumber = !!spanSectionNumber ? spanSectionNumber.textContent : ''; 195 | const runningTitle = 'shortTitle' in div.dataset ? mainNumber + ' ' + div.dataset.shortTitle : mainTitle; 196 | const span = document.createElement('span'); 197 | span.className = 'shorttitle' + level; 198 | span.innerText = runningTitle; 199 | span.style.display = "none"; 200 | mainHeader.appendChild(span); 201 | if (level == 1 && div.querySelector('.level2') === null) { 202 | let span2 = document.createElement('span'); 203 | span2.className = 'shorttitle2'; 204 | span2.innerText = ' '; 205 | span2.style.display = "none"; 206 | span.insertAdjacentElement('afterend', span2); 207 | } 208 | } 209 | 210 | for (const div of divs) { 211 | addSpan(div); 212 | } 213 | }; 214 | } 215 | 216 | appendShortTitleSpans(1)(); 217 | appendShortTitleSpans(2)(); 218 | } 219 | }); 220 | 221 | // Footnotes support 222 | Paged.registerHandlers(class extends Paged.Handler { 223 | constructor(chunker, polisher, caller) { 224 | super(chunker, polisher, caller); 225 | 226 | this.splittedParagraphRefs = []; 227 | } 228 | 229 | beforeParsed(content) { 230 | // remove footnotes in toc, lof, lot 231 | // see https://github.com/rstudio/pagedown/issues/54 232 | let removeThese = content.querySelectorAll('.toc .footnote, .lof .footnote, .lot .footnote'); 233 | for (const el of removeThese) { 234 | el.remove(); 235 | } 236 | 237 | let footnotes = content.querySelectorAll('.footnote'); 238 | 239 | for (let footnote of footnotes) { 240 | let parentElement = footnote.parentElement; 241 | let footnoteCall = document.createElement('a'); 242 | let footnoteNumber = footnote.dataset.pagedownFootnoteNumber; 243 | 244 | footnoteCall.className = 'footnote-ref'; // same class as Pandoc 245 | footnoteCall.setAttribute('id', 'fnref' + footnoteNumber); // same notation as Pandoc 246 | footnoteCall.setAttribute('href', '#' + footnote.id); 247 | footnoteCall.innerHTML = '' + footnoteNumber +''; 248 | parentElement.insertBefore(footnoteCall, footnote); 249 | 250 | // Here comes a hack. Fortunately, it works with Chrome and FF. 251 | let handler = document.createElement('p'); 252 | handler.className = 'footnoteHandler'; 253 | parentElement.insertBefore(handler, footnote); 254 | handler.appendChild(footnote); 255 | handler.style.display = 'inline-block'; 256 | handler.style.width = '100%'; 257 | handler.style.float = 'right'; 258 | handler.style.pageBreakInside = 'avoid'; 259 | } 260 | } 261 | 262 | afterPageLayout(pageFragment, page, breakToken) { 263 | function hasItemParent(node) { 264 | if (node.parentElement === null) { 265 | return false; 266 | } else { 267 | if (node.parentElement.tagName === 'LI') { 268 | return true; 269 | } else { 270 | return hasItemParent(node.parentElement); 271 | } 272 | } 273 | } 274 | // If a li item is broken, we store the reference of the p child element 275 | // see https://github.com/rstudio/pagedown/issues/23#issue-376548000 276 | if (breakToken !== undefined) { 277 | if (breakToken.node.nodeName === "#text" && hasItemParent(breakToken.node)) { 278 | this.splittedParagraphRefs.push(breakToken.node.parentElement.dataset.ref); 279 | } 280 | } 281 | } 282 | 283 | afterRendered(pages) { 284 | for (let page of pages) { 285 | const footnotes = page.element.querySelectorAll('.footnote'); 286 | if (footnotes.length === 0) { 287 | continue; 288 | } 289 | 290 | const pageContent = page.element.querySelector('.pagedjs_page_content'); 291 | let hr = document.createElement('hr'); 292 | let footnoteArea = document.createElement('div'); 293 | 294 | pageContent.style.display = 'flex'; 295 | pageContent.style.flexDirection = 'column'; 296 | 297 | hr.className = 'footnote-break'; 298 | hr.style.marginTop = 'auto'; 299 | hr.style.marginBottom = 0; 300 | hr.style.marginLeft = 0; 301 | hr.style.marginRight = 'auto'; 302 | pageContent.appendChild(hr); 303 | 304 | footnoteArea.className = 'footnote-area'; 305 | pageContent.appendChild(footnoteArea); 306 | 307 | for (let footnote of footnotes) { 308 | let handler = footnote.parentElement; 309 | 310 | footnoteArea.appendChild(footnote); 311 | handler.parentNode.removeChild(handler); 312 | 313 | footnote.innerHTML = '' + footnote.dataset.pagedownFootnoteNumber + '' + footnote.innerHTML; 314 | footnote.style.fontSize = 'x-small'; 315 | footnote.style.marginTop = 0; 316 | footnote.style.marginBottom = 0; 317 | footnote.style.paddingTop = 0; 318 | footnote.style.paddingBottom = 0; 319 | footnote.style.display = 'block'; 320 | } 321 | } 322 | 323 | for (let ref of this.splittedParagraphRefs) { 324 | let paragraphFirstPage = document.querySelector('[data-split-to="' + ref + '"]'); 325 | // We test whether the paragraph is empty 326 | // see https://github.com/rstudio/pagedown/issues/23#issue-376548000 327 | if (paragraphFirstPage.innerText === "") { 328 | paragraphFirstPage.parentElement.style.display = "none"; 329 | let paragraphSecondPage = document.querySelector('[data-split-from="' + ref + '"]'); 330 | paragraphSecondPage.parentElement.style.setProperty('list-style', 'inherit', 'important'); 331 | } 332 | } 333 | } 334 | }); 335 | 336 | // Support for "Chapter " label on section with class `.chapter` 337 | Paged.registerHandlers(class extends Paged.Handler { 338 | constructor(chunker, polisher, caller) { 339 | super(chunker, polisher, caller); 340 | 341 | this.options = pandocMeta['chapter_name']; 342 | 343 | let styles; 344 | if (isString(this.options)) { 345 | this.options = pandocMetaToString(this.options); 346 | styles = ` 347 | :root { 348 | --chapter-name-before: "${this.options}"; 349 | } 350 | `; 351 | } 352 | if (isArray(this.options)) { 353 | this.options = this.options.map(pandocMetaToString); 354 | styles = ` 355 | :root { 356 | --chapter-name-before: "${this.options[0]}"; 357 | --chapter-name-after: "${this.options[1]}"; 358 | } 359 | `; 360 | } 361 | if (styles) polisher.insert(styles); 362 | } 363 | 364 | beforeParsed(content) { 365 | const tocAnchors = content.querySelectorAll('.toc a[href^="#"]:not([href*=":"]'); 366 | for (const anchor of tocAnchors) { 367 | const ref = anchor.getAttribute('href').replace(/^#/, ''); 368 | const element = content.getElementById(ref); 369 | if (element.classList.contains('chapter')) { 370 | anchor.classList.add('chapter-ref'); 371 | } 372 | } 373 | } 374 | }); 375 | 376 | // Main text line numbering, 377 | // see https://github.com/rstudio/pagedown/issues/115 378 | // Original idea: Julien Taquet, thanks! 379 | Paged.registerHandlers(class extends Paged.Handler { 380 | constructor(chunker, polisher, caller) { 381 | super(chunker, polisher, caller); 382 | 383 | // get the number-lines option from Pandoc metavariables 384 | this.options = pandocMeta['number-lines']; 385 | // quit early if the "number-lines" option is false or missing 386 | if (!this.options) return; 387 | // retrieve the selector if provided, otherwise use the default selector 388 | this.selector = this.options.selector ? pandocMetaToString(this.options.selector) : '.level1:not(.front-matter) h1, .level1 h2, .level1 h3, .level1 p'; 389 | 390 | const styles = ` 391 | :root { 392 | --line-numbers-padding-right: 10px; 393 | --line-numbers-font-size: 8pt; 394 | } 395 | .pagedown-linenumbers-container { 396 | position: absolute; 397 | margin-top: var(--pagedjs-margin-top); 398 | right: calc(var(--pagedjs-width) - var(--pagedjs-margin-left)); 399 | } 400 | .maintextlinenumbers { 401 | position: absolute; 402 | right: 0; 403 | text-align: right; 404 | padding-right: var(--line-numbers-padding-right); 405 | font-size: var(--line-numbers-font-size); 406 | } 407 | `; 408 | polisher.insert(styles); 409 | 410 | this.resetLinesCounter(); 411 | } 412 | 413 | appendLineNumbersContainer(page) { 414 | const pagebox = page.element.querySelector('.pagedjs_pagebox'); 415 | const lineNumbersContainer = document.createElement('div'); 416 | lineNumbersContainer.classList.add('pagedown-linenumbers-container'); 417 | 418 | return pagebox.appendChild(lineNumbersContainer); 419 | } 420 | 421 | lineHeight(element) { 422 | // If the document stylesheet does not define a value for line-height, 423 | // Blink returns "normal". Therefore, parseInt may return NaN. 424 | return parseInt(getComputedStyle(element).lineHeight); 425 | } 426 | 427 | innerHeight(element) { 428 | let outerHeight = element.getBoundingClientRect().height; 429 | let {borderTopWidth, 430 | borderBottomWidth, 431 | paddingTop, 432 | paddingBottom} = getComputedStyle(element); 433 | 434 | borderTopWidth = parseFloat(borderTopWidth); 435 | borderBottomWidth = parseFloat(borderBottomWidth); 436 | paddingTop = parseFloat(paddingTop); 437 | paddingBottom = parseFloat(paddingBottom); 438 | 439 | return Math.round(outerHeight - borderTopWidth - borderBottomWidth - paddingTop - paddingBottom); 440 | } 441 | 442 | arrayOfInt(from, length) { 443 | // adapted from https://stackoverflow.com/a/50234108/6500804 444 | return Array.from(Array(length).keys(), n => n + from); 445 | } 446 | 447 | incrementLinesCounter(value) { 448 | this.linesCounter = this.linesCounter + value; 449 | } 450 | 451 | resetLinesCounter() { 452 | this.linesCounter = 0; 453 | } 454 | 455 | isDisplayMath(element) { 456 | const nodes = element.childNodes; 457 | if (nodes.length != 1) return false; 458 | return (nodes[0].nodeName === 'SPAN') && (nodes[0].classList.value === 'math display'); 459 | } 460 | 461 | afterRendered(pages) { 462 | if (!this.options) return; 463 | 464 | for (let page of pages) { 465 | const lineNumbersContainer = this.appendLineNumbersContainer(page); 466 | const pageAreaY = page.area.getBoundingClientRect().y; 467 | let elementsToNumber = page.area.querySelectorAll(this.selector); 468 | 469 | for (let element of elementsToNumber) { 470 | // Do not add line numbers for display math environment 471 | if (this.isDisplayMath(element)) continue; 472 | 473 | // Try to retrieve line height 474 | const lineHeight = this.lineHeight(element); 475 | // Test against lineHeight method returns NaN 476 | if (!lineHeight) { 477 | console.warn('Failed to compute line height value on "' + page.id + '".'); 478 | continue; 479 | } 480 | 481 | const innerHeight = this.innerHeight(element); 482 | 483 | // Number of lines estimation 484 | // There is no built-in method to detect the number of lines in a block. 485 | // The main caveat is that an actual line height can differ from 486 | // the line-height CSS property. 487 | // Mixed fonts, subscripts, superscripts, inline math... can increase 488 | // the actual line height. 489 | // Here, we divide the inner height of the block by the line-height 490 | // computed property and round to the floor to take into account that 491 | // sometimes the actual line height is greater than its property value. 492 | // This is far from perfect and can be easily broken especially by 493 | // inline math. 494 | const nLines = Math.floor(innerHeight / lineHeight); 495 | 496 | // do not add line numbers for void paragraphs 497 | if (nLines <= 0) continue; 498 | 499 | const linenumbers = document.createElement('div'); 500 | lineNumbersContainer.appendChild(linenumbers); 501 | linenumbers.classList.add('maintextlinenumbers'); 502 | 503 | const elementY = element.getBoundingClientRect().y; 504 | linenumbers.style.top = (elementY - pageAreaY) + 'px'; 505 | 506 | const cs = getComputedStyle(element); 507 | const paddingTop = parseFloat(cs.paddingTop) + parseFloat(cs.borderTopWidth); 508 | linenumbers.style.paddingTop = paddingTop + 'px'; 509 | 510 | linenumbers.style.lineHeight = cs.lineHeight; 511 | 512 | linenumbers.innerHTML = this.arrayOfInt(this.linesCounter + 1, nLines) 513 | .reduce((t, v) => t + '
' + v); 514 | this.incrementLinesCounter(nLines); 515 | } 516 | 517 | if (this.options['reset-page']) { 518 | this.resetLinesCounter(); 519 | } 520 | } 521 | } 522 | }); 523 | 524 | // Clean links to avoid impossible line breaking of long urls in a justified text 525 | // Author: Julien Taquet (Paged.js core team) 526 | // see https://github.com/spyrales/gouvdown/issues/37 527 | Paged.registerHandlers(class extends Paged.Handler { 528 | constructor(chunker, polisher, caller) { 529 | super(chunker, polisher, caller); 530 | } 531 | beforeParsed(content) { 532 | // add wbr to / in links 533 | const links = content.querySelectorAll('a[href^="http"], a[href^="www"]'); 534 | links.forEach(link => { 535 | // Rerun to avoid large spaces. 536 | // Break after a colon or a double slash (//) 537 | // or before a single slash (/), a tilde (~), a period, a comma, a hyphen, 538 | // an underline (_), a question mark, a number sign, or a percent symbol. 539 | const content = link.textContent; 540 | if (!(link.childElementCount === 0 && content.match(/^http|^www/))) return; 541 | let printableUrl = content.replace(/\/\//g, "//\u003Cwbr\u003E"); 542 | printableUrl = printableUrl.replace(/\,/g, ",\u003Cwbr\u003E"); 543 | // put wbr around everything. 544 | printableUrl = printableUrl.replace( 545 | /(\/|\~|\-|\.|\,|\_|\?|\#|\%)/g, 546 | "\u003Cwbr\u003E$1" 547 | ); 548 | // turn hyphen in non breaking hyphen 549 | printableUrl = printableUrl.replace(/\-/g, "\u003Cwbr\u003E‑"); 550 | link.setAttribute("data-print-url", printableUrl); 551 | link.innerHTML = printableUrl; 552 | }); 553 | } 554 | }); 555 | 556 | // Repeat table headers on multiple pages 557 | // Authors: Julien Taquet, Lucas Maciuga and Tafael Caixeta, see https://gitlab.coko.foundation/pagedjs/pagedjs/-/issues/84 558 | // TODO: remove this hook when Paged.js integrates this feature 559 | Paged.registerHandlers(class RepeatingTableHeadersHandler extends Paged.Handler { 560 | 561 | constructor(chunker, polisher, caller) { 562 | super(chunker, polisher, caller); 563 | this.splitTablesRefs = []; 564 | } 565 | 566 | afterPageLayout(pageElement, page, breakToken, chunker) { 567 | this.chunker = chunker; 568 | this.splitTablesRefs = []; 569 | 570 | if (breakToken) { 571 | const node = breakToken.node; 572 | const tables = this.findAllAncestors(node, "table"); 573 | if (node.tagName === "TABLE") { 574 | tables.push(node); 575 | } 576 | 577 | if (tables.length > 0) { 578 | this.splitTablesRefs = tables.map(t => t.dataset.ref); 579 | 580 | //checks if split inside thead and if so, set breakToken to next sibling element 581 | let thead = node.tagName === "THEAD" ? node : this.findFirstAncestor(node, "thead"); 582 | if (thead) { 583 | let lastTheadNode = thead.hasChildNodes() ? thead.lastChild : thead; 584 | breakToken.node = this.nodeAfter(lastTheadNode, chunker.source); 585 | } 586 | 587 | this.hideEmptyTables(pageElement, node); 588 | } 589 | } 590 | } 591 | 592 | hideEmptyTables(pageElement, breakTokenNode) { 593 | this.splitTablesRefs.forEach(ref => { 594 | let table = pageElement.querySelector("[data-ref='" + ref + "']"); 595 | if (table) { 596 | let sourceBody = table.querySelector("tbody > tr"); 597 | if (!sourceBody || this.refEquals(sourceBody.firstElementChild, breakTokenNode)) { 598 | table.style.visibility = "hidden"; 599 | table.style.position = "absolute"; 600 | let lineSpacer = table.nextSibling; 601 | if (lineSpacer) { 602 | lineSpacer.style.visibility = "hidden"; 603 | lineSpacer.style.position = "absolute"; 604 | } 605 | } 606 | } 607 | }); 608 | } 609 | 610 | refEquals(a, b) { 611 | return a && a.dataset && b && b.dataset && a.dataset.ref === b.dataset.ref; 612 | } 613 | 614 | findFirstAncestor(element, selector) { 615 | while (element.parentNode && element.parentNode.nodeType === 1) { 616 | if (element.parentNode.matches(selector)) { 617 | return element.parentNode; 618 | } 619 | element = element.parentNode; 620 | } 621 | return null; 622 | } 623 | 624 | findAllAncestors(element, selector) { 625 | const ancestors = []; 626 | while (element.parentNode && element.parentNode.nodeType === 1) { 627 | if (element.parentNode.matches(selector)) { 628 | ancestors.unshift(element.parentNode); 629 | } 630 | element = element.parentNode; 631 | } 632 | return ancestors; 633 | } 634 | 635 | // The addition of repeating Table Headers is done here because this hook is triggered before overflow handling 636 | layout(rendered, layout) { 637 | this.splitTablesRefs.forEach(ref => { 638 | const renderedTable = rendered.querySelector("[data-ref='" + ref + "']"); 639 | if (renderedTable && renderedTable.hasAttribute("data-split-from")) { 640 | // this event can be triggered multiple times 641 | // added a flag repeated-headers to control when table headers already repeated in current page. 642 | if (!renderedTable.getAttribute("repeated-headers")) { 643 | const sourceTable = this.chunker.source.querySelector("[data-ref='" + ref + "']"); 644 | this.repeatColgroup(sourceTable, renderedTable); 645 | this.repeatTHead(sourceTable, renderedTable); 646 | renderedTable.setAttribute("repeated-headers", true); 647 | } 648 | } 649 | }); 650 | } 651 | 652 | repeatColgroup(sourceTable, renderedTable) { 653 | let colgroup = sourceTable.querySelectorAll("colgroup"); 654 | let firstChild = renderedTable.firstChild; 655 | colgroup.forEach((colgroup) => { 656 | let clonedColgroup = colgroup.cloneNode(true); 657 | renderedTable.insertBefore(clonedColgroup, firstChild); 658 | }); 659 | } 660 | 661 | repeatTHead(sourceTable, renderedTable) { 662 | let thead = sourceTable.querySelector("thead"); 663 | if (thead) { 664 | let clonedThead = thead.cloneNode(true); 665 | renderedTable.insertBefore(clonedThead, renderedTable.firstChild); 666 | } 667 | } 668 | 669 | // the functions below are from pagedjs utils/dom.js 670 | nodeAfter(node, limiter) { 671 | if (limiter && node === limiter) { 672 | return; 673 | } 674 | let significantNode = this.nextSignificantNode(node); 675 | if (significantNode) { 676 | return significantNode; 677 | } 678 | if (node.parentNode) { 679 | while ((node = node.parentNode)) { 680 | if (limiter && node === limiter) { 681 | return; 682 | } 683 | significantNode = this.nextSignificantNode(node); 684 | if (significantNode) { 685 | return significantNode; 686 | } 687 | } 688 | } 689 | } 690 | 691 | nextSignificantNode(sib) { 692 | while ((sib = sib.nextSibling)) { 693 | if (!this.isIgnorable(sib)) return sib; 694 | } 695 | return null; 696 | } 697 | 698 | isIgnorable(node) { 699 | return (node.nodeType === 8) || // A comment node 700 | ((node.nodeType === 3) && this.isAllWhitespace(node)); // a text node, all whitespace 701 | } 702 | 703 | isAllWhitespace(node) { 704 | return !(/[^\t\n\r ]/.test(node.textContent)); 705 | } 706 | }); 707 | 708 | } 709 | -------------------------------------------------------------------------------- /anderson-cv_files/paged-0.5/js/config.js: -------------------------------------------------------------------------------- 1 | // Configuration script for paged.js 2 | 3 | (function() { 4 | // Retrieve previous config object if defined 5 | window.PagedConfig = window.PagedConfig || {}; 6 | const {before: beforePaged, after: afterPaged} = window.PagedConfig; 7 | 8 | // utils 9 | const insertCSS = text => { 10 | let style = document.createElement('style'); 11 | style.type = 'text/css'; 12 | style.appendChild(document.createTextNode(text)); 13 | document.head.appendChild(style); 14 | }; 15 | 16 | // Util function for front and back covers images 17 | const insertCSSForCover = type => { 18 | const links = document.querySelectorAll('link[id^=' + type + ']'); 19 | if (!links.length) return; 20 | const re = new RegExp(type + '-\\d+'); 21 | let text = ':root {--' + type + ': var(--' + type + '-1);'; 22 | for (const link of links) { 23 | text += '--' + re.exec(link.id)[0] + ': url("' + link.href + '");'; 24 | } 25 | text += '}'; 26 | insertCSS(text); 27 | }; 28 | 29 | window.PagedConfig.before = async () => { 30 | // Front and back covers support 31 | let frontCover = document.querySelector('.front-cover'); 32 | let backCover = document.querySelector('.back-cover'); 33 | if (frontCover) document.body.prepend(frontCover); 34 | if (backCover) document.body.append(backCover); 35 | insertCSSForCover('front-cover'); 36 | insertCSSForCover('back-cover'); 37 | 38 | if (beforePaged) await beforePaged(); 39 | }; 40 | 41 | window.PagedConfig.after = (flow) => { 42 | // force redraw, see https://github.com/rstudio/pagedown/issues/35#issuecomment-475905361 43 | // and https://stackoverflow.com/a/24753578/6500804 44 | document.body.style.display = 'none'; 45 | document.body.offsetHeight; 46 | document.body.style.display = ''; 47 | 48 | // run previous PagedConfig.after function if defined 49 | if (afterPaged) afterPaged(flow); 50 | 51 | // pagedownListener is a binding added by the chrome_print function 52 | // this binding exists only when chrome_print opens the html file 53 | if (window.pagedownListener) { 54 | // the html file is opened for printing 55 | // call the binding to signal to the R session that Paged.js has finished 56 | pagedownListener(JSON.stringify({ 57 | pagedjs: true, 58 | pages: flow.total, 59 | elapsedtime: flow.performance 60 | })); 61 | return; 62 | } 63 | if (sessionStorage.getItem('pagedown-scroll')) { 64 | // scroll to the last position before the page is reloaded 65 | window.scrollTo(0, sessionStorage.getItem('pagedown-scroll')); 66 | return; 67 | } 68 | if (window.location.hash) { 69 | const id = window.location.hash.replace(/^#/, ''); 70 | document.getElementById(id).scrollIntoView({behavior: 'smooth'}); 71 | } 72 | }; 73 | })(); 74 | -------------------------------------------------------------------------------- /anderson-cv_files/paged-0.5/js/hooks.js: -------------------------------------------------------------------------------- 1 | // Hooks for paged.js 2 | { 3 | // Utils 4 | let pandocMeta, pandocMetaToString; 5 | { 6 | let el = document.getElementById('pandoc-meta'); 7 | pandocMeta = el ? JSON.parse(el.firstChild.data) : {}; 8 | } 9 | 10 | pandocMetaToString = meta => { 11 | let el = document.createElement('div'); 12 | el.innerHTML = meta; 13 | return el.innerText; 14 | }; 15 | 16 | let isString = value => { 17 | return typeof value === 'string' || value instanceof String; 18 | }; 19 | 20 | let isArray = value => { 21 | return value && typeof value === 'object' && value.constructor === Array; 22 | }; 23 | 24 | // This hook is an attempt to fix https://github.com/rstudio/pagedown/issues/131 25 | // Sometimes, the {break-after: avoid;} declaration applied on headers 26 | // lead to duplicated headers. I hate this bug. 27 | // This is linked to the way the HTML source is written 28 | // When we have the \n character like this:
\n

...

29 | // the header may be duplicated. 30 | // But, if we have

...

without any \n, the problem disappear 31 | // I think this handler can fix most of cases 32 | // Obviously, we cannot suppress all the \n in the HTML document 33 | // because carriage returns are important in
 elements.
 34 |   // Tested with Chrome 76.0.3809.100/Windows
 35 |   Paged.registerHandlers(class extends Paged.Handler {
 36 |     constructor(chunker, polisher, caller) {
 37 |       super(chunker, polisher, caller);
 38 |       this.carriageReturn = String.fromCharCode(10);
 39 |     }
 40 | 
 41 |     checkNode(node) {
 42 |       if (!node) return;
 43 |       if (node.nodeType !== 3) return;
 44 |       if (node.textContent === this.carriageReturn) {
 45 |         node.remove();
 46 |       }
 47 |     }
 48 | 
 49 |     afterParsed(parsed) {
 50 |       let template = document.querySelector('template').content;
 51 |       const breakAfterAvoidElements = template.querySelectorAll('[data-break-after="avoid"], [data-break-before="avoid"]');
 52 |       for (let el of breakAfterAvoidElements) {
 53 |         this.checkNode(el.previousSibling);
 54 |         this.checkNode(el.nextSibling);
 55 |       }
 56 |     }
 57 |   });
 58 | 
 59 |   // This hook creates a list of abbreviations
 60 |   // Note: we also could implement this feature using a Pandoc filter
 61 |   Paged.registerHandlers(class extends Paged.Handler {
 62 |     constructor(chunker, polisher, caller) {
 63 |       super(chunker, polisher, caller);
 64 |     }
 65 |     beforeParsed(content) {
 66 |       const abbreviations = content.querySelectorAll('abbr');
 67 |       if(abbreviations.length === 0) return;
 68 |       const loaTitle = 'List of Abbreviations';
 69 |       const loaId = 'LOA';
 70 |       const tocList = content.querySelector('.toc ul');
 71 |       let listOfAbbreviations = document.createElement('div');
 72 |       let descriptionList = document.createElement('dl');
 73 |       content.appendChild(listOfAbbreviations);
 74 |       listOfAbbreviations.id = loaId;
 75 |       listOfAbbreviations.classList.add('section', 'front-matter', 'level1', 'loa');
 76 |       listOfAbbreviations.innerHTML = '

' + loaTitle + '

'; 77 | listOfAbbreviations.appendChild(descriptionList); 78 | for(let abbr of abbreviations) { 79 | if(!abbr.title) continue; 80 | let term = document.createElement('dt'); 81 | let definition = document.createElement('dd'); 82 | descriptionList.appendChild(term); 83 | descriptionList.appendChild(definition); 84 | term.innerHTML = abbr.innerHTML; 85 | definition.innerText = abbr.title; 86 | } 87 | if (tocList) { 88 | const loaTOCItem = document.createElement('li'); 89 | loaTOCItem.innerHTML = '' + loaTitle + ''; 90 | tocList.appendChild(loaTOCItem); 91 | } 92 | } 93 | }); 94 | 95 | // This hook moves the sections of class front-matter in the div.front-matter-container 96 | Paged.registerHandlers(class extends Paged.Handler { 97 | constructor(chunker, polisher, caller) { 98 | super(chunker, polisher, caller); 99 | } 100 | 101 | beforeParsed(content) { 102 | const frontMatter = content.querySelector('.front-matter-container'); 103 | if (!frontMatter) return; 104 | 105 | // move front matter sections in the front matter container 106 | const frontMatterSections = content.querySelectorAll('.level1.front-matter'); 107 | for (const section of frontMatterSections) { 108 | frontMatter.appendChild(section); 109 | } 110 | 111 | // add the class front-matter-ref to any element 112 | // referring to an entry in the front matter 113 | const anchors = content.querySelectorAll('a[href^="#"]:not([href*=":"])'); 114 | for (const a of anchors) { 115 | const ref = a.getAttribute('href').replace(/^#/, ''); 116 | const element = content.getElementById(ref); 117 | if (frontMatter.contains(element)) a.classList.add('front-matter-ref'); 118 | } 119 | 120 | // update the toc, lof and lot for front matter sections 121 | const frontMatterSectionsLinks = content.querySelectorAll('.toc .front-matter-ref, .lof .front-matter-ref, .lot .front-matter-ref'); 122 | for (let i = frontMatterSectionsLinks.length - 1; i >= 0; i--) { 123 | const listItem = frontMatterSectionsLinks[i].parentNode; 124 | const list = listItem.parentNode; 125 | list.insertBefore(listItem, list.firstChild); 126 | } 127 | } 128 | }); 129 | 130 | // This hook expands the links in the lists of figures and tables 131 | Paged.registerHandlers(class extends Paged.Handler { 132 | constructor(chunker, polisher, caller) { 133 | super(chunker, polisher, caller); 134 | } 135 | 136 | beforeParsed(content) { 137 | const items = content.querySelectorAll('.lof li, .lot li'); 138 | for (const item of items) { 139 | const anchor = item.firstChild; 140 | anchor.innerText = item.innerText; 141 | item.innerText = ''; 142 | item.append(anchor); 143 | } 144 | } 145 | }); 146 | 147 | // This hook adds spans for leading symbols 148 | Paged.registerHandlers(class extends Paged.Handler { 149 | constructor(chunker, polisher, caller) { 150 | super(chunker, polisher, caller); 151 | } 152 | 153 | beforeParsed(content) { 154 | const anchors = content.querySelectorAll('.toc a, .lof a, .lot a'); 155 | for (const a of anchors) { 156 | a.innerHTML = a.innerHTML + ''; 157 | } 158 | } 159 | }); 160 | 161 | // This hook appends short titles spans 162 | Paged.registerHandlers(class extends Paged.Handler { 163 | constructor(chunker, polisher, caller) { 164 | super(chunker, polisher, caller); 165 | } 166 | 167 | beforeParsed(content) { 168 | /* A factory returning a function that appends short titles spans. 169 | The text content of these spans are reused for running titles (see default.css). 170 | Argument: level - An integer between 1 and 6. 171 | */ 172 | function appendShortTitleSpans(level) { 173 | return () => { 174 | const divs = Array.from(content.querySelectorAll('.level' + level)); 175 | 176 | function addSpan(div) { 177 | const mainHeader = div.getElementsByTagName('h' + level)[0]; 178 | if (!mainHeader) return; 179 | const mainTitle = mainHeader.textContent; 180 | const spanSectionNumber = mainHeader.getElementsByClassName('header-section-number')[0]; 181 | const mainNumber = !!spanSectionNumber ? spanSectionNumber.textContent : ''; 182 | const runningTitle = 'shortTitle' in div.dataset ? mainNumber + ' ' + div.dataset.shortTitle : mainTitle; 183 | const span = document.createElement('span'); 184 | span.className = 'shorttitle' + level; 185 | span.innerText = runningTitle; 186 | span.style.display = "none"; 187 | mainHeader.appendChild(span); 188 | if (level == 1 && div.querySelector('.level2') === null) { 189 | let span2 = document.createElement('span'); 190 | span2.className = 'shorttitle2'; 191 | span2.innerText = ' '; 192 | span2.style.display = "none"; 193 | span.insertAdjacentElement('afterend', span2); 194 | } 195 | } 196 | 197 | for (const div of divs) { 198 | addSpan(div); 199 | } 200 | }; 201 | } 202 | 203 | appendShortTitleSpans(1)(); 204 | appendShortTitleSpans(2)(); 205 | } 206 | }); 207 | 208 | // Footnotes support 209 | Paged.registerHandlers(class extends Paged.Handler { 210 | constructor(chunker, polisher, caller) { 211 | super(chunker, polisher, caller); 212 | 213 | this.splittedParagraphRefs = []; 214 | } 215 | 216 | beforeParsed(content) { 217 | // remove footnotes in toc, lof, lot 218 | // see https://github.com/rstudio/pagedown/issues/54 219 | let removeThese = content.querySelectorAll('.toc .footnote, .lof .footnote, .lot .footnote'); 220 | for (const el of removeThese) { 221 | el.remove(); 222 | } 223 | 224 | let footnotes = content.querySelectorAll('.footnote'); 225 | 226 | for (let footnote of footnotes) { 227 | let parentElement = footnote.parentElement; 228 | let footnoteCall = document.createElement('a'); 229 | let footnoteNumber = footnote.dataset.pagedownFootnoteNumber; 230 | 231 | footnoteCall.className = 'footnote-ref'; // same class as Pandoc 232 | footnoteCall.setAttribute('id', 'fnref' + footnoteNumber); // same notation as Pandoc 233 | footnoteCall.setAttribute('href', '#' + footnote.id); 234 | footnoteCall.innerHTML = '' + footnoteNumber +''; 235 | parentElement.insertBefore(footnoteCall, footnote); 236 | 237 | // Here comes a hack. Fortunately, it works with Chrome and FF. 238 | let handler = document.createElement('p'); 239 | handler.className = 'footnoteHandler'; 240 | parentElement.insertBefore(handler, footnote); 241 | handler.appendChild(footnote); 242 | handler.style.display = 'inline-block'; 243 | handler.style.width = '100%'; 244 | handler.style.float = 'right'; 245 | handler.style.pageBreakInside = 'avoid'; 246 | } 247 | } 248 | 249 | afterPageLayout(pageFragment, page, breakToken) { 250 | function hasItemParent(node) { 251 | if (node.parentElement === null) { 252 | return false; 253 | } else { 254 | if (node.parentElement.tagName === 'LI') { 255 | return true; 256 | } else { 257 | return hasItemParent(node.parentElement); 258 | } 259 | } 260 | } 261 | // If a li item is broken, we store the reference of the p child element 262 | // see https://github.com/rstudio/pagedown/issues/23#issue-376548000 263 | if (breakToken !== undefined) { 264 | if (breakToken.node.nodeName === "#text" && hasItemParent(breakToken.node)) { 265 | this.splittedParagraphRefs.push(breakToken.node.parentElement.dataset.ref); 266 | } 267 | } 268 | } 269 | 270 | afterRendered(pages) { 271 | for (let page of pages) { 272 | const footnotes = page.element.querySelectorAll('.footnote'); 273 | if (footnotes.length === 0) { 274 | continue; 275 | } 276 | 277 | const pageContent = page.element.querySelector('.pagedjs_page_content'); 278 | let hr = document.createElement('hr'); 279 | let footnoteArea = document.createElement('div'); 280 | 281 | pageContent.style.display = 'flex'; 282 | pageContent.style.flexDirection = 'column'; 283 | 284 | hr.className = 'footnote-break'; 285 | hr.style.marginTop = 'auto'; 286 | hr.style.marginBottom = 0; 287 | hr.style.marginLeft = 0; 288 | hr.style.marginRight = 'auto'; 289 | pageContent.appendChild(hr); 290 | 291 | footnoteArea.className = 'footnote-area'; 292 | pageContent.appendChild(footnoteArea); 293 | 294 | for (let footnote of footnotes) { 295 | let handler = footnote.parentElement; 296 | 297 | footnoteArea.appendChild(footnote); 298 | handler.parentNode.removeChild(handler); 299 | 300 | footnote.innerHTML = '' + footnote.dataset.pagedownFootnoteNumber + '' + footnote.innerHTML; 301 | footnote.style.fontSize = 'x-small'; 302 | footnote.style.marginTop = 0; 303 | footnote.style.marginBottom = 0; 304 | footnote.style.paddingTop = 0; 305 | footnote.style.paddingBottom = 0; 306 | footnote.style.display = 'block'; 307 | } 308 | } 309 | 310 | for (let ref of this.splittedParagraphRefs) { 311 | let paragraphFirstPage = document.querySelector('[data-split-to="' + ref + '"]'); 312 | // We test whether the paragraph is empty 313 | // see https://github.com/rstudio/pagedown/issues/23#issue-376548000 314 | if (paragraphFirstPage.innerText === "") { 315 | paragraphFirstPage.parentElement.style.display = "none"; 316 | let paragraphSecondPage = document.querySelector('[data-split-from="' + ref + '"]'); 317 | paragraphSecondPage.parentElement.style.setProperty('list-style', 'inherit', 'important'); 318 | } 319 | } 320 | } 321 | }); 322 | 323 | // Support for "Chapter " label on section with class `.chapter` 324 | Paged.registerHandlers(class extends Paged.Handler { 325 | constructor(chunker, polisher, caller) { 326 | super(chunker, polisher, caller); 327 | 328 | this.options = pandocMeta['chapter_name']; 329 | 330 | let styles; 331 | if (isString(this.options)) { 332 | this.options = pandocMetaToString(this.options); 333 | styles = ` 334 | :root { 335 | --chapter-name-before: "${this.options}"; 336 | } 337 | `; 338 | } 339 | if (isArray(this.options)) { 340 | this.options = this.options.map(pandocMetaToString); 341 | styles = ` 342 | :root { 343 | --chapter-name-before: "${this.options[0]}"; 344 | --chapter-name-after: "${this.options[1]}"; 345 | } 346 | `; 347 | } 348 | if (styles) polisher.insert(styles); 349 | } 350 | 351 | beforeParsed(content) { 352 | const tocAnchors = content.querySelectorAll('.toc a[href^="#"]:not([href*=":"]'); 353 | for (const anchor of tocAnchors) { 354 | const ref = anchor.getAttribute('href').replace(/^#/, ''); 355 | const element = content.getElementById(ref); 356 | if (element.classList.contains('chapter')) { 357 | anchor.classList.add('chapter-ref'); 358 | } 359 | } 360 | } 361 | }); 362 | 363 | // Main text line numbering, 364 | // see https://github.com/rstudio/pagedown/issues/115 365 | // Original idea: Julien Taquet, thanks! 366 | Paged.registerHandlers(class extends Paged.Handler { 367 | constructor(chunker, polisher, caller) { 368 | super(chunker, polisher, caller); 369 | 370 | // get the number-lines option from Pandoc metavariables 371 | this.options = pandocMeta['number-lines']; 372 | // quit early if the "number-lines" option is false or missing 373 | if (!this.options) return; 374 | // retrieve the selector if provided, otherwise use the default selector 375 | this.selector = this.options.selector ? pandocMetaToString(this.options.selector) : '.level1:not(.front-matter) h1, .level1 h2, .level1 h3, .level1 p'; 376 | 377 | const styles = ` 378 | :root { 379 | --line-numbers-padding-right: 10px; 380 | --line-numbers-font-size: 8pt; 381 | } 382 | .pagedown-linenumbers-container { 383 | position: absolute; 384 | margin-top: var(--pagedjs-margin-top); 385 | right: calc(var(--pagedjs-width) - var(--pagedjs-margin-left)); 386 | } 387 | .maintextlinenumbers { 388 | position: absolute; 389 | right: 0; 390 | text-align: right; 391 | padding-right: var(--line-numbers-padding-right); 392 | font-size: var(--line-numbers-font-size); 393 | } 394 | `; 395 | polisher.insert(styles); 396 | 397 | this.resetLinesCounter(); 398 | } 399 | 400 | appendLineNumbersContainer(page) { 401 | const pagebox = page.element.querySelector('.pagedjs_pagebox'); 402 | const lineNumbersContainer = document.createElement('div'); 403 | lineNumbersContainer.classList.add('pagedown-linenumbers-container'); 404 | 405 | return pagebox.appendChild(lineNumbersContainer); 406 | } 407 | 408 | lineHeight(element) { 409 | // If the document stylesheet does not define a value for line-height, 410 | // Blink returns "normal". Therefore, parseInt may return NaN. 411 | return parseInt(getComputedStyle(element).lineHeight); 412 | } 413 | 414 | innerHeight(element) { 415 | let outerHeight = element.getBoundingClientRect().height; 416 | let {borderTopWidth, 417 | borderBottomWidth, 418 | paddingTop, 419 | paddingBottom} = getComputedStyle(element); 420 | 421 | borderTopWidth = parseFloat(borderTopWidth); 422 | borderBottomWidth = parseFloat(borderBottomWidth); 423 | paddingTop = parseFloat(paddingTop); 424 | paddingBottom = parseFloat(paddingBottom); 425 | 426 | return Math.round(outerHeight - borderTopWidth - borderBottomWidth - paddingTop - paddingBottom); 427 | } 428 | 429 | arrayOfInt(from, length) { 430 | // adapted from https://stackoverflow.com/a/50234108/6500804 431 | return Array.from(Array(length).keys(), n => n + from); 432 | } 433 | 434 | incrementLinesCounter(value) { 435 | this.linesCounter = this.linesCounter + value; 436 | } 437 | 438 | resetLinesCounter() { 439 | this.linesCounter = 0; 440 | } 441 | 442 | isDisplayMath(element) { 443 | const nodes = element.childNodes; 444 | if (nodes.length != 1) return false; 445 | return (nodes[0].nodeName === 'SPAN') && (nodes[0].classList.value === 'math display'); 446 | } 447 | 448 | afterRendered(pages) { 449 | if (!this.options) return; 450 | 451 | for (let page of pages) { 452 | const lineNumbersContainer = this.appendLineNumbersContainer(page); 453 | const pageAreaY = page.area.getBoundingClientRect().y; 454 | let elementsToNumber = page.area.querySelectorAll(this.selector); 455 | 456 | for (let element of elementsToNumber) { 457 | // Do not add line numbers for display math environment 458 | if (this.isDisplayMath(element)) continue; 459 | 460 | // Try to retrieve line height 461 | const lineHeight = this.lineHeight(element); 462 | // Test against lineHeight method returns NaN 463 | if (!lineHeight) { 464 | console.warn('Failed to compute line height value on "' + page.id + '".'); 465 | continue; 466 | } 467 | 468 | const innerHeight = this.innerHeight(element); 469 | 470 | // Number of lines estimation 471 | // There is no built-in method to detect the number of lines in a block. 472 | // The main caveat is that an actual line height can differ from 473 | // the line-height CSS property. 474 | // Mixed fonts, subscripts, superscripts, inline math... can increase 475 | // the actual line height. 476 | // Here, we divide the inner height of the block by the line-height 477 | // computed property and round to the floor to take into account that 478 | // sometimes the actual line height is greater than its property value. 479 | // This is far from perfect and can be easily broken especially by 480 | // inline math. 481 | const nLines = Math.floor(innerHeight / lineHeight); 482 | 483 | // do not add line numbers for void paragraphs 484 | if (nLines <= 0) continue; 485 | 486 | const linenumbers = document.createElement('div'); 487 | lineNumbersContainer.appendChild(linenumbers); 488 | linenumbers.classList.add('maintextlinenumbers'); 489 | 490 | const elementY = element.getBoundingClientRect().y; 491 | linenumbers.style.top = (elementY - pageAreaY) + 'px'; 492 | 493 | const cs = getComputedStyle(element); 494 | const paddingTop = parseFloat(cs.paddingTop) + parseFloat(cs.borderTopWidth); 495 | linenumbers.style.paddingTop = paddingTop + 'px'; 496 | 497 | linenumbers.style.lineHeight = cs.lineHeight; 498 | 499 | linenumbers.innerHTML = this.arrayOfInt(this.linesCounter + 1, nLines) 500 | .reduce((t, v) => t + '
' + v); 501 | this.incrementLinesCounter(nLines); 502 | } 503 | 504 | if (this.options['reset-page']) { 505 | this.resetLinesCounter(); 506 | } 507 | } 508 | } 509 | }); 510 | } 511 | -------------------------------------------------------------------------------- /anderson-cv_files/paged-0.7.1/js/config.js: -------------------------------------------------------------------------------- 1 | // Configuration script for paged.js 2 | 3 | (function() { 4 | // Retrieve previous config object if defined 5 | window.PagedConfig = window.PagedConfig || {}; 6 | const {before: beforePaged, after: afterPaged} = window.PagedConfig; 7 | 8 | // utils 9 | const insertCSS = text => { 10 | let style = document.createElement('style'); 11 | style.type = 'text/css'; 12 | style.appendChild(document.createTextNode(text)); 13 | document.head.appendChild(style); 14 | }; 15 | 16 | // Util function for front and back covers images 17 | const insertCSSForCover = type => { 18 | const links = document.querySelectorAll('link[id^=' + type + ']'); 19 | if (!links.length) return; 20 | const re = new RegExp(type + '-\\d+'); 21 | let text = ':root {--' + type + ': var(--' + type + '-1);'; 22 | for (const link of links) { 23 | text += '--' + re.exec(link.id)[0] + ': url("' + link.href + '");'; 24 | } 25 | text += '}'; 26 | insertCSS(text); 27 | }; 28 | 29 | const insertPageBreaksCSS = () => { 30 | insertCSS(` 31 | .page-break-after {break-after: page;} 32 | .page-break-before {break-before: page;} 33 | `); 34 | }; 35 | 36 | window.PagedConfig.before = async () => { 37 | // Front and back covers support 38 | let frontCover = document.querySelector('.front-cover'); 39 | let backCover = document.querySelector('.back-cover'); 40 | if (frontCover) document.body.prepend(frontCover); 41 | if (backCover) document.body.append(backCover); 42 | insertCSSForCover('front-cover'); 43 | insertCSSForCover('back-cover'); 44 | insertPageBreaksCSS(); 45 | 46 | if (beforePaged) await beforePaged(); 47 | }; 48 | 49 | window.PagedConfig.after = (flow) => { 50 | // force redraw, see https://github.com/rstudio/pagedown/issues/35#issuecomment-475905361 51 | // and https://stackoverflow.com/a/24753578/6500804 52 | document.body.style.display = 'none'; 53 | document.body.offsetHeight; 54 | document.body.style.display = ''; 55 | 56 | // run previous PagedConfig.after function if defined 57 | if (afterPaged) afterPaged(flow); 58 | 59 | // pagedownListener is a binding added by the chrome_print function 60 | // this binding exists only when chrome_print opens the html file 61 | if (window.pagedownListener) { 62 | // the html file is opened for printing 63 | // call the binding to signal to the R session that Paged.js has finished 64 | pagedownListener(JSON.stringify({ 65 | pagedjs: true, 66 | pages: flow.total, 67 | elapsedtime: flow.performance 68 | })); 69 | return; 70 | } 71 | if (sessionStorage.getItem('pagedown-scroll')) { 72 | // scroll to the last position before the page is reloaded 73 | window.scrollTo(0, sessionStorage.getItem('pagedown-scroll')); 74 | return; 75 | } 76 | if (window.location.hash) { 77 | const id = window.location.hash.replace(/^#/, ''); 78 | document.getElementById(id).scrollIntoView({behavior: 'smooth'}); 79 | } 80 | }; 81 | })(); 82 | -------------------------------------------------------------------------------- /anderson-cv_files/paged-0.7.1/js/hooks.js: -------------------------------------------------------------------------------- 1 | // Hooks for paged.js 2 | { 3 | // Utils 4 | let pandocMeta, pandocMetaToString; 5 | { 6 | let el = document.getElementById('pandoc-meta'); 7 | pandocMeta = el ? JSON.parse(el.firstChild.data) : {}; 8 | } 9 | 10 | pandocMetaToString = meta => { 11 | let el = document.createElement('div'); 12 | el.innerHTML = meta; 13 | return el.innerText; 14 | }; 15 | 16 | let isString = value => { 17 | return typeof value === 'string' || value instanceof String; 18 | }; 19 | 20 | let isArray = value => { 21 | return value && typeof value === 'object' && value.constructor === Array; 22 | }; 23 | 24 | // This hook is an attempt to fix https://github.com/rstudio/pagedown/issues/131 25 | // Sometimes, the {break-after: avoid;} declaration applied on headers 26 | // lead to duplicated headers. I hate this bug. 27 | // This is linked to the way the HTML source is written 28 | // When we have the \n character like this:
\n

...

29 | // the header may be duplicated. 30 | // But, if we have

...

without any \n, the problem disappear 31 | // I think this handler can fix most of cases 32 | // Obviously, we cannot suppress all the \n in the HTML document 33 | // because carriage returns are important in
 elements.
 34 |   // Tested with Chrome 76.0.3809.100/Windows
 35 |   Paged.registerHandlers(class extends Paged.Handler {
 36 |     constructor(chunker, polisher, caller) {
 37 |       super(chunker, polisher, caller);
 38 |       this.carriageReturn = String.fromCharCode(10);
 39 |     }
 40 | 
 41 |     checkNode(node) {
 42 |       if (!node) return;
 43 |       if (node.nodeType !== 3) return;
 44 |       if (node.textContent === this.carriageReturn) {
 45 |         node.remove();
 46 |       }
 47 |     }
 48 | 
 49 |     afterParsed(parsed) {
 50 |       let template = document.querySelector('template').content;
 51 |       const breakAfterAvoidElements = template.querySelectorAll('[data-break-after="avoid"], [data-break-before="avoid"]');
 52 |       for (let el of breakAfterAvoidElements) {
 53 |         this.checkNode(el.previousSibling);
 54 |         this.checkNode(el.nextSibling);
 55 |       }
 56 |     }
 57 |   });
 58 | 
 59 |   // This hook creates a list of abbreviations
 60 |   // Note: we also could implement this feature using a Pandoc filter
 61 |   Paged.registerHandlers(class extends Paged.Handler {
 62 |     constructor(chunker, polisher, caller) {
 63 |       super(chunker, polisher, caller);
 64 |     }
 65 |     beforeParsed(content) {
 66 |       const abbreviations = content.querySelectorAll('abbr');
 67 |       if(abbreviations.length === 0) return;
 68 |       const loaTitle = 'List of Abbreviations';
 69 |       const loaId = 'LOA';
 70 |       const tocList = content.querySelector('.toc ul');
 71 |       let listOfAbbreviations = document.createElement('div');
 72 |       let descriptionList = document.createElement('dl');
 73 |       content.appendChild(listOfAbbreviations);
 74 |       listOfAbbreviations.id = loaId;
 75 |       listOfAbbreviations.classList.add('section', 'front-matter', 'level1', 'loa');
 76 |       listOfAbbreviations.innerHTML = '

' + loaTitle + '

'; 77 | listOfAbbreviations.appendChild(descriptionList); 78 | for(let abbr of abbreviations) { 79 | if(!abbr.title) continue; 80 | let term = document.createElement('dt'); 81 | let definition = document.createElement('dd'); 82 | descriptionList.appendChild(term); 83 | descriptionList.appendChild(definition); 84 | term.innerHTML = abbr.innerHTML; 85 | definition.innerText = abbr.title; 86 | } 87 | if (tocList) { 88 | const loaTOCItem = document.createElement('li'); 89 | loaTOCItem.innerHTML = '' + loaTitle + ''; 90 | tocList.appendChild(loaTOCItem); 91 | } 92 | } 93 | }); 94 | 95 | // This hook moves the sections of class front-matter in the div.front-matter-container 96 | Paged.registerHandlers(class extends Paged.Handler { 97 | constructor(chunker, polisher, caller) { 98 | super(chunker, polisher, caller); 99 | } 100 | 101 | beforeParsed(content) { 102 | const frontMatter = content.querySelector('.front-matter-container'); 103 | if (!frontMatter) return; 104 | 105 | // move front matter sections in the front matter container 106 | const frontMatterSections = content.querySelectorAll('.level1.front-matter'); 107 | for (const section of frontMatterSections) { 108 | frontMatter.appendChild(section); 109 | } 110 | 111 | // add the class front-matter-ref to any element 112 | // referring to an entry in the front matter 113 | const anchors = content.querySelectorAll('a[href^="#"]:not([href*=":"])'); 114 | for (const a of anchors) { 115 | const ref = a.getAttribute('href').replace(/^#/, ''); 116 | const element = content.getElementById(ref); 117 | if (frontMatter.contains(element)) a.classList.add('front-matter-ref'); 118 | } 119 | 120 | // update the toc, lof and lot for front matter sections 121 | const frontMatterSectionsLinks = content.querySelectorAll('.toc .front-matter-ref, .lof .front-matter-ref, .lot .front-matter-ref'); 122 | for (let i = frontMatterSectionsLinks.length - 1; i >= 0; i--) { 123 | const listItem = frontMatterSectionsLinks[i].parentNode; 124 | const list = listItem.parentNode; 125 | list.insertBefore(listItem, list.firstChild); 126 | } 127 | } 128 | }); 129 | 130 | // This hook expands the links in the lists of figures and tables 131 | Paged.registerHandlers(class extends Paged.Handler { 132 | constructor(chunker, polisher, caller) { 133 | super(chunker, polisher, caller); 134 | } 135 | 136 | beforeParsed(content) { 137 | const items = content.querySelectorAll('.lof li, .lot li'); 138 | for (const item of items) { 139 | const anchor = item.firstChild; 140 | anchor.innerText = item.innerText; 141 | item.innerText = ''; 142 | item.append(anchor); 143 | } 144 | } 145 | }); 146 | 147 | // This hook adds spans for leading symbols 148 | Paged.registerHandlers(class extends Paged.Handler { 149 | constructor(chunker, polisher, caller) { 150 | super(chunker, polisher, caller); 151 | } 152 | 153 | beforeParsed(content) { 154 | const anchors = content.querySelectorAll('.toc a, .lof a, .lot a'); 155 | for (const a of anchors) { 156 | a.innerHTML = a.innerHTML + ''; 157 | } 158 | } 159 | }); 160 | 161 | // This hook appends short titles spans 162 | Paged.registerHandlers(class extends Paged.Handler { 163 | constructor(chunker, polisher, caller) { 164 | super(chunker, polisher, caller); 165 | } 166 | 167 | beforeParsed(content) { 168 | /* A factory returning a function that appends short titles spans. 169 | The text content of these spans are reused for running titles (see default.css). 170 | Argument: level - An integer between 1 and 6. 171 | */ 172 | function appendShortTitleSpans(level) { 173 | return () => { 174 | const divs = Array.from(content.querySelectorAll('.level' + level)); 175 | 176 | function addSpan(div) { 177 | const mainHeader = div.getElementsByTagName('h' + level)[0]; 178 | if (!mainHeader) return; 179 | const mainTitle = mainHeader.textContent; 180 | const spanSectionNumber = mainHeader.getElementsByClassName('header-section-number')[0]; 181 | const mainNumber = !!spanSectionNumber ? spanSectionNumber.textContent : ''; 182 | const runningTitle = 'shortTitle' in div.dataset ? mainNumber + ' ' + div.dataset.shortTitle : mainTitle; 183 | const span = document.createElement('span'); 184 | span.className = 'shorttitle' + level; 185 | span.innerText = runningTitle; 186 | span.style.display = "none"; 187 | mainHeader.appendChild(span); 188 | if (level == 1 && div.querySelector('.level2') === null) { 189 | let span2 = document.createElement('span'); 190 | span2.className = 'shorttitle2'; 191 | span2.innerText = ' '; 192 | span2.style.display = "none"; 193 | span.insertAdjacentElement('afterend', span2); 194 | } 195 | } 196 | 197 | for (const div of divs) { 198 | addSpan(div); 199 | } 200 | }; 201 | } 202 | 203 | appendShortTitleSpans(1)(); 204 | appendShortTitleSpans(2)(); 205 | } 206 | }); 207 | 208 | // Footnotes support 209 | Paged.registerHandlers(class extends Paged.Handler { 210 | constructor(chunker, polisher, caller) { 211 | super(chunker, polisher, caller); 212 | 213 | this.splittedParagraphRefs = []; 214 | } 215 | 216 | beforeParsed(content) { 217 | // remove footnotes in toc, lof, lot 218 | // see https://github.com/rstudio/pagedown/issues/54 219 | let removeThese = content.querySelectorAll('.toc .footnote, .lof .footnote, .lot .footnote'); 220 | for (const el of removeThese) { 221 | el.remove(); 222 | } 223 | 224 | let footnotes = content.querySelectorAll('.footnote'); 225 | 226 | for (let footnote of footnotes) { 227 | let parentElement = footnote.parentElement; 228 | let footnoteCall = document.createElement('a'); 229 | let footnoteNumber = footnote.dataset.pagedownFootnoteNumber; 230 | 231 | footnoteCall.className = 'footnote-ref'; // same class as Pandoc 232 | footnoteCall.setAttribute('id', 'fnref' + footnoteNumber); // same notation as Pandoc 233 | footnoteCall.setAttribute('href', '#' + footnote.id); 234 | footnoteCall.innerHTML = '' + footnoteNumber +''; 235 | parentElement.insertBefore(footnoteCall, footnote); 236 | 237 | // Here comes a hack. Fortunately, it works with Chrome and FF. 238 | let handler = document.createElement('p'); 239 | handler.className = 'footnoteHandler'; 240 | parentElement.insertBefore(handler, footnote); 241 | handler.appendChild(footnote); 242 | handler.style.display = 'inline-block'; 243 | handler.style.width = '100%'; 244 | handler.style.float = 'right'; 245 | handler.style.pageBreakInside = 'avoid'; 246 | } 247 | } 248 | 249 | afterPageLayout(pageFragment, page, breakToken) { 250 | function hasItemParent(node) { 251 | if (node.parentElement === null) { 252 | return false; 253 | } else { 254 | if (node.parentElement.tagName === 'LI') { 255 | return true; 256 | } else { 257 | return hasItemParent(node.parentElement); 258 | } 259 | } 260 | } 261 | // If a li item is broken, we store the reference of the p child element 262 | // see https://github.com/rstudio/pagedown/issues/23#issue-376548000 263 | if (breakToken !== undefined) { 264 | if (breakToken.node.nodeName === "#text" && hasItemParent(breakToken.node)) { 265 | this.splittedParagraphRefs.push(breakToken.node.parentElement.dataset.ref); 266 | } 267 | } 268 | } 269 | 270 | afterRendered(pages) { 271 | for (let page of pages) { 272 | const footnotes = page.element.querySelectorAll('.footnote'); 273 | if (footnotes.length === 0) { 274 | continue; 275 | } 276 | 277 | const pageContent = page.element.querySelector('.pagedjs_page_content'); 278 | let hr = document.createElement('hr'); 279 | let footnoteArea = document.createElement('div'); 280 | 281 | pageContent.style.display = 'flex'; 282 | pageContent.style.flexDirection = 'column'; 283 | 284 | hr.className = 'footnote-break'; 285 | hr.style.marginTop = 'auto'; 286 | hr.style.marginBottom = 0; 287 | hr.style.marginLeft = 0; 288 | hr.style.marginRight = 'auto'; 289 | pageContent.appendChild(hr); 290 | 291 | footnoteArea.className = 'footnote-area'; 292 | pageContent.appendChild(footnoteArea); 293 | 294 | for (let footnote of footnotes) { 295 | let handler = footnote.parentElement; 296 | 297 | footnoteArea.appendChild(footnote); 298 | handler.parentNode.removeChild(handler); 299 | 300 | footnote.innerHTML = '' + footnote.dataset.pagedownFootnoteNumber + '' + footnote.innerHTML; 301 | footnote.style.fontSize = 'x-small'; 302 | footnote.style.marginTop = 0; 303 | footnote.style.marginBottom = 0; 304 | footnote.style.paddingTop = 0; 305 | footnote.style.paddingBottom = 0; 306 | footnote.style.display = 'block'; 307 | } 308 | } 309 | 310 | for (let ref of this.splittedParagraphRefs) { 311 | let paragraphFirstPage = document.querySelector('[data-split-to="' + ref + '"]'); 312 | // We test whether the paragraph is empty 313 | // see https://github.com/rstudio/pagedown/issues/23#issue-376548000 314 | if (paragraphFirstPage.innerText === "") { 315 | paragraphFirstPage.parentElement.style.display = "none"; 316 | let paragraphSecondPage = document.querySelector('[data-split-from="' + ref + '"]'); 317 | paragraphSecondPage.parentElement.style.setProperty('list-style', 'inherit', 'important'); 318 | } 319 | } 320 | } 321 | }); 322 | 323 | // Support for "Chapter " label on section with class `.chapter` 324 | Paged.registerHandlers(class extends Paged.Handler { 325 | constructor(chunker, polisher, caller) { 326 | super(chunker, polisher, caller); 327 | 328 | this.options = pandocMeta['chapter_name']; 329 | 330 | let styles; 331 | if (isString(this.options)) { 332 | this.options = pandocMetaToString(this.options); 333 | styles = ` 334 | :root { 335 | --chapter-name-before: "${this.options}"; 336 | } 337 | `; 338 | } 339 | if (isArray(this.options)) { 340 | this.options = this.options.map(pandocMetaToString); 341 | styles = ` 342 | :root { 343 | --chapter-name-before: "${this.options[0]}"; 344 | --chapter-name-after: "${this.options[1]}"; 345 | } 346 | `; 347 | } 348 | if (styles) polisher.insert(styles); 349 | } 350 | 351 | beforeParsed(content) { 352 | const tocAnchors = content.querySelectorAll('.toc a[href^="#"]:not([href*=":"]'); 353 | for (const anchor of tocAnchors) { 354 | const ref = anchor.getAttribute('href').replace(/^#/, ''); 355 | const element = content.getElementById(ref); 356 | if (element.classList.contains('chapter')) { 357 | anchor.classList.add('chapter-ref'); 358 | } 359 | } 360 | } 361 | }); 362 | 363 | // Main text line numbering, 364 | // see https://github.com/rstudio/pagedown/issues/115 365 | // Original idea: Julien Taquet, thanks! 366 | Paged.registerHandlers(class extends Paged.Handler { 367 | constructor(chunker, polisher, caller) { 368 | super(chunker, polisher, caller); 369 | 370 | // get the number-lines option from Pandoc metavariables 371 | this.options = pandocMeta['number-lines']; 372 | // quit early if the "number-lines" option is false or missing 373 | if (!this.options) return; 374 | // retrieve the selector if provided, otherwise use the default selector 375 | this.selector = this.options.selector ? pandocMetaToString(this.options.selector) : '.level1:not(.front-matter) h1, .level1 h2, .level1 h3, .level1 p'; 376 | 377 | const styles = ` 378 | :root { 379 | --line-numbers-padding-right: 10px; 380 | --line-numbers-font-size: 8pt; 381 | } 382 | .pagedown-linenumbers-container { 383 | position: absolute; 384 | margin-top: var(--pagedjs-margin-top); 385 | right: calc(var(--pagedjs-width) - var(--pagedjs-margin-left)); 386 | } 387 | .maintextlinenumbers { 388 | position: absolute; 389 | right: 0; 390 | text-align: right; 391 | padding-right: var(--line-numbers-padding-right); 392 | font-size: var(--line-numbers-font-size); 393 | } 394 | `; 395 | polisher.insert(styles); 396 | 397 | this.resetLinesCounter(); 398 | } 399 | 400 | appendLineNumbersContainer(page) { 401 | const pagebox = page.element.querySelector('.pagedjs_pagebox'); 402 | const lineNumbersContainer = document.createElement('div'); 403 | lineNumbersContainer.classList.add('pagedown-linenumbers-container'); 404 | 405 | return pagebox.appendChild(lineNumbersContainer); 406 | } 407 | 408 | lineHeight(element) { 409 | // If the document stylesheet does not define a value for line-height, 410 | // Blink returns "normal". Therefore, parseInt may return NaN. 411 | return parseInt(getComputedStyle(element).lineHeight); 412 | } 413 | 414 | innerHeight(element) { 415 | let outerHeight = element.getBoundingClientRect().height; 416 | let {borderTopWidth, 417 | borderBottomWidth, 418 | paddingTop, 419 | paddingBottom} = getComputedStyle(element); 420 | 421 | borderTopWidth = parseFloat(borderTopWidth); 422 | borderBottomWidth = parseFloat(borderBottomWidth); 423 | paddingTop = parseFloat(paddingTop); 424 | paddingBottom = parseFloat(paddingBottom); 425 | 426 | return Math.round(outerHeight - borderTopWidth - borderBottomWidth - paddingTop - paddingBottom); 427 | } 428 | 429 | arrayOfInt(from, length) { 430 | // adapted from https://stackoverflow.com/a/50234108/6500804 431 | return Array.from(Array(length).keys(), n => n + from); 432 | } 433 | 434 | incrementLinesCounter(value) { 435 | this.linesCounter = this.linesCounter + value; 436 | } 437 | 438 | resetLinesCounter() { 439 | this.linesCounter = 0; 440 | } 441 | 442 | isDisplayMath(element) { 443 | const nodes = element.childNodes; 444 | if (nodes.length != 1) return false; 445 | return (nodes[0].nodeName === 'SPAN') && (nodes[0].classList.value === 'math display'); 446 | } 447 | 448 | afterRendered(pages) { 449 | if (!this.options) return; 450 | 451 | for (let page of pages) { 452 | const lineNumbersContainer = this.appendLineNumbersContainer(page); 453 | const pageAreaY = page.area.getBoundingClientRect().y; 454 | let elementsToNumber = page.area.querySelectorAll(this.selector); 455 | 456 | for (let element of elementsToNumber) { 457 | // Do not add line numbers for display math environment 458 | if (this.isDisplayMath(element)) continue; 459 | 460 | // Try to retrieve line height 461 | const lineHeight = this.lineHeight(element); 462 | // Test against lineHeight method returns NaN 463 | if (!lineHeight) { 464 | console.warn('Failed to compute line height value on "' + page.id + '".'); 465 | continue; 466 | } 467 | 468 | const innerHeight = this.innerHeight(element); 469 | 470 | // Number of lines estimation 471 | // There is no built-in method to detect the number of lines in a block. 472 | // The main caveat is that an actual line height can differ from 473 | // the line-height CSS property. 474 | // Mixed fonts, subscripts, superscripts, inline math... can increase 475 | // the actual line height. 476 | // Here, we divide the inner height of the block by the line-height 477 | // computed property and round to the floor to take into account that 478 | // sometimes the actual line height is greater than its property value. 479 | // This is far from perfect and can be easily broken especially by 480 | // inline math. 481 | const nLines = Math.floor(innerHeight / lineHeight); 482 | 483 | // do not add line numbers for void paragraphs 484 | if (nLines <= 0) continue; 485 | 486 | const linenumbers = document.createElement('div'); 487 | lineNumbersContainer.appendChild(linenumbers); 488 | linenumbers.classList.add('maintextlinenumbers'); 489 | 490 | const elementY = element.getBoundingClientRect().y; 491 | linenumbers.style.top = (elementY - pageAreaY) + 'px'; 492 | 493 | const cs = getComputedStyle(element); 494 | const paddingTop = parseFloat(cs.paddingTop) + parseFloat(cs.borderTopWidth); 495 | linenumbers.style.paddingTop = paddingTop + 'px'; 496 | 497 | linenumbers.style.lineHeight = cs.lineHeight; 498 | 499 | linenumbers.innerHTML = this.arrayOfInt(this.linesCounter + 1, nLines) 500 | .reduce((t, v) => t + '
' + v); 501 | this.incrementLinesCounter(nLines); 502 | } 503 | 504 | if (this.options['reset-page']) { 505 | this.resetLinesCounter(); 506 | } 507 | } 508 | } 509 | }); 510 | } 511 | -------------------------------------------------------------------------------- /content/contact-info.Rmd: -------------------------------------------------------------------------------- 1 | ```{block type='col- grid-item', echo=TRUE} 2 | ## Contact information {.box} 3 | 4 |
5 | | right | right | 6 | |:------|-----:| 7 | | [BRT, University of Oregon](https://www.brtprojects.org)| 8 | | daniela\@uoregon.edu | 9 | | [datalorax](https://www.datalorax.com) | 10 | | [datalorax](https://github.com/datalorax/) | 11 | | [datalorax_](https://twitter.com/datalorax_/) | 12 | | [Daniel Anderson](https://stackoverflow.com/users/4959854/daniel-anderson) | 13 | | [Daniel Anderson](https://orcid.org/0000-0003-4699-4680) 14 | 15 |
16 | ``` -------------------------------------------------------------------------------- /content/summary.Rmd: -------------------------------------------------------------------------------- 1 | ```{block type="col-1 grid-item", echo=TRUE} 2 | ## About Me {.box} 3 | I am primarily interested in data science and computational social science, broadly defined as the intersection between computer science and statistics, as applied to large-scale research in education. I am particularly interested in systematic inequalities that influence students’ learning and growth over time. I am also a strong proponent of open and reproducible workflows. 4 | ``` -------------------------------------------------------------------------------- /data/courses.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datalorax/anderson-cv/04e645f9145a8ede014079609f373ca8d349af87/data/courses.xlsx -------------------------------------------------------------------------------- /data/cv_entries.numbers: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datalorax/anderson-cv/04e645f9145a8ede014079609f373ca8d349af87/data/cv_entries.numbers -------------------------------------------------------------------------------- /data/cv_entries.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datalorax/anderson-cv/04e645f9145a8ede014079609f373ca8d349af87/data/cv_entries.xlsx -------------------------------------------------------------------------------- /data/grants.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datalorax/anderson-cv/04e645f9145a8ede014079609f373ca8d349af87/data/grants.xlsx -------------------------------------------------------------------------------- /data/in-progress.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datalorax/anderson-cv/04e645f9145a8ede014079609f373ca8d349af87/data/in-progress.xlsx -------------------------------------------------------------------------------- /data/pubs.numbers: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datalorax/anderson-cv/04e645f9145a8ede014079609f373ca8d349af87/data/pubs.numbers -------------------------------------------------------------------------------- /data/pubs.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datalorax/anderson-cv/04e645f9145a8ede014079609f373ca8d349af87/data/pubs.xlsx --------------------------------------------------------------------------------