keydown 0.5.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.
@@ -0,0 +1,415 @@
1
+ (function() {
2
+ var doc = document;
3
+ var disableBuilds = true;
4
+
5
+ var ctr = 0;
6
+ var spaces = /\s+/, a1 = [''];
7
+
8
+ var toArray = function(list) {
9
+ return Array.prototype.slice.call(list || [], 0);
10
+ };
11
+
12
+ var byId = function(id) {
13
+ if (typeof id == 'string') {
14
+ return doc.getElementById(id);
15
+ }
16
+ return id;
17
+ };
18
+
19
+ var query = function(query, root) {
20
+ if (!query) {
21
+ return [];
22
+ }
23
+ if (typeof query != 'string') {
24
+ return toArray(query);
25
+ }
26
+ if (typeof root == 'string') {
27
+ root = byId(root);
28
+ if (!root) {
29
+ return [];
30
+ }
31
+ }
32
+
33
+ root = root || document;
34
+ var rootIsDoc = (root.nodeType == 9);
35
+ var doc = rootIsDoc ? root : (root.ownerDocument || document);
36
+
37
+ // rewrite the query to be ID rooted
38
+ if (!rootIsDoc || ('>~+'.indexOf(query.charAt(0)) >= 0)) {
39
+ root.id = root.id || ('qUnique' + (ctr++));
40
+ query = '#' + root.id + ' ' + query;
41
+ }
42
+ // don't choke on something like ".yada.yada >"
43
+ if ('>~+'.indexOf(query.slice(-1)) >= 0) {
44
+ query += ' *';
45
+ }
46
+
47
+ return toArray(doc.querySelectorAll(query));
48
+ };
49
+
50
+ var strToArray = function(s) {
51
+ if (typeof s == 'string' || s instanceof String) {
52
+ if (s.indexOf(' ') < 0) {
53
+ a1[0] = s;
54
+ return a1;
55
+ } else {
56
+ return s.split(spaces);
57
+ }
58
+ }
59
+ return s;
60
+ };
61
+
62
+ var addClass = function(node, classStr) {
63
+ classStr = strToArray(classStr);
64
+ var cls = ' ' + node.className + ' ';
65
+ for (var i = 0, len = classStr.length, c; i < len; ++i) {
66
+ c = classStr[i];
67
+ if (c && cls.indexOf(' ' + c + ' ') < 0) {
68
+ cls += c + ' ';
69
+ }
70
+ }
71
+ node.className = cls.trim();
72
+ };
73
+
74
+ var removeClass = function(node, classStr) {
75
+ var cls;
76
+ if (classStr !== undefined) {
77
+ classStr = strToArray(classStr);
78
+ cls = ' ' + node.className + ' ';
79
+ for (var i = 0, len = classStr.length; i < len; ++i) {
80
+ cls = cls.replace(' ' + classStr[i] + ' ', ' ');
81
+ }
82
+ cls = cls.trim();
83
+ } else {
84
+ cls = '';
85
+ }
86
+ if (node.className != cls) {
87
+ node.className = cls;
88
+ }
89
+ };
90
+
91
+ var toggleClass = function(node, classStr) {
92
+ var cls = ' ' + node.className + ' ';
93
+ if (cls.indexOf(' ' + classStr.trim() + ' ') >= 0) {
94
+ removeClass(node, classStr);
95
+ } else {
96
+ addClass(node, classStr);
97
+ }
98
+ };
99
+
100
+ var ua = navigator.userAgent;
101
+ var isFF = parseFloat(ua.split('Firefox/')[1]) || undefined;
102
+ var isWK = parseFloat(ua.split('WebKit/')[1]) || undefined;
103
+ var isOpera = parseFloat(ua.split('Opera/')[1]) || undefined;
104
+
105
+ var canTransition = (function() {
106
+ var ver = parseFloat(ua.split('Version/')[1]) || undefined;
107
+ // test to determine if this browser can handle CSS transitions.
108
+ var cachedCanTransition =
109
+ (isWK || (isFF && isFF > 3.6 ) || (isOpera && ver >= 10.5));
110
+ return function() {
111
+ return cachedCanTransition;
112
+ }
113
+ })();
114
+
115
+ //
116
+ // Slide class
117
+ //
118
+ var Slide = function(node, idx) {
119
+ this._node = node;
120
+ if (idx >= 0) {
121
+ this._count = idx + 1;
122
+ }
123
+ if (this._node) {
124
+ addClass(this._node, 'slide distant-slide');
125
+ }
126
+ this._makeCounter();
127
+ this._makeBuildList();
128
+ };
129
+
130
+ Slide.prototype = {
131
+ _node: null,
132
+ _count: 0,
133
+ _buildList: [],
134
+ _visited: false,
135
+ _currentState: '',
136
+ _states: [ 'distant-slide', 'far-past',
137
+ 'past', 'current', 'future',
138
+ 'far-future', 'distant-slide' ],
139
+ setState: function(state) {
140
+ if (typeof state != 'string') {
141
+ state = this._states[state];
142
+ }
143
+ if (state == 'current' && !this._visited) {
144
+ this._visited = true;
145
+ this._makeBuildList();
146
+ }
147
+ removeClass(this._node, this._states);
148
+ addClass(this._node, state);
149
+ this._currentState = state;
150
+
151
+ // delay first auto run. Really wish this were in CSS.
152
+ /*
153
+ this._runAutos();
154
+ */
155
+ var _t = this;
156
+ setTimeout(function() {
157
+ _t._runAutos();
158
+ }, 400);
159
+ },
160
+ _makeCounter: function() {
161
+ if (!this._count || !this._node) {
162
+ return;
163
+ }
164
+ var c = doc.createElement('span');
165
+ c.innerHTML = this._count;
166
+ c.className = 'counter';
167
+ this._node.appendChild(c);
168
+ },
169
+ _makeBuildList: function() {
170
+ this._buildList = [];
171
+ if (disableBuilds) {
172
+ return;
173
+ }
174
+ if (this._node) {
175
+ this._buildList = query('[data-build] > *', this._node);
176
+ }
177
+ this._buildList.forEach(function(el) {
178
+ addClass(el, 'to-build');
179
+ });
180
+ },
181
+ _runAutos: function() {
182
+ if (this._currentState != 'current') {
183
+ return;
184
+ }
185
+ // find the next auto, slice it out of the list, and run it
186
+ var idx = -1;
187
+ this._buildList.some(function(n, i) {
188
+ if (n.hasAttribute('data-auto')) {
189
+ idx = i;
190
+ return true;
191
+ }
192
+ return false;
193
+ });
194
+ if (idx >= 0) {
195
+ var elem = this._buildList.splice(idx, 1)[0];
196
+ var transitionEnd = isWK ? 'webkitTransitionEnd' : (isFF ? 'mozTransitionEnd' : 'oTransitionEnd');
197
+ var _t = this;
198
+ if (canTransition()) {
199
+ var l = function(evt) {
200
+ elem.parentNode.removeEventListener(transitionEnd, l, false);
201
+ _t._runAutos();
202
+ };
203
+ elem.parentNode.addEventListener(transitionEnd, l, false);
204
+ removeClass(elem, 'to-build');
205
+ } else {
206
+ setTimeout(function() {
207
+ removeClass(elem, 'to-build');
208
+ _t._runAutos();
209
+ }, 400);
210
+ }
211
+ }
212
+ },
213
+ buildNext: function() {
214
+ if (!this._buildList.length) {
215
+ return false;
216
+ }
217
+ removeClass(this._buildList.shift(), 'to-build');
218
+ return true;
219
+ }
220
+ };
221
+
222
+ //
223
+ // SlideShow class
224
+ //
225
+ var SlideShow = function(slides) {
226
+ this._slides = (slides || []).map(function(el, idx) {
227
+ return new Slide(el, idx);
228
+ });
229
+
230
+ this.init();
231
+ var _t = this;
232
+ doc.addEventListener('keydown',
233
+ function(e) {
234
+ _t.handleKeys(e);
235
+ }, false);
236
+ doc.addEventListener('mousewheel',
237
+ function(e) {
238
+ _t.handleWheel(e);
239
+ }, false);
240
+ doc.addEventListener('DOMMouseScroll',
241
+ function(e) {
242
+ _t.handleWheel(e);
243
+ }, false);
244
+ doc.addEventListener('touchstart',
245
+ function(e) {
246
+ _t.handleTouchStart(e);
247
+ }, false);
248
+ doc.addEventListener('touchend',
249
+ function(e) {
250
+ _t.handleTouchEnd(e);
251
+ }, false);
252
+ window.addEventListener('popstate',
253
+ function(e) {
254
+ if (e.state === null) {
255
+ _t.init();
256
+ } else {
257
+ _t.current = e.state;
258
+ }
259
+ _t.go();
260
+ }, false);
261
+ this._update();
262
+ };
263
+
264
+ SlideShow.prototype = {
265
+ _slides: [],
266
+ _update: function(dontPush) {
267
+ document.querySelector('#presentation-counter').innerText = this.current;
268
+ if (history.pushState) {
269
+ if (!dontPush) {
270
+ history.pushState(this.current, 'Slide ' + this.current, '#slide' + this.current);
271
+ }
272
+ } else {
273
+ window.location.hash = 'slide' + this.current;
274
+ }
275
+ for (var x = this.current - 1; x < this.current + 7; x++) {
276
+ if (this._slides[x - 4]) {
277
+ this._slides[x - 4].setState(Math.max(0, x - this.current));
278
+ }
279
+ }
280
+ },
281
+
282
+ current: 0,
283
+ init: function() {
284
+ var h = window.location.hash;
285
+ try {
286
+ this.current = parseInt(h.split('#slide')[1], 10);
287
+ } catch (e) { /* squeltch */
288
+ }
289
+ this.current = current = isNaN(this.current) ? 1 : this.current;
290
+ },
291
+ next: function() {
292
+ if (!this._slides[this.current - 1].buildNext()) {
293
+ this.current = Math.min(this.current + 1, this._slides.length);
294
+ this._update();
295
+ }
296
+ },
297
+ prev: function() {
298
+ this.current = Math.max(this.current - 1, 1);
299
+ this._update();
300
+ },
301
+ go: function() {
302
+ this._update(true);
303
+ },
304
+
305
+ _notesOn: false,
306
+ showNotes: function() {
307
+ var isOn = this._notesOn = !this._notesOn;
308
+ query('.notes').forEach(function(el) {
309
+ el.style.display = (notesOn) ? 'block' : 'none';
310
+ });
311
+ },
312
+ switch3D: function() {
313
+ toggleClass(document.body, 'three-d');
314
+ },
315
+ handleWheel: function(e) {
316
+ var delta = 0;
317
+ if (e.wheelDelta) {
318
+ delta = e.wheelDelta / 120;
319
+ if (isOpera) {
320
+ delta = -delta;
321
+ }
322
+ } else if (e.detail) {
323
+ delta = -e.detail / 3;
324
+ }
325
+
326
+ if (delta > 0) {
327
+ this.prev();
328
+ return;
329
+ }
330
+ if (delta < 0) {
331
+ this.next();
332
+ return;
333
+ }
334
+ },
335
+ handleKeys: function(e) {
336
+
337
+ if (/^(input|textarea)$/i.test(e.target.nodeName)) return;
338
+
339
+ switch (e.keyCode) {
340
+ case 37: // left arrow
341
+ this.prev(); break;
342
+ case 39: // right arrow
343
+ case 32: // space
344
+ this.next(); break;
345
+ case 50: // 2
346
+ this.showNotes(); break;
347
+ case 51: // 3
348
+ this.switch3D(); break;
349
+ }
350
+ },
351
+ _touchStartX: 0,
352
+ handleTouchStart: function(e) {
353
+ this._touchStartX = e.touches[0].pageX;
354
+ },
355
+ handleTouchEnd: function(e) {
356
+ var delta = this._touchStartX - e.changedTouches[0].pageX;
357
+ var SWIPE_SIZE = 150;
358
+ if (delta > SWIPE_SIZE) {
359
+ this.next();
360
+ } else if (delta < -SWIPE_SIZE) {
361
+ this.prev();
362
+ }
363
+ }
364
+ };
365
+
366
+ // Initialize
367
+ var slideshow = new SlideShow(query('.slide'));
368
+
369
+ document.querySelector('#toggle-counter').addEventListener('click', toggleCounter, false);
370
+ document.querySelector('#toggle-size').addEventListener('click', toggleSize, false);
371
+ document.querySelector('#toggle-transitions').addEventListener('click', toggleTransitions, false);
372
+ document.querySelector('#toggle-gradients').addEventListener('click', toggleGradients, false);
373
+
374
+ var counters = document.querySelectorAll('.counter');
375
+ var slides = document.querySelectorAll('.slide');
376
+
377
+ function toggleCounter() {
378
+ toArray(counters).forEach(function(el) {
379
+ el.style.display = (el.offsetHeight) ? 'none' : 'block';
380
+ });
381
+ }
382
+
383
+ function toggleSize() {
384
+ toArray(slides).forEach(function(el) {
385
+ if (!/reduced/.test(el.className)) {
386
+ addClass(el, 'reduced');
387
+ }
388
+ else {
389
+ removeClass(el, 'reduced');
390
+ }
391
+ });
392
+ }
393
+
394
+ function toggleTransitions() {
395
+ toArray(slides).forEach(function(el) {
396
+ if (!/no-transitions/.test(el.className)) {
397
+ addClass(el, 'no-transitions');
398
+ }
399
+ else {
400
+ removeClass(el, 'no-transitions');
401
+ }
402
+ });
403
+ }
404
+
405
+ function toggleGradients() {
406
+ toArray(slides).forEach(function(el) {
407
+ if (!/no-gradients/.test(el.className)) {
408
+ addClass(el, 'no-gradients');
409
+ }
410
+ else {
411
+ removeClass(el, 'no-gradients');
412
+ }
413
+ });
414
+ }
415
+ })();
@@ -0,0 +1,104 @@
1
+ /* To show bullests in unordered lists */
2
+ section.bulleted ul {
3
+ padding-left: 30px;
4
+ }
5
+
6
+ /* Full slide backgrounds */
7
+ .slide.full-background {
8
+ -webkit-background-size: cover;
9
+ -moz-background-size: cover;
10
+ background-size: cover;
11
+ background-position: center;
12
+ }
13
+ <% backgrounds.each do |background| %>
14
+ .<%= background[:classname] %> {
15
+ background-image: url(../<%= background[:path] %>);
16
+ }
17
+ <% end %>
18
+
19
+ .attribution {
20
+ font-size: 24px;
21
+ position: fixed;
22
+ bottom: 8px;
23
+ left: 40px;
24
+ -webkit-background-size: contain;
25
+ -moz-background-size: contain;
26
+ background-size: contain;
27
+ }
28
+
29
+ .attribution.flickr {
30
+ background: url(../images/flickr.png) left top no-repeat;
31
+ padding-left: 60px;
32
+ }
33
+
34
+ .attribution.cc {
35
+ background: url(../images/cc.large.png) left top no-repeat;
36
+ padding-left: 36px;
37
+ }
38
+
39
+ /* Happy generic hiding class */
40
+ .hidden {
41
+ display: none;
42
+ }
43
+
44
+ /* - Pygments sytles for code fragments - */
45
+ pre { background: none; }
46
+ pre .c { color: #999988; font-style: italic } /* Comment */
47
+ pre .err { color: #a61717; background-color: #e3d2d2 } /* Error */
48
+ pre .k { font-weight: bold } /* Keyword */
49
+ pre .o { font-weight: bold } /* Operator */
50
+ pre .cm { color: #999988; font-style: italic } /* Comment.Multiline */
51
+ pre .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
52
+ pre .c1 { color: #999988; font-style: italic } /* Comment.Single */
53
+ pre .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
54
+ pre .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
55
+ pre .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */
56
+ pre .ge { font-style: italic } /* Generic.Emph */
57
+ pre .gr { color: #aa0000 } /* Generic.Error */
58
+ pre .gh { color: #999999 } /* Generic.Heading */
59
+ pre .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
60
+ pre .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */
61
+ pre .go { color: #888888 } /* Generic.Output */
62
+ pre .gp { color: #555555 } /* Generic.Prompt */
63
+ pre .gs { font-weight: bold } /* Generic.Strong */
64
+ pre .gu { color: #aaaaaa } /* Generic.Subheading */
65
+ pre .gt { color: #aa0000 } /* Generic.Traceback */
66
+ pre .kc { font-weight: bold } /* Keyword.Constant */
67
+ pre .kd { font-weight: bold } /* Keyword.Declaration */
68
+ pre .kp { font-weight: bold } /* Keyword.Pseudo */
69
+ pre .kr { font-weight: bold } /* Keyword.Reserved */
70
+ pre .kt { color: #445588; font-weight: bold } /* Keyword.Type */
71
+ pre .m { color: #009999 } /* Literal.Number */
72
+ pre .s { color: #d14 } /* Literal.String */
73
+ pre .na { color: #008080 } /* Name.Attribute */
74
+ pre .nb { color: #0086B3 } /* Name.Builtin */
75
+ pre .nc { color: #445588; font-weight: bold } /* Name.Class */
76
+ pre .no { color: #008080 } /* Name.Constant */
77
+ pre .ni { color: #800080 } /* Name.Entity */
78
+ pre .ne { color: #990000; font-weight: bold } /* Name.Exception */
79
+ pre .nf { color: #990000; font-weight: bold } /* Name.Function */
80
+ pre .nn { color: #555555 } /* Name.Namespace */
81
+ pre .nt { color: #000080 } /* Name.Tag */
82
+ pre .nv { color: #008080 } /* Name.Variable */
83
+ pre .ow { font-weight: bold } /* Operator.Word */
84
+ pre .w { color: #bbbbbb } /* Text.Whitespace */
85
+ pre .mf { color: #009999 } /* Literal.Number.Float */
86
+ pre .mh { color: #009999 } /* Literal.Number.Hex */
87
+ pre .mi { color: #009999 } /* Literal.Number.Integer */
88
+ pre .mo { color: #009999 } /* Literal.Number.Oct */
89
+ pre .sb { color: #d14 } /* Literal.String.Backtick */
90
+ pre .sc { color: #d14 } /* Literal.String.Char */
91
+ pre .sd { color: #d14 } /* Literal.String.Doc */
92
+ pre .s2 { color: #d14 } /* Literal.String.Double */
93
+ pre .se { color: #d14 } /* Literal.String.Escape */
94
+ pre .sh { color: #d14 } /* Literal.String.Heredoc */
95
+ pre .si { color: #d14 } /* Literal.String.Interpol */
96
+ pre .sx { color: #d14 } /* Literal.String.Other */
97
+ pre .sr { color: #009926 } /* Literal.String.Regex */
98
+ pre .s1 { color: #d14 } /* Literal.String.Single */
99
+ pre .ss { color: #990073 } /* Literal.String.Symbol */
100
+ pre .bp { color: #999999 } /* Name.Builtin.Pseudo */
101
+ pre .vc { color: #008080 } /* Name.Variable.Class */
102
+ pre .vg { color: #008080 } /* Name.Variable.Global */
103
+ pre .vi { color: #008080 } /* Name.Variable.Instance */
104
+ pre .il { color: #009999 } /* Literal.Number.Integer.Long */
@@ -0,0 +1,125 @@
1
+ <!DOCTYPE html>
2
+ <!--
3
+ Original Project, HTML5 Rocks 'Slides Template' Copyright 2010 Google Inc.
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+
17
+ Original slides: Marcin Wichary (mwichary@google.com)
18
+ Modifications: Ernest Delgado (ernestd@google.com)
19
+ Alex Russell (slightlyoff@chromium.org)
20
+ Brad Neuberg
21
+
22
+ Keydown generates an HTML5 Rocks-style presentation from a Markdown file, adding
23
+ the ability to full screen backgrounds, CSS overrides, and additional JavaScript.
24
+
25
+ Keydown (http://infews.github.com/keydown), Copyright 2010 Infews LLC
26
+ -->
27
+ <html manifest="cache.manifest">
28
+ <head>
29
+ <!--[if gte IE 9]>
30
+ <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
31
+ <![endif]-->
32
+
33
+ <!--[if lt IE 9]>
34
+ <meta http-equiv="X-UA-Compatible" content="IE=edge;chrome=1"/>
35
+ <![endif]-->
36
+
37
+ <meta charset="utf-8"/>
38
+ <title><%= title %></title>
39
+ <link href="http://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans+Mono" rel="stylesheet" type="text/css"/>
40
+
41
+ <!--
42
+ Original HTML5 Rocks CSS extracted for readability
43
+ -->
44
+ <link href="css/rocks.css" rel="stylesheet" type="text/css"/>
45
+
46
+ <!--
47
+ Keydown provided CSS & your custom CSS
48
+ -->
49
+ <% css_files.each do |css_file| %>
50
+ <link href="<%= css_file %>" rel="stylesheet" type="text/css"/>
51
+ <% end %>
52
+
53
+ </head>
54
+ <body>
55
+ <div class="presentation">
56
+ <div id="presentation-counter"></div>
57
+ <div class="slides">
58
+ <!--
59
+ First slide has Title, Instructions & options. Remove (or display:none) this slide if you like
60
+ -->
61
+ <div class="slide">
62
+ <section class="middle">
63
+ <h1><%= title %></h1>
64
+ <p>
65
+ Press <span class="key"><b>&rarr;</b></span>, scroll, or swipe to advance
66
+ </p>
67
+ <h3>
68
+ Options
69
+ </h3>
70
+ <ul>
71
+ <li>
72
+ <input type="checkbox" id="toggle-size" />
73
+ <label for="toggle-size">
74
+ <span>Grow</span>
75
+ </label>
76
+ </li>
77
+ <li>
78
+ <input type="checkbox" id="toggle-transitions" checked/>
79
+ <label for="toggle-transitions">
80
+ <span>Transitions</span>
81
+ </label>
82
+ </li>
83
+ <li>
84
+ <input type="checkbox" id="toggle-gradients" checked/>
85
+ <label for="toggle-gradients">
86
+ <span>Gradients</span>
87
+ </label>
88
+ </li>
89
+ <li>
90
+ <input type="checkbox" id="toggle-counter" checked/>
91
+ <label for="toggle-counter">
92
+ <span>Slide numbers</span>
93
+ </label>
94
+ </li>
95
+ </ul>
96
+ <p>
97
+ Made with <a href="http://infews.github.com/keydown"><b>Keydown</b></a>
98
+ </p>
99
+ </section>
100
+ </div>
101
+ <% slides.each do |slide| %>
102
+ <%= slide.to_html %>
103
+ <% end %>
104
+ </div>
105
+ </div>
106
+
107
+ <!--
108
+ Original HTML5 Rocks JavaScript extracted for readability
109
+ -->
110
+ <script src="js/rocks.js" type="text/javascript"></script>
111
+
112
+ <!--[if lt IE 9]>
113
+ <script src="http://ajax.googleapis.com/ajax/libs/chrome-frame/1/CFInstall.min.js"></script>
114
+ <script>CFInstall.check({ mode: "overlay" });</script>
115
+ <![endif]-->
116
+
117
+ <!--
118
+ Keydown puts your custom JS here
119
+ -->
120
+ <% js_files.each do |js_file| %>
121
+ <script src="<%= js_file %>" type="text/javascript"></script>
122
+ <% end %>
123
+
124
+ </body>
125
+ </html>
@@ -0,0 +1,10 @@
1
+ <div class="<%= container_classnames %>">
2
+ <section<%= " class=\"#{classnames}\"" unless classnames.empty? %>>
3
+ <%= html_content %>
4
+ </section>
5
+ <div class="<%= background_attribution_classnames %>">
6
+ <a href="<%= background_image[:attribution_link] %>">
7
+ <%= background_image[:attribution_text] %>
8
+ </a>
9
+ </div>
10
+ </div>