|
137 | 137 |
|
138 | 138 | }()); |
139 | 139 |
|
| 140 | +!(function () { |
| 141 | + 'use strict'; |
| 142 | + |
| 143 | + // Ratchet's layout includes fixed position headers & footers that should always |
| 144 | + // appear before the main .content div within <body> |
| 145 | + // |
| 146 | + // These fixed bars will have new content swapped in, ignoring any |
| 147 | + // transitions (slide-in, slide-out & fade). |
| 148 | + // |
| 149 | + // These following selectors define which elements are transitioned with |
| 150 | + // simple DOM replacement and are always immediate children of <body> |
| 151 | + var barSelectors = [ |
| 152 | + '.bar-tab', |
| 153 | + '.bar-nav', |
| 154 | + '.bar-footer', |
| 155 | + '.bar-header-secondary' |
| 156 | + ]; |
| 157 | + |
| 158 | + // Other than any fixed bars, '.content' should be the only other child of body |
| 159 | + var contentSelector = '.content'; |
| 160 | + |
| 161 | + // For any bar elements in `newMarkup`, either: |
| 162 | + // * replace an existing bar elements with new content |
| 163 | + // * add new bar elements when an existing one isn't present |
| 164 | + // * remove any bar elements not found in `newMarkup` |
| 165 | + var updateBars = function (newMarkup) { |
| 166 | + for (var i = 0; i < barSelectors.length; i++) { |
| 167 | + var selector = barSelectors[i]; |
| 168 | + var newBar = newMarkup.querySelector(selector); |
| 169 | + var existingBar = document.querySelector(selector); |
| 170 | + |
| 171 | + if (newBar) { |
| 172 | + displayBar(newBar, existingBar); |
| 173 | + } else if (existingBar) { |
| 174 | + existingBar.parentNode.removeChild(existingBar); |
| 175 | + } |
| 176 | + } |
| 177 | + }; |
| 178 | + |
| 179 | + var displayBar = function (bar, container) { |
| 180 | + if (container) { |
| 181 | + container.innerHTML = ''; |
| 182 | + container.appendChild(bar); |
| 183 | + } else { |
| 184 | + // per Ratchet's CSS, bar elements must be the first thing in <body> |
| 185 | + // here we assume `.content` is an immediate child of <body> |
| 186 | + document.body.insertBefore(bar, document.querySelector(contentSelector)); |
| 187 | + } |
| 188 | + }; |
| 189 | + |
| 190 | + var transitionContent = function (swap, container, transition, complete) { |
| 191 | + var enter; |
| 192 | + var containerDirection; |
| 193 | + var swapDirection; |
| 194 | + |
| 195 | + enter = /in$/.test(transition); |
| 196 | + |
| 197 | + if (transition === 'fade') { |
| 198 | + container.classList.add('in'); |
| 199 | + container.classList.add('fade'); |
| 200 | + swap.classList.add('fade'); |
| 201 | + } |
| 202 | + |
| 203 | + if (/slide/.test(transition)) { |
| 204 | + swap.classList.add('sliding-in', enter ? 'right' : 'left'); |
| 205 | + swap.classList.add('sliding'); |
| 206 | + container.classList.add('sliding'); |
| 207 | + } |
| 208 | + |
| 209 | + container.parentNode.insertBefore(swap, container); |
| 210 | + |
| 211 | + if (transition === 'fade') { |
| 212 | + container.offsetWidth; // force reflow |
| 213 | + container.classList.remove('in'); |
| 214 | + var fadeContainerEnd = function () { |
| 215 | + container.removeEventListener('webkitTransitionEnd', fadeContainerEnd); |
| 216 | + swap.classList.add('in'); |
| 217 | + swap.addEventListener('webkitTransitionEnd', fadeSwapEnd); |
| 218 | + }; |
| 219 | + var fadeSwapEnd = function () { |
| 220 | + swap.removeEventListener('webkitTransitionEnd', fadeSwapEnd); |
| 221 | + container.parentNode.removeChild(container); |
| 222 | + swap.classList.remove('fade'); |
| 223 | + swap.classList.remove('in'); |
| 224 | + complete && complete(); |
| 225 | + }; |
| 226 | + container.addEventListener('webkitTransitionEnd', fadeContainerEnd); |
| 227 | + } |
| 228 | + |
| 229 | + if (/slide/.test(transition)) { |
| 230 | + var slideEnd = function () { |
| 231 | + swap.removeEventListener('webkitTransitionEnd', slideEnd); |
| 232 | + swap.classList.remove('sliding', 'sliding-in'); |
| 233 | + swap.classList.remove(swapDirection); |
| 234 | + container.parentNode.removeChild(container); |
| 235 | + complete && complete(); |
| 236 | + }; |
| 237 | + |
| 238 | + container.offsetWidth; // force reflow |
| 239 | + swapDirection = enter ? 'right' : 'left'; |
| 240 | + containerDirection = enter ? 'left' : 'right'; |
| 241 | + container.classList.add(containerDirection); |
| 242 | + swap.classList.remove(swapDirection); |
| 243 | + swap.addEventListener('webkitTransitionEnd', slideEnd); |
| 244 | + } |
| 245 | + }; |
| 246 | + |
| 247 | + // `contents` can either be a string of HTML or a DOM object. |
| 248 | + // Either way, `contents` must include: |
| 249 | + // * bar elements (optional -- see `barSelectors`) |
| 250 | + // * a single content element |
| 251 | + // All as children of a single parent. |
| 252 | + // |
| 253 | + // For example: |
| 254 | + // <div> |
| 255 | + // <div class="bar-tab"></div> |
| 256 | + // <div class="bar-nav"></div> |
| 257 | + // <div class="contents"></div> |
| 258 | + // </div> |
| 259 | + var TRANSITION = function (contents, transition, complete) { |
| 260 | + |
| 261 | + if(typeof(contents) === 'string' || contents instanceof String) { |
| 262 | + var div = document.createElement('div'); |
| 263 | + div.innerHTML = contents; |
| 264 | + contents = div.childNodes[0]; |
| 265 | + } |
| 266 | + |
| 267 | + if (transition) { |
| 268 | + updateBars(contents); |
| 269 | + |
| 270 | + var existingContentDiv = document.querySelector(contentSelector); |
| 271 | + var newContentDiv = contents.querySelector(contentSelector); |
| 272 | + transitionContent(newContentDiv, existingContentDiv, |
| 273 | + transition, complete); |
| 274 | + } else { |
| 275 | + document.body.innerHTML = ''; |
| 276 | + document.body.appendChild(contents); |
| 277 | + complete && complete(); |
| 278 | + } |
| 279 | + }; |
| 280 | + |
| 281 | + window.TRANSITION = TRANSITION; |
| 282 | +}()); |
| 283 | + |
140 | 284 | /* ======================================================================== |
141 | 285 | * Ratchet: push.js v2.0.2 |
142 | 286 | * http://goratchet.com/components#push |
|
146 | 290 | * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE) |
147 | 291 | * ======================================================================== */ |
148 | 292 |
|
149 | | -/* global _gaq: true */ |
| 293 | +/* global _gaq, TRANSITION */ |
150 | 294 |
|
151 | 295 | !(function () { |
152 | 296 | 'use strict'; |
|
168 | 312 | fade : 'fade' |
169 | 313 | }; |
170 | 314 |
|
171 | | - var bars = { |
172 | | - bartab : '.bar-tab', |
173 | | - barnav : '.bar-nav', |
174 | | - barfooter : '.bar-footer', |
175 | | - barheadersecondary : '.bar-header-secondary' |
176 | | - }; |
177 | | - |
178 | 315 | var cacheReplace = function (data, updates) { |
179 | 316 | PUSH.id = data.id; |
180 | 317 | if (updates) { |
|
264 | 401 | }; |
265 | 402 |
|
266 | 403 | var popstate = function (e) { |
267 | | - var key; |
268 | | - var barElement; |
269 | 404 | var activeObj; |
270 | 405 | var activeDom; |
271 | 406 | var direction; |
|
313 | 448 | }); |
314 | 449 | } |
315 | 450 |
|
316 | | - if (transitionFromObj.transition) { |
317 | | - activeObj = extendWithDom(activeObj, '.content', activeDom.cloneNode(true)); |
318 | | - for (key in bars) { |
319 | | - if (bars.hasOwnProperty(key)) { |
320 | | - barElement = document.querySelector(bars[key]); |
321 | | - if (activeObj[key]) { |
322 | | - swapContent(activeObj[key], barElement); |
323 | | - } else if (barElement) { |
324 | | - barElement.parentNode.removeChild(barElement); |
325 | | - } |
326 | | - } |
327 | | - } |
328 | | - } |
329 | | - |
330 | | - swapContent( |
331 | | - (activeObj.contents || activeDom).cloneNode(true), |
332 | | - document.querySelector('.content'), |
333 | | - transition, function() { |
334 | | - triggerStateChange(); |
335 | | - } |
336 | | - ); |
| 451 | + TRANSITION(activeDom.cloneNode(true), |
| 452 | + transitionFromObj.transition, |
| 453 | + function() { |
| 454 | + triggerStateChange(); |
| 455 | + }); |
337 | 456 |
|
338 | 457 | PUSH.id = id; |
339 | 458 |
|
|
345 | 464 | // ======================= |
346 | 465 |
|
347 | 466 | var PUSH = function (options) { |
348 | | - var key; |
349 | 467 | var xhr = PUSH.xhr; |
350 | 468 |
|
351 | | - options.container = options.container || options.transition ? document.querySelector('.content') : document.body; |
352 | | - |
353 | | - for (key in bars) { |
354 | | - if (bars.hasOwnProperty(key)) { |
355 | | - options[key] = options[key] || document.querySelector(bars[key]); |
356 | | - } |
357 | | - } |
358 | | - |
359 | 469 | if (xhr && xhr.readyState < 4) { |
360 | 470 | xhr.onreadystatechange = noop; |
361 | 471 | xhr.abort(); |
|
406 | 516 | // ================= |
407 | 517 |
|
408 | 518 | var success = function (xhr, options) { |
409 | | - var key; |
410 | | - var barElement; |
411 | 519 | var data = parseXHR(xhr, options); |
412 | 520 |
|
413 | 521 | if (!data.contents) { |
|
418 | 526 | document.title = data.title; |
419 | 527 | } |
420 | 528 |
|
421 | | - if (options.transition) { |
422 | | - for (key in bars) { |
423 | | - if (bars.hasOwnProperty(key)) { |
424 | | - barElement = document.querySelector(bars[key]); |
425 | | - if (data[key]) { |
426 | | - swapContent(data[key], barElement); |
427 | | - } else if (barElement) { |
428 | | - barElement.parentNode.removeChild(barElement); |
429 | | - } |
430 | | - } |
431 | | - } |
432 | | - } |
433 | | - |
434 | | - swapContent(data.contents, options.container, options.transition, function () { |
| 529 | + TRANSITION(data.contents, options.transition, function () { |
435 | 530 | cacheReplace({ |
436 | 531 | id : options.id || +new Date(), |
437 | 532 | url : data.url, |
|
442 | 537 | triggerStateChange(); |
443 | 538 | }); |
444 | 539 |
|
| 540 | + |
445 | 541 | if (!options.ignorePush && window._gaq) { |
446 | 542 | _gaq.push(['_trackPageview']); // google analytics |
447 | 543 | } |
|
458 | 554 | // PUSH helpers |
459 | 555 | // ============ |
460 | 556 |
|
461 | | - var swapContent = function (swap, container, transition, complete) { |
462 | | - var enter; |
463 | | - var containerDirection; |
464 | | - var swapDirection; |
465 | | - |
466 | | - if (!transition) { |
467 | | - if (container) { |
468 | | - container.innerHTML = swap.innerHTML; |
469 | | - } else if (swap.classList.contains('content')) { |
470 | | - document.body.appendChild(swap); |
471 | | - } else { |
472 | | - document.body.insertBefore(swap, document.querySelector('.content')); |
473 | | - } |
474 | | - } else { |
475 | | - enter = /in$/.test(transition); |
476 | | - |
477 | | - if (transition === 'fade') { |
478 | | - container.classList.add('in'); |
479 | | - container.classList.add('fade'); |
480 | | - swap.classList.add('fade'); |
481 | | - } |
482 | | - |
483 | | - if (/slide/.test(transition)) { |
484 | | - swap.classList.add('sliding-in', enter ? 'right' : 'left'); |
485 | | - swap.classList.add('sliding'); |
486 | | - container.classList.add('sliding'); |
487 | | - } |
488 | | - |
489 | | - container.parentNode.insertBefore(swap, container); |
490 | | - } |
491 | | - |
492 | | - if (!transition) { |
493 | | - complete && complete(); |
494 | | - } |
495 | | - |
496 | | - if (transition === 'fade') { |
497 | | - container.offsetWidth; // force reflow |
498 | | - container.classList.remove('in'); |
499 | | - var fadeContainerEnd = function () { |
500 | | - container.removeEventListener('webkitTransitionEnd', fadeContainerEnd); |
501 | | - swap.classList.add('in'); |
502 | | - swap.addEventListener('webkitTransitionEnd', fadeSwapEnd); |
503 | | - }; |
504 | | - var fadeSwapEnd = function () { |
505 | | - swap.removeEventListener('webkitTransitionEnd', fadeSwapEnd); |
506 | | - container.parentNode.removeChild(container); |
507 | | - swap.classList.remove('fade'); |
508 | | - swap.classList.remove('in'); |
509 | | - complete && complete(); |
510 | | - }; |
511 | | - container.addEventListener('webkitTransitionEnd', fadeContainerEnd); |
512 | | - |
513 | | - } |
514 | | - |
515 | | - if (/slide/.test(transition)) { |
516 | | - var slideEnd = function () { |
517 | | - swap.removeEventListener('webkitTransitionEnd', slideEnd); |
518 | | - swap.classList.remove('sliding', 'sliding-in'); |
519 | | - swap.classList.remove(swapDirection); |
520 | | - container.parentNode.removeChild(container); |
521 | | - complete && complete(); |
522 | | - }; |
523 | | - |
524 | | - container.offsetWidth; // force reflow |
525 | | - swapDirection = enter ? 'right' : 'left'; |
526 | | - containerDirection = enter ? 'left' : 'right'; |
527 | | - container.classList.add(containerDirection); |
528 | | - swap.classList.remove(swapDirection); |
529 | | - swap.addEventListener('webkitTransitionEnd', slideEnd); |
530 | | - } |
531 | | - }; |
532 | | - |
533 | 557 | var triggerStateChange = function () { |
534 | 558 | var e = new CustomEvent('push', { |
535 | 559 | detail: { state: getCached(PUSH.id) }, |
|
558 | 582 | window.location.replace(url); |
559 | 583 | }; |
560 | 584 |
|
561 | | - var extendWithDom = function (obj, fragment, dom) { |
562 | | - var i; |
563 | | - var result = {}; |
564 | | - |
565 | | - for (i in obj) { |
566 | | - if (obj.hasOwnProperty(i)) { |
567 | | - result[i] = obj[i]; |
568 | | - } |
569 | | - } |
570 | | - |
571 | | - Object.keys(bars).forEach(function (key) { |
572 | | - var el = dom.querySelector(bars[key]); |
573 | | - if (el) { |
574 | | - el.parentNode.removeChild(el); |
575 | | - } |
576 | | - result[key] = el; |
577 | | - }); |
578 | | - |
579 | | - result.contents = dom.querySelector(fragment); |
580 | | - |
581 | | - return result; |
582 | | - }; |
583 | | - |
584 | 585 | var parseXHR = function (xhr, options) { |
585 | 586 | var head; |
586 | 587 | var body; |
|
607 | 608 | var text = 'innerText' in data.title ? 'innerText' : 'textContent'; |
608 | 609 | data.title = data.title && data.title[text].trim(); |
609 | 610 |
|
610 | | - if (options.transition) { |
611 | | - data = extendWithDom(data, '.content', body); |
612 | | - } else { |
613 | | - data.contents = body; |
614 | | - } |
| 611 | + data.contents = body; |
615 | 612 |
|
616 | 613 | return data; |
617 | 614 | }; |
|
0 commit comments