white-rabbit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
}));
|