white-rabbit 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +51 -0
- data/_includes/content-work.html +0 -0
- data/_includes/doctype-closed.html +14 -0
- data/_includes/doctype-head.html +15 -0
- data/_includes/doctype-open.html +32 -0
- data/_includes/post-content.html +14 -0
- data/_layouts/default.html +7 -0
- data/_layouts/page.html +70 -0
- data/_layouts/post.html +5 -0
- data/_sass/_blocks.scss +59 -0
- data/_sass/_content.scss +104 -0
- data/_sass/_custom-properties.scss +45 -0
- data/_sass/_general.scss +11 -0
- data/_sass/_grid.scss +14 -0
- data/_sass/_navigation.scss +45 -0
- data/_sass/_resets.scss +87 -0
- data/_sass/_typography.scss +10 -0
- data/_sass/app.scss +13 -0
- data/_sass/third-party/_tabby.scss +71 -0
- data/assets/images/hero-blog.jpg +0 -0
- data/assets/images/hero-contact.jpg +0 -0
- data/assets/images/hero-photos.jpg +0 -0
- data/assets/images/hero-portrait.jpg +0 -0
- data/assets/images/hero-work.jpg +0 -0
- data/assets/scripts/app.js +518 -0
- data/assets/styles/app.scss +6 -0
- metadata +183 -0
data/_sass/_general.scss
ADDED
data/_sass/_grid.scss
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
.site-header,
|
2
|
+
.site-footer {
|
3
|
+
padding: var(--spacing-4);
|
4
|
+
}
|
5
|
+
|
6
|
+
.site-footer {
|
7
|
+
color: var(--dva-secondary-base);
|
8
|
+
text-align: center;
|
9
|
+
}
|
10
|
+
|
11
|
+
// navigation
|
12
|
+
.site-header .navigation {
|
13
|
+
display: flex;
|
14
|
+
align-items: center;
|
15
|
+
}
|
16
|
+
|
17
|
+
.site-header .logo .header,
|
18
|
+
.site-header .logo .subheader {
|
19
|
+
display: block;
|
20
|
+
}
|
21
|
+
|
22
|
+
.site-header .logo .header {
|
23
|
+
font-size: var(--font-size-5);
|
24
|
+
font-weight: 700;
|
25
|
+
}
|
26
|
+
|
27
|
+
.site-header .logo .subheader {
|
28
|
+
font-size: var(--font-size-2);
|
29
|
+
font-weight: 400;
|
30
|
+
margin-top: calc(-1*var(--spacing-1));
|
31
|
+
position: relative;
|
32
|
+
}
|
33
|
+
|
34
|
+
.site-header .links {
|
35
|
+
flex-grow: 1;
|
36
|
+
text-align: right;
|
37
|
+
}
|
38
|
+
|
39
|
+
.site-header .link {
|
40
|
+
display: inline-block;
|
41
|
+
}
|
42
|
+
|
43
|
+
.site-header .link:not(:last-child) {
|
44
|
+
margin-right: var(--spacing-3);
|
45
|
+
}
|
data/_sass/_resets.scss
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
/*! minireset.css v0.0.3 | MIT License | github.com/jgthms/minireset.css */
|
2
|
+
html {
|
3
|
+
background-color: var(--meka-accent);
|
4
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 304 304' width='304' height='304'%3E%3Cpath fill='%23ffffff' fill-opacity='0.025' d='M44.1 224a5 5 0 1 1 0 2H0v-2h44.1zm160 48a5 5 0 1 1 0 2H82v-2h122.1zm57.8-46a5 5 0 1 1 0-2H304v2h-42.1zm0 16a5 5 0 1 1 0-2H304v2h-42.1zm6.2-114a5 5 0 1 1 0 2h-86.2a5 5 0 1 1 0-2h86.2zm-256-48a5 5 0 1 1 0 2H0v-2h12.1zm185.8 34a5 5 0 1 1 0-2h86.2a5 5 0 1 1 0 2h-86.2zM258 12.1a5 5 0 1 1-2 0V0h2v12.1zm-64 208a5 5 0 1 1-2 0v-54.2a5 5 0 1 1 2 0v54.2zm48-198.2V80h62v2h-64V21.9a5 5 0 1 1 2 0zm16 16V64h46v2h-48V37.9a5 5 0 1 1 2 0zm-128 96V208h16v12.1a5 5 0 1 1-2 0V210h-16v-76.1a5 5 0 1 1 2 0zm-5.9-21.9a5 5 0 1 1 0 2H114v48H85.9a5 5 0 1 1 0-2H112v-48h12.1zm-6.2 130a5 5 0 1 1 0-2H176v-74.1a5 5 0 1 1 2 0V242h-60.1zm-16-64a5 5 0 1 1 0-2H114v48h10.1a5 5 0 1 1 0 2H112v-48h-10.1zM66 284.1a5 5 0 1 1-2 0V274H50v30h-2v-32h18v12.1zM236.1 176a5 5 0 1 1 0 2H226v94h48v32h-2v-30h-48v-98h12.1zm25.8-30a5 5 0 1 1 0-2H274v44.1a5 5 0 1 1-2 0V146h-10.1zm-64 96a5 5 0 1 1 0-2H208v-80h16v-14h-42.1a5 5 0 1 1 0-2H226v18h-16v80h-12.1zm86.2-210a5 5 0 1 1 0 2H272V0h2v32h10.1zM98 101.9V146H53.9a5 5 0 1 1 0-2H96v-42.1a5 5 0 1 1 2 0zM53.9 34a5 5 0 1 1 0-2H80V0h2v34H53.9zm60.1 3.9V66H82v64H69.9a5 5 0 1 1 0-2H80V64h32V37.9a5 5 0 1 1 2 0zM101.9 82a5 5 0 1 1 0-2H128V37.9a5 5 0 1 1 2 0V82h-28.1zm16-64a5 5 0 1 1 0-2H146v44.1a5 5 0 1 1-2 0V18h-26.1zm102.2 270a5 5 0 1 1 0 2H98v14h-2v-16h124.1zM242 149.9V160h16v34h-16v62h48v48h-2v-46h-48v-66h16v-30h-16v-12.1a5 5 0 1 1 2 0zM53.9 18a5 5 0 1 1 0-2H64V2H48V0h18v18H53.9zm112 32a5 5 0 1 1 0-2H192V0h50v2h-48v48h-28.1zm-48-48a5 5 0 0 1-9.8-2h2.07a3 3 0 1 0 5.66 0H178v34h-18V21.9a5 5 0 1 1 2 0V32h14V2h-58.1zm0 96a5 5 0 1 1 0-2H137l32-32h39V21.9a5 5 0 1 1 2 0V66h-40.17l-32 32H117.9zm28.1 90.1a5 5 0 1 1-2 0v-76.51L175.59 80H224V21.9a5 5 0 1 1 2 0V82h-49.59L146 112.41v75.69zm16 32a5 5 0 1 1-2 0v-99.51L184.59 96H300.1a5 5 0 0 1 3.9-3.9v2.07a3 3 0 0 0 0 5.66v2.07a5 5 0 0 1-3.9-3.9H185.41L162 121.41v98.69zm-144-64a5 5 0 1 1-2 0v-3.51l48-48V48h32V0h2v50H66v55.41l-48 48v2.69zM50 53.9v43.51l-48 48V208h26.1a5 5 0 1 1 0 2H0v-65.41l48-48V53.9a5 5 0 1 1 2 0zm-16 16V89.41l-34 34v-2.82l32-32V69.9a5 5 0 1 1 2 0zM12.1 32a5 5 0 1 1 0 2H9.41L0 43.41V40.6L8.59 32h3.51zm265.8 18a5 5 0 1 1 0-2h18.69l7.41-7.41v2.82L297.41 50H277.9zm-16 160a5 5 0 1 1 0-2H288v-71.41l16-16v2.82l-14 14V210h-28.1zm-208 32a5 5 0 1 1 0-2H64v-22.59L40.59 194H21.9a5 5 0 1 1 0-2H41.41L66 216.59V242H53.9zm150.2 14a5 5 0 1 1 0 2H96v-56.6L56.6 162H37.9a5 5 0 1 1 0-2h19.5L98 200.6V256h106.1zm-150.2 2a5 5 0 1 1 0-2H80v-46.59L48.59 178H21.9a5 5 0 1 1 0-2H49.41L82 208.59V258H53.9zM34 39.8v1.61L9.41 66H0v-2h8.59L32 40.59V0h2v39.8zM2 300.1a5 5 0 0 1 3.9 3.9H3.83A3 3 0 0 0 0 302.17V256h18v48h-2v-46H2v42.1zM34 241v63h-2v-62H0v-2h34v1zM17 18H0v-2h16V0h2v18h-1zm273-2h14v2h-16V0h2v16zm-32 273v15h-2v-14h-14v14h-2v-16h18v1zM0 92.1A5.02 5.02 0 0 1 6 97a5 5 0 0 1-6 4.9v-2.07a3 3 0 1 0 0-5.66V92.1zM80 272h2v32h-2v-32zm37.9 32h-2.07a3 3 0 0 0-5.66 0h-2.07a5 5 0 0 1 9.8 0zM5.9 0A5.02 5.02 0 0 1 0 5.9V3.83A3 3 0 0 0 3.83 0H5.9zm294.2 0h2.07A3 3 0 0 0 304 3.83V5.9a5 5 0 0 1-3.9-5.9zm3.9 300.1v2.07a3 3 0 0 0-1.83 1.83h-2.07a5 5 0 0 1 3.9-3.9zM97 100a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-48 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 96a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-144a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-96 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm96 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-32 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM49 36a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-32 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM33 68a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 240a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm80-176a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm112 176a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM17 180a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM17 84a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6z'%3E%3C/path%3E%3C/svg%3E");
|
5
|
+
box-sizing: border-box;
|
6
|
+
}
|
7
|
+
|
8
|
+
html,
|
9
|
+
body,
|
10
|
+
p,
|
11
|
+
ol,
|
12
|
+
ul,
|
13
|
+
li,
|
14
|
+
dl,
|
15
|
+
dt,
|
16
|
+
dd,
|
17
|
+
blockquote,
|
18
|
+
figure,
|
19
|
+
fieldset,
|
20
|
+
legend,
|
21
|
+
textarea,
|
22
|
+
pre,
|
23
|
+
iframe,
|
24
|
+
hr,
|
25
|
+
h1,
|
26
|
+
h2,
|
27
|
+
h3,
|
28
|
+
h4,
|
29
|
+
h5,
|
30
|
+
h6 {
|
31
|
+
margin: 0;
|
32
|
+
padding: 0;
|
33
|
+
}
|
34
|
+
|
35
|
+
h1,
|
36
|
+
h2,
|
37
|
+
h3,
|
38
|
+
h4,
|
39
|
+
h5,
|
40
|
+
h6 {
|
41
|
+
font-weight: normal;
|
42
|
+
font-size: 100%;
|
43
|
+
}
|
44
|
+
|
45
|
+
ul {
|
46
|
+
list-style: none;
|
47
|
+
}
|
48
|
+
|
49
|
+
button,
|
50
|
+
input,
|
51
|
+
select,
|
52
|
+
textarea {
|
53
|
+
margin: 0;
|
54
|
+
}
|
55
|
+
|
56
|
+
*,
|
57
|
+
*:before,
|
58
|
+
*:after {
|
59
|
+
box-sizing: inherit;
|
60
|
+
}
|
61
|
+
|
62
|
+
img,
|
63
|
+
embed,
|
64
|
+
iframe,
|
65
|
+
object,
|
66
|
+
audio,
|
67
|
+
video {
|
68
|
+
height: auto;
|
69
|
+
max-width: 100%;
|
70
|
+
width: 100%;
|
71
|
+
vertical-align: middle;
|
72
|
+
}
|
73
|
+
|
74
|
+
iframe {
|
75
|
+
border: 0;
|
76
|
+
}
|
77
|
+
|
78
|
+
table {
|
79
|
+
border-collapse: collapse;
|
80
|
+
border-spacing: 0;
|
81
|
+
}
|
82
|
+
|
83
|
+
td,
|
84
|
+
th {
|
85
|
+
padding: 0;
|
86
|
+
text-align: left;
|
87
|
+
}
|
data/_sass/app.scss
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
/*!
|
2
|
+
* Tabby v11.2.0: Simple, mobile-first toggle tabs.
|
3
|
+
* (c) 2016 Chris Ferdinandi
|
4
|
+
* MIT License
|
5
|
+
* http://github.com/cferdinandi/tabby
|
6
|
+
*/
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Tab content
|
10
|
+
*/
|
11
|
+
|
12
|
+
/* line 4, /Users/cferdinandi/Sites/tabby/src/sass/components/_tabby.scss */
|
13
|
+
.js-tabby .tabs-pane {
|
14
|
+
border: 0;
|
15
|
+
clip: rect(0 0 0 0);
|
16
|
+
height: 1px;
|
17
|
+
margin: -1px;
|
18
|
+
opacity: 0;
|
19
|
+
overflow: hidden;
|
20
|
+
padding: 0;
|
21
|
+
position: absolute;
|
22
|
+
transform: translateY(40px);
|
23
|
+
transition: opacity 250ms ease-in, transform 300ms ease-in;
|
24
|
+
}
|
25
|
+
|
26
|
+
/* line 14, /Users/cferdinandi/Sites/tabby/src/sass/components/_tabby.scss */
|
27
|
+
.js-tabby .tabs-pane.active {
|
28
|
+
clip: auto;
|
29
|
+
height: auto;
|
30
|
+
margin: 0;
|
31
|
+
opacity: 1;
|
32
|
+
overflow: visible;
|
33
|
+
position: static;
|
34
|
+
transform: translateY(0px);
|
35
|
+
}
|
36
|
+
|
37
|
+
/* line 23, /Users/cferdinandi/Sites/tabby/src/sass/components/_tabby.scss */
|
38
|
+
.js-tabby .tabs-pane:focus {
|
39
|
+
outline: none;
|
40
|
+
}
|
41
|
+
|
42
|
+
// custom styling
|
43
|
+
.tabs {
|
44
|
+
margin-bottom: var(--spacing-4);
|
45
|
+
text-align: center;
|
46
|
+
}
|
47
|
+
|
48
|
+
.tabs li {
|
49
|
+
display: inline-block;
|
50
|
+
font-size: var(--font-size-1);
|
51
|
+
margin-right: var(--spacing-3);
|
52
|
+
}
|
53
|
+
|
54
|
+
.tabs a {
|
55
|
+
background-color: var(--meka-body);
|
56
|
+
color: var(--meka-accent);
|
57
|
+
padding: var(--spacing-2) var(--spacing-3);
|
58
|
+
}
|
59
|
+
|
60
|
+
.tabs a:hover,
|
61
|
+
.tabs .active a {
|
62
|
+
color: var(--meka-body);
|
63
|
+
}
|
64
|
+
|
65
|
+
.tabs a:hover {
|
66
|
+
background-color: var(--dva-secondary-dark);
|
67
|
+
}
|
68
|
+
|
69
|
+
.tabs .active a {
|
70
|
+
background-color: var(--meka-matrix);
|
71
|
+
}
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,518 @@
|
|
1
|
+
/*!
|
2
|
+
* Tabby v11.2.0: Simple, mobile-first toggle tabs.
|
3
|
+
* (c) 2016 Chris Ferdinandi
|
4
|
+
* MIT License
|
5
|
+
* http://github.com/cferdinandi/tabby
|
6
|
+
*/
|
7
|
+
|
8
|
+
(function (root, factory) {
|
9
|
+
if (typeof define === 'function' && define.amd) {
|
10
|
+
define([], factory(root));
|
11
|
+
} else if (typeof exports === 'object') {
|
12
|
+
module.exports = factory(root);
|
13
|
+
} else {
|
14
|
+
root.tabby = factory(root);
|
15
|
+
}
|
16
|
+
})(typeof global !== 'undefined' ? global : this.window || this.global, (function (root) {
|
17
|
+
|
18
|
+
'use strict';
|
19
|
+
|
20
|
+
//
|
21
|
+
// Variables
|
22
|
+
//
|
23
|
+
|
24
|
+
var tabby = {}; // Object for public APIs
|
25
|
+
var supports = 'querySelector' in document && 'addEventListener' in root && 'classList' in document.createElement('_') && 'onhashchange' in root; // Feature test
|
26
|
+
var settings, tab;
|
27
|
+
|
28
|
+
// Default settings
|
29
|
+
var defaults = {
|
30
|
+
selectorToggle: '[data-tab]',
|
31
|
+
selectorToggleGroup: '[data-tabs]',
|
32
|
+
selectorContent: '[data-tabs-pane]',
|
33
|
+
selectorContentGroup: '[data-tabs-content]',
|
34
|
+
toggleActiveClass: 'active',
|
35
|
+
contentActiveClass: 'active',
|
36
|
+
initClass: 'js-tabby',
|
37
|
+
stopVideo: true,
|
38
|
+
callback: function () {}
|
39
|
+
};
|
40
|
+
|
41
|
+
|
42
|
+
//
|
43
|
+
// Methods
|
44
|
+
//
|
45
|
+
|
46
|
+
/**
|
47
|
+
* A simple forEach() implementation for Arrays, Objects and NodeLists
|
48
|
+
* @private
|
49
|
+
* @param {Array|Object|NodeList} collection Collection of items to iterate
|
50
|
+
* @param {Function} callback Callback function for each iteration
|
51
|
+
* @param {Array|Object|NodeList} scope Object/NodeList/Array that forEach is iterating over (aka `this`)
|
52
|
+
*/
|
53
|
+
var forEach = function (collection, callback, scope) {
|
54
|
+
if (Object.prototype.toString.call(collection) === '[object Object]') {
|
55
|
+
for (var prop in collection) {
|
56
|
+
if (Object.prototype.hasOwnProperty.call(collection, prop)) {
|
57
|
+
callback.call(scope, collection[prop], prop, collection);
|
58
|
+
}
|
59
|
+
}
|
60
|
+
} else {
|
61
|
+
for (var i = 0, len = collection.length; i < len; i++) {
|
62
|
+
callback.call(scope, collection[i], i, collection);
|
63
|
+
}
|
64
|
+
}
|
65
|
+
};
|
66
|
+
|
67
|
+
/**
|
68
|
+
* Merge defaults with user options
|
69
|
+
* @private
|
70
|
+
* @param {Object} defaults Default settings
|
71
|
+
* @param {Object} options User options
|
72
|
+
* @returns {Object} Merged values of defaults and options
|
73
|
+
*/
|
74
|
+
var extend = function () {
|
75
|
+
|
76
|
+
// Variables
|
77
|
+
var extended = {};
|
78
|
+
var deep = false;
|
79
|
+
var i = 0;
|
80
|
+
var length = arguments.length;
|
81
|
+
|
82
|
+
// Check if a deep merge
|
83
|
+
if (Object.prototype.toString.call(arguments[0]) === '[object Boolean]') {
|
84
|
+
deep = arguments[0];
|
85
|
+
i++;
|
86
|
+
}
|
87
|
+
|
88
|
+
// Merge the object into the extended object
|
89
|
+
var merge = function (obj) {
|
90
|
+
for (var prop in obj) {
|
91
|
+
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
|
92
|
+
// If deep merge and property is an object, merge properties
|
93
|
+
if (deep && Object.prototype.toString.call(obj[prop]) === '[object Object]') {
|
94
|
+
extended[prop] = extend(true, extended[prop], obj[prop]);
|
95
|
+
} else {
|
96
|
+
extended[prop] = obj[prop];
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
};
|
101
|
+
|
102
|
+
// Loop through each object and conduct a merge
|
103
|
+
for (; i < length; i++) {
|
104
|
+
var obj = arguments[i];
|
105
|
+
merge(obj);
|
106
|
+
}
|
107
|
+
|
108
|
+
return extended;
|
109
|
+
|
110
|
+
};
|
111
|
+
|
112
|
+
/**
|
113
|
+
* Get the closest matching element up the DOM tree.
|
114
|
+
* @private
|
115
|
+
* @param {Element} elem Starting element
|
116
|
+
* @param {String} selector Selector to match against
|
117
|
+
* @return {Boolean|Element} Returns null if not match found
|
118
|
+
*/
|
119
|
+
var getClosest = function (elem, selector) {
|
120
|
+
|
121
|
+
// Element.matches() polyfill
|
122
|
+
if (!Element.prototype.matches) {
|
123
|
+
Element.prototype.matches =
|
124
|
+
Element.prototype.matchesSelector ||
|
125
|
+
Element.prototype.mozMatchesSelector ||
|
126
|
+
Element.prototype.msMatchesSelector ||
|
127
|
+
Element.prototype.oMatchesSelector ||
|
128
|
+
Element.prototype.webkitMatchesSelector ||
|
129
|
+
function (s) {
|
130
|
+
var matches = (this.document || this.ownerDocument).querySelectorAll(s),
|
131
|
+
i = matches.length;
|
132
|
+
while (--i >= 0 && matches.item(i) !== this) {}
|
133
|
+
return i > -1;
|
134
|
+
};
|
135
|
+
}
|
136
|
+
|
137
|
+
// Get closest match
|
138
|
+
for (; elem && elem !== document; elem = elem.parentNode) {
|
139
|
+
if (elem.matches(selector)) return elem;
|
140
|
+
}
|
141
|
+
|
142
|
+
return null;
|
143
|
+
|
144
|
+
};
|
145
|
+
|
146
|
+
/**
|
147
|
+
* Escape special characters for use with querySelector
|
148
|
+
* @public
|
149
|
+
* @param {String} id The anchor ID to escape
|
150
|
+
* @author Mathias Bynens
|
151
|
+
* @link https://github.com/mathiasbynens/CSS.escape
|
152
|
+
*/
|
153
|
+
var escapeCharacters = function (id) {
|
154
|
+
|
155
|
+
// Remove leading hash
|
156
|
+
if (id.charAt(0) === '#') {
|
157
|
+
id = id.substr(1);
|
158
|
+
}
|
159
|
+
|
160
|
+
var string = String(id);
|
161
|
+
var length = string.length;
|
162
|
+
var index = -1;
|
163
|
+
var codeUnit;
|
164
|
+
var result = '';
|
165
|
+
var firstCodeUnit = string.charCodeAt(0);
|
166
|
+
while (++index < length) {
|
167
|
+
codeUnit = string.charCodeAt(index);
|
168
|
+
// Note: there’s no need to special-case astral symbols, surrogate
|
169
|
+
// pairs, or lone surrogates.
|
170
|
+
|
171
|
+
// If the character is NULL (U+0000), then throw an
|
172
|
+
// `InvalidCharacterError` exception and terminate these steps.
|
173
|
+
if (codeUnit === 0x0000) {
|
174
|
+
throw new InvalidCharacterError(
|
175
|
+
'Invalid character: the input contains U+0000.'
|
176
|
+
);
|
177
|
+
}
|
178
|
+
|
179
|
+
if (
|
180
|
+
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
|
181
|
+
// U+007F, […]
|
182
|
+
(codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
|
183
|
+
// If the character is the first character and is in the range [0-9]
|
184
|
+
// (U+0030 to U+0039), […]
|
185
|
+
(index === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
|
186
|
+
// If the character is the second character and is in the range [0-9]
|
187
|
+
// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
|
188
|
+
(
|
189
|
+
index === 1 &&
|
190
|
+
codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
|
191
|
+
firstCodeUnit === 0x002D
|
192
|
+
)
|
193
|
+
) {
|
194
|
+
// http://dev.w3.org/csswg/cssom/#escape-a-character-as-code-point
|
195
|
+
result += '\\' + codeUnit.toString(16) + ' ';
|
196
|
+
continue;
|
197
|
+
}
|
198
|
+
|
199
|
+
// If the character is not handled by one of the above rules and is
|
200
|
+
// greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
|
201
|
+
// is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
|
202
|
+
// U+005A), or [a-z] (U+0061 to U+007A), […]
|
203
|
+
if (
|
204
|
+
codeUnit >= 0x0080 ||
|
205
|
+
codeUnit === 0x002D ||
|
206
|
+
codeUnit === 0x005F ||
|
207
|
+
codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
|
208
|
+
codeUnit >= 0x0041 && codeUnit <= 0x005A ||
|
209
|
+
codeUnit >= 0x0061 && codeUnit <= 0x007A
|
210
|
+
) {
|
211
|
+
// the character itself
|
212
|
+
result += string.charAt(index);
|
213
|
+
continue;
|
214
|
+
}
|
215
|
+
|
216
|
+
// Otherwise, the escaped character.
|
217
|
+
// http://dev.w3.org/csswg/cssom/#escape-a-character
|
218
|
+
result += '\\' + string.charAt(index);
|
219
|
+
|
220
|
+
}
|
221
|
+
|
222
|
+
return '#' + result;
|
223
|
+
|
224
|
+
};
|
225
|
+
|
226
|
+
/**
|
227
|
+
* Stop YouTube, Vimeo, and HTML5 videos from playing when leaving the slide
|
228
|
+
* @private
|
229
|
+
* @param {Element} content The content container the video is in
|
230
|
+
* @param {String} activeClass The class asigned to expanded content areas
|
231
|
+
*/
|
232
|
+
var stopVideos = function (content, settings) {
|
233
|
+
|
234
|
+
// Check if stop video enabled
|
235
|
+
if (!settings.stopVideo) return;
|
236
|
+
|
237
|
+
// Only run if content container is closed
|
238
|
+
if (content.classList.contains(settings.contentActiveClass)) return;
|
239
|
+
|
240
|
+
// Check if the video is an iframe or HTML5 video
|
241
|
+
var iframe = content.querySelector('iframe');
|
242
|
+
var video = content.querySelector('video');
|
243
|
+
|
244
|
+
// Stop the video
|
245
|
+
if (iframe) {
|
246
|
+
var iframeSrc = iframe.src;
|
247
|
+
iframe.src = iframeSrc;
|
248
|
+
}
|
249
|
+
if (video) {
|
250
|
+
video.pause();
|
251
|
+
}
|
252
|
+
|
253
|
+
};
|
254
|
+
|
255
|
+
/**
|
256
|
+
* Add focus to tab
|
257
|
+
* @private
|
258
|
+
* @param {node} tab The content to bring into focus
|
259
|
+
* @param {object} settings Options
|
260
|
+
*/
|
261
|
+
var adjustFocus = function (tab, settings) {
|
262
|
+
|
263
|
+
if (tab.hasAttribute('data-tab-no-focus')) return;
|
264
|
+
|
265
|
+
// If tab is closed, remove tabindex
|
266
|
+
if (!tab.classList.contains(settings.contentActiveClass)) {
|
267
|
+
if (tab.hasAttribute('data-tab-focused')) {
|
268
|
+
tab.removeAttribute('tabindex');
|
269
|
+
}
|
270
|
+
return;
|
271
|
+
}
|
272
|
+
|
273
|
+
// Get current position on the page
|
274
|
+
var position = {
|
275
|
+
x: root.pageXOffset,
|
276
|
+
y: root.pageYOffset
|
277
|
+
};
|
278
|
+
|
279
|
+
// Set focus and reset position to account for page jump on focus
|
280
|
+
tab.focus();
|
281
|
+
if (document.activeElement.id !== tab.id) {
|
282
|
+
tab.setAttribute('tabindex', '-1');
|
283
|
+
tab.setAttribute('data-tab-focused', true);
|
284
|
+
tab.focus();
|
285
|
+
}
|
286
|
+
root.scrollTo(position.x, position.y);
|
287
|
+
|
288
|
+
};
|
289
|
+
|
290
|
+
/**
|
291
|
+
* Toggle tab toggle active state
|
292
|
+
* @private
|
293
|
+
* @param {Node} toggle The toggle element
|
294
|
+
* @param {Object} settings
|
295
|
+
*/
|
296
|
+
var toggleToggles = function (toggle, settings) {
|
297
|
+
|
298
|
+
// Variables
|
299
|
+
var toggleGroup = getClosest(toggle, settings.selectorToggleGroup); // The parent for the toggle group
|
300
|
+
if (!toggleGroup) return;
|
301
|
+
var toggles = toggleGroup.querySelectorAll(settings.selectorToggle); // The toggles in the group
|
302
|
+
var toggleList;
|
303
|
+
|
304
|
+
// Show or hide each toggle
|
305
|
+
// @todo Start here
|
306
|
+
forEach(toggles, (function (item) {
|
307
|
+
|
308
|
+
// If this is the selected toggle, activate it
|
309
|
+
if (item.hash === toggle.hash) {
|
310
|
+
|
311
|
+
// Add active class
|
312
|
+
item.classList.add(settings.toggleActiveClass);
|
313
|
+
|
314
|
+
// If toggle is a list item, activate <li> element, too
|
315
|
+
toggleList = getClosest(item, 'li');
|
316
|
+
if (toggleList) {
|
317
|
+
toggleList.classList.add(settings.toggleActiveClass);
|
318
|
+
}
|
319
|
+
|
320
|
+
return;
|
321
|
+
|
322
|
+
}
|
323
|
+
|
324
|
+
// Otherwise, deactivate it
|
325
|
+
item.classList.remove(settings.toggleActiveClass);
|
326
|
+
toggleList = getClosest(item, 'li');
|
327
|
+
if (toggleList) {
|
328
|
+
toggleList.classList.remove(settings.toggleActiveClass);
|
329
|
+
}
|
330
|
+
|
331
|
+
}));
|
332
|
+
|
333
|
+
};
|
334
|
+
|
335
|
+
/**
|
336
|
+
* Toggle tab active state
|
337
|
+
* @private
|
338
|
+
* @param {String} tabID The ID of the tab to activate
|
339
|
+
* @param {Object} settings
|
340
|
+
*/
|
341
|
+
var toggleTabs = function (tabID, settings) {
|
342
|
+
|
343
|
+
// Variables
|
344
|
+
var tab = document.querySelector(escapeCharacters(tabID)); // The selected tab
|
345
|
+
if (!tab) return;
|
346
|
+
var tabGroup = getClosest(tab, settings.selectorContentGroup); // The parent for the tab group
|
347
|
+
if (!tabGroup) return;
|
348
|
+
var tabs = tabGroup.querySelectorAll(settings.selectorContent); // The tabs in the group
|
349
|
+
|
350
|
+
// Show or hide each tab
|
351
|
+
forEach(tabs, (function (tab) {
|
352
|
+
|
353
|
+
// If this is the selected tab, show it
|
354
|
+
if (tab.id === tabID.substring(1)) {
|
355
|
+
tab.classList.add(settings.contentActiveClass);
|
356
|
+
adjustFocus(tab, settings);
|
357
|
+
return;
|
358
|
+
}
|
359
|
+
|
360
|
+
// Otherwise, hide it
|
361
|
+
tab.classList.remove(settings.contentActiveClass);
|
362
|
+
stopVideos(tab, settings);
|
363
|
+
adjustFocus(tab, settings);
|
364
|
+
|
365
|
+
}));
|
366
|
+
|
367
|
+
};
|
368
|
+
|
369
|
+
/**
|
370
|
+
* Show a tab and hide all others
|
371
|
+
* @public
|
372
|
+
* @param {Element} toggle The element that toggled the show tab event
|
373
|
+
* @param {String} tabID The ID of the tab to show
|
374
|
+
* @param {Object} options
|
375
|
+
*/
|
376
|
+
tabby.toggleTab = function (tabID, toggle, options) {
|
377
|
+
|
378
|
+
// Selectors and variables
|
379
|
+
var localSettings = extend(settings || defaults, options || {}); // Merge user options with defaults
|
380
|
+
var tabs = document.querySelectorAll(escapeCharacters(tabID)); // Get tab content
|
381
|
+
|
382
|
+
// Toggle visibility of the toggles and tabs
|
383
|
+
toggleTabs(tabID, localSettings);
|
384
|
+
if (toggle) {
|
385
|
+
toggleToggles(toggle, localSettings);
|
386
|
+
}
|
387
|
+
|
388
|
+
// Run callbacks after toggling tab
|
389
|
+
localSettings.callback(tabs, toggle);
|
390
|
+
|
391
|
+
};
|
392
|
+
|
393
|
+
/**
|
394
|
+
* Handle has change event
|
395
|
+
* @private
|
396
|
+
*/
|
397
|
+
var hashChangeHandler = function (event) {
|
398
|
+
|
399
|
+
// Get hash from URL
|
400
|
+
var hash = root.location.hash;
|
401
|
+
|
402
|
+
// If clicked tab is cached, reset it's ID
|
403
|
+
if (tab) {
|
404
|
+
tab.id = tab.getAttribute('data-tab-id');
|
405
|
+
tab = null;
|
406
|
+
}
|
407
|
+
|
408
|
+
// If there's a URL hash, activate tab with matching ID
|
409
|
+
if (!hash) return;
|
410
|
+
var toggle = document.querySelector(settings.selectorToggle + '[href*="' + hash + '"]');
|
411
|
+
tabby.toggleTab(hash, toggle);
|
412
|
+
|
413
|
+
};
|
414
|
+
|
415
|
+
/**
|
416
|
+
* Handle toggle click events
|
417
|
+
* @private
|
418
|
+
*/
|
419
|
+
var clickHandler = function (event) {
|
420
|
+
|
421
|
+
// Don't run if right-click or command/control + click
|
422
|
+
if (event.button !== 0 || event.metaKey || event.ctrlKey) return;
|
423
|
+
|
424
|
+
// Check if event target is a tab toggle
|
425
|
+
var toggle = getClosest(event.target, settings.selectorToggle);
|
426
|
+
if (!toggle || !toggle.hash) return;
|
427
|
+
|
428
|
+
// Don't run if toggle points to currently open tab
|
429
|
+
if (toggle.hash === root.location.hash) {
|
430
|
+
event.preventDefault();
|
431
|
+
return;
|
432
|
+
}
|
433
|
+
|
434
|
+
// Get the tab content
|
435
|
+
tab = document.querySelector(toggle.hash);
|
436
|
+
|
437
|
+
// If tab content exists, save the ID as a data attribute and remove it (prevents scroll jump)
|
438
|
+
if (!tab) return;
|
439
|
+
tab.setAttribute('data-tab-id', tab.id);
|
440
|
+
tab.id = '';
|
441
|
+
|
442
|
+
};
|
443
|
+
|
444
|
+
/**
|
445
|
+
* Handle content focus events
|
446
|
+
* @private
|
447
|
+
*/
|
448
|
+
var focusHandler = function (event) {
|
449
|
+
|
450
|
+
// Only run if the focused content is in a tab
|
451
|
+
tab = getClosest(event.target, settings.selectorContent);
|
452
|
+
if (!tab) return;
|
453
|
+
|
454
|
+
// Don't run if the content area is already open
|
455
|
+
if (tab.classList.contains(settings.contentActiveClass)) return;
|
456
|
+
|
457
|
+
// Store tab ID to variable and remove it from the tab
|
458
|
+
var hash = tab.id;
|
459
|
+
tab.setAttribute('data-tab-id', hash);
|
460
|
+
tab.setAttribute('data-tab-no-focus', true);
|
461
|
+
tab.id = '';
|
462
|
+
|
463
|
+
// Change the hash
|
464
|
+
location.hash = hash;
|
465
|
+
|
466
|
+
};
|
467
|
+
|
468
|
+
/**
|
469
|
+
* Destroy the current initialization.
|
470
|
+
* @public
|
471
|
+
*/
|
472
|
+
tabby.destroy = function () {
|
473
|
+
if (!settings) return;
|
474
|
+
document.documentElement.classList.remove(settings.initClass);
|
475
|
+
document.removeEventListener('click', clickHandler, false);
|
476
|
+
document.removeEventListener('focus', focusHandler, true);
|
477
|
+
root.removeEventListener('hashchange', hashChangeHandler, false);
|
478
|
+
settings = null;
|
479
|
+
tab = null;
|
480
|
+
};
|
481
|
+
|
482
|
+
/**
|
483
|
+
* Initialize Tabby
|
484
|
+
* @public
|
485
|
+
* @param {Object} options User settings
|
486
|
+
*/
|
487
|
+
tabby.init = function (options) {
|
488
|
+
|
489
|
+
// feature test
|
490
|
+
if (!supports) return;
|
491
|
+
|
492
|
+
// Destroy any existing initializations
|
493
|
+
tabby.destroy();
|
494
|
+
|
495
|
+
// Merge user options with defaults
|
496
|
+
settings = extend(defaults, options || {});
|
497
|
+
|
498
|
+
// Add class to HTML element to activate conditional CSS
|
499
|
+
document.documentElement.classList.add(settings.initClass);
|
500
|
+
|
501
|
+
// Listen for all click events
|
502
|
+
document.addEventListener('click', clickHandler, false);
|
503
|
+
document.addEventListener('focus', focusHandler, true);
|
504
|
+
root.addEventListener('hashchange', hashChangeHandler, false);
|
505
|
+
|
506
|
+
// If URL has a hash, activate hashed tab by default
|
507
|
+
hashChangeHandler();
|
508
|
+
|
509
|
+
};
|
510
|
+
|
511
|
+
|
512
|
+
//
|
513
|
+
// Public APIs
|
514
|
+
//
|
515
|
+
|
516
|
+
return tabby;
|
517
|
+
|
518
|
+
}));
|