-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcv.html
More file actions
executable file
·330 lines (278 loc) · 13.9 KB
/
Copy pathcv.html
File metadata and controls
executable file
·330 lines (278 loc) · 13.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
<!DOCTYPE html>
<html class="no-js" lang="en">
<head>
<!— basic page needs
================================================== -->
<meta charset="utf-8">
<title>CV</title>
<meta name="description" content="">
<meta name="author" content="">
<!-- mobile specific metas
================================================== -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<!-- CSS
================================================== -->
<link rel="stylesheet" href="css/base.css">
<link rel="stylesheet" href="css/vendor.css">
<link rel="stylesheet" href="css/main.css">
<!-- script
================================================== -->
<script src="js/modernizr.js"></script>
<!-- favicons
================================================== -->
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<link rel="icon" href="favicon.ico" type="image/x-icon">
</head>
<body id="top">
<!-- preloader
================================================== -->
<div id="preloader">
<div id="loader" class="dots-fade">
<div></div>
<div></div>
<div></div>
</div>
</div>
<!-- header
================================================== -->
<header class="s-header header">
<div class="header__logo">
<a class="logo" href="index.html">
<img src="images/logo.png" alt="Homepage" width="100%" height="auto">
</a>
</div>
<!-- navigation bar-->
<a class="header__toggle-menu" href="#0" title="Menu"><span>Menu</span></a>
<nav class="header__nav-wrap">
<h2 class="header__nav-heading h6">Navigate to</h2>
<ul class="header__nav">
<li><a href="index.html" title="">Home</a></li>
<li><a href="projects.html" title="">Publications & Projects</a></li>
<li><a href="cv.html" title="">CV</a></li>
<li><a href="page-blog.html" title="">Blog</a></li>
</ul>
<a href="#0" title="Close Menu" class="header__overlay-close close-mobile-menu">Close</a>
</nav> <!-- end header__nav-wrap -->
</header>
<!-- s-content
================================================== -->
<section class="gdocbg">
<div class="scaled-iframe-wrapper">
<iframe class="embed-doc" scrolling="no" src="https://docs.google.com/document/d/e/2PACX-1vSY0CfswGIq9QDYlNr8NFALmQNOURObYsEbFiwhuGakpeT5Yy8A8kQ-3izqJJU-oHNhofDVyS-vlrfS/pub?embedded=true"></iframe>
</div>
</section>
<script>
// The document is 816px wide by nature: a 624px text column plus 96px of
// padding each side. It is never scaled -- text always renders at its own
// size -- so the page reads as a document rather than a zoomed image, and
// once the window fits all 816px, widening only widens the grey margins.
//
// Narrower than that the document reflows, and its own side padding is
// what gives: the iframe is pulled outward so part of that padding falls
// outside the wrapper and is clipped. On a phone most of it goes, leaving
// the text the room it needs; as the frame grows the padding eases back
// until, at 816px, the document is showing its natural margins in full.
//
// Sizing the frame to the whole document matters: a short iframe scrolls
// internally, and an inner scroll area swallows the touch gesture at its
// end, which is what made scrolling stick partway down the page.
//
// A cross-origin frame's height cannot be read. Google serves the document
// with a permissive Access-Control-Allow-Origin, so it is fetched and
// written into the frame instead, which makes the frame same-origin and
// its height directly measurable -- re-measured on every resize, so the CV
// can be edited freely and nothing here needs updating. Measuring the
// frame that is actually on screen (rather than a hidden copy of it, which
// a mobile browser may lay out differently) is what keeps the frame height
// and the content in agreement, with no band of empty grey at the end.
// Writing it in also lets us pin text-size-adjust, which stops phone
// browsers inflating some blocks and not others -- the reason table text
// used to render smaller than body text.
//
// The markup keeps the plain cross-origin src, so the CV still shows
// without JavaScript, or if the fetch fails; FALLBACK_HEIGHTS then sizes
// it. It is also what the first paint uses, before the fetch lands, so it
// is sampled every 20px of column width: any error here shows up as the
// frame resizing slightly once the real measurement arrives. Interpolating
// this convex curve errs high, so a stale table costs a little extra band
// above the footer, never clipped text.
(function () {
var DOC_URL = 'https://docs.google.com/document/d/e/2PACX-1vSY0CfswGIq9QDYlNr8NFALmQNOURObYsEbFiwhuGakpeT5Yy8A8kQ-3izqJJU-oHNhofDVyS-vlrfS/pub?embedded=true';
var DOC_WIDTH = 816; // the document's natural full width
var DOC_PAD = 96; // its own side padding
var TAIL_PAD = 72; // its trailing padding
var BODY_MARGIN = 8; // default body margin inside the frame
var MIN_PAD = 16; // padding still shown at the narrowest sizes
var MIN_FRAME = 320; // frame width at which MIN_PAD applies
var FALLBACK_HEIGHTS = [
[260, 18969], [270, 18215], [280, 17387], [290, 16412], [300, 15603],
[310, 14702], [320, 14058], [330, 13433], [340, 12955], [350, 12550],
[360, 12146], [370, 11557], [380, 11116], [390, 10840], [400, 10619],
[410, 10380], [420, 10086], [430, 9865], [440, 9608], [450, 9442],
[460, 9277], [470, 9056], [480, 8762], [490, 8523], [500, 8339],
[510, 8228], [520, 8118], [530, 7989], [540, 7842], [550, 7658],
[560, 7603], [570, 7364], [580, 7291], [590, 7107], [600, 6978],
[610, 6849], [620, 6757], [624, 6739]
];
var CACHE_KEY = 'cv-doc-height';
var wrap = document.querySelector('.scaled-iframe-wrapper');
if (!wrap) return;
var frame = wrap.querySelector('.embed-doc');
var liveDoc = null;
var fetchFailed = false;
// Heights already measured in this browser, keyed by column width, so a
// return visit sizes the frame exactly on the first paint instead of
// estimating and then correcting once the fetch lands. A stale entry
// (the CV changed since) costs one resize on the next visit and is
// then overwritten.
var cache = {};
try {
cache = JSON.parse(localStorage.getItem(CACHE_KEY)) || {};
} catch (e) {
cache = {};
}
function remember(column, height) {
if (cache[column] === height) return;
cache[column] = height;
try {
localStorage.setItem(CACHE_KEY, JSON.stringify(cache));
} catch (e) { /* private mode, or full: not worth handling */ }
}
// How much of the document's own side padding to show at this frame
// width: all of it once the frame fits the document, easing down to
// MIN_PAD on the narrowest screens. The easing is quadratic so that
// phones, where every pixel of column counts, keep nearly all their
// width, while anything tablet-sized and up quickly takes on the
// document's real margins.
function paddingFor(frameWidth) {
if (frameWidth >= DOC_WIDTH) return DOC_PAD;
var t = (frameWidth - MIN_FRAME) / (DOC_WIDTH - MIN_FRAME);
if (t < 0) t = 0;
if (t > 1) t = 1;
return Math.round(MIN_PAD + (DOC_PAD - MIN_PAD) * t * t);
}
function fallbackHeight(column) {
var pts = FALLBACK_HEIGHTS, last = pts.length - 1, i, a = pts[0], b = pts[1];
if (column >= pts[last][0]) return pts[last][1];
if (column > pts[0][0]) {
for (i = 0; i < last; i++) {
if (column <= pts[i + 1][0]) { a = pts[i]; b = pts[i + 1]; break; }
}
}
// interpolate (and, below the first point, extrapolate) in 1/column,
// where the curve is very nearly a straight line
var xa = 1 / a[0], xb = 1 / b[0], x = 1 / column;
return a[1] + (x - xa) * (b[1] - a[1]) / (xb - xa);
}
function fitDoc() {
var frameWidth = wrap.getBoundingClientRect().width || DOC_WIDTH;
var shown = paddingFor(frameWidth);
var column = Math.max(1, Math.round(frameWidth - 2 * shown));
wrap.style.setProperty('--doc-clip', (DOC_PAD - shown) + 'px');
var required = null;
if (liveDoc) {
// Read the frame's own box first so the width change above is
// applied before the document's height is measured.
frame.getBoundingClientRect();
required = liveDoc.documentElement.scrollHeight - BODY_MARGIN;
if (required < 1) required = null;
if (required) remember(column, required);
}
if (!required) {
// Before the fetch lands, a cached height from a previous visit
// is exact for the document as it was then, so it avoids the
// brief resize an estimate would cause. If the fetch has failed
// outright there will be no correction, so fall back to
// whichever of the two is larger: a cached height that predates
// an edit could be too short and clip the end of the CV,
// whereas erring long only shows a little extra band.
if (fetchFailed) {
required = Math.max(cache[column] || 0, fallbackHeight(column));
} else {
required = cache[column] || fallbackHeight(column);
}
}
// Trim the trailing padding by the same proportion as the sides, so
// the document's bottom margin matches the ones beside it.
var tail = Math.round(TAIL_PAD * (shown / DOC_PAD));
wrap.style.setProperty('--doc-height',
Math.ceil(required - (TAIL_PAD - tail)) + 'px');
}
fitDoc(); // lay out immediately from the fallback, then refine
window.addEventListener('resize', fitDoc);
window.addEventListener('orientationchange', fitDoc);
if (!window.fetch) return;
fetch(DOC_URL, { credentials: 'omit' })
.then(function (response) {
if (!response.ok) throw new Error(response.status);
return response.text();
})
.then(function (html) {
// A fresh frame starts on about:blank, which is same-origin and
// so can be written to and measured.
var written = document.createElement('iframe');
written.className = frame.className;
written.setAttribute('scrolling', 'no');
written.setAttribute('title', 'Curriculum Vitae');
wrap.replaceChild(written, frame);
frame = written;
var d = frame.contentDocument;
d.open();
d.write(html);
d.close();
var base = d.createElement('base');
base.target = '_blank'; // links leave the frame
d.head.appendChild(base);
var pin = d.createElement('style');
pin.textContent = 'html{-webkit-text-size-adjust:100%;' +
'text-size-adjust:100%}';
d.head.appendChild(pin);
liveDoc = d;
fitDoc();
// Re-measure once more after the frame has settled.
window.requestAnimationFrame(fitDoc);
})
.catch(function () {
liveDoc = null; // keep the cross-origin frame
fetchFailed = true; // and size it conservatively
fitDoc();
});
})();
</script>
<footer class="s-footer">
<div class="col-six">
<div class="s-footer__copyright">
<p style="color: lightsteelblue; font-size: 10px;"><!-- Link back to Colorlib can't be removed. Template is licensed under CC BY 3.0. -->
Copyright ©<script>document.write(new Date().getFullYear());</script> All rights reserved | Website made with <i class="fa fa-heart" aria-hidden="true"></i> by Xinlan Emily Hu with an initial template by <a href="https://colorlib.com" target="_blank" style="color:lightsteelblue;">Colorlib</a>
<!-- Link back to Colorlib can't be removed. Template is licensed under CC BY 3.0. -->
</p>
</div>
</div>
<div class="go-top">
<a class="smoothscroll" title="Back to Top" href="#top"></a>
</div>
</footer> <!-- end s-footer -->
<!-- Java Script
================================================== -->
<script src="js/jquery-3.2.1.min.js"></script>
<script src="js/plugins.js"></script>
<script src="js/main.js"></script>
<script>
var coll = document.getElementsByClassName("collapsible");
var i;
for (i = 0; i < coll.length; i++) {
coll[i].addEventListener("click", function() {
this.classList.toggle("active");
var content = this.nextElementSibling;
if (content.style.display === "block") {
content.style.display = "none";
this.innerHTML = "Read More";
} else {
content.style.display = "block";
this.innerHTML = "Read Less";
}
});
}
</script>
</body>
</html>