github.com/jgarto/itcv@v0.0.0-20180826224514-4eea09c1aa0d/examples/sites/present/templates/slides.tmpl (about)

     1  {/* This is the slide template. It defines how presentations are formatted. */}
     2  
     3  {{define "root"}}
     4  <!DOCTYPE html>
     5  <html>
     6    <head>
     7      <title>{{.Title}}</title>
     8      <meta charset='utf-8'>
     9      <script>
    10        var notesEnabled = {{.NotesEnabled}};
    11      </script>
    12      <!-- This is a test -->
    13        <style>
    14  @media screen {
    15    /* Framework */
    16    html {
    17      height: 100%;
    18    }
    19  
    20    body {
    21      margin: 0;
    22      padding: 0;
    23  
    24      display: block !important;
    25  
    26      height: 100%;
    27      min-height: 740px;
    28  
    29      overflow-x: hidden;
    30      overflow-y: auto;
    31  
    32      background: rgb(215, 215, 215);
    33      background: -o-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190));
    34      background: -moz-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190));
    35      background: -webkit-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190));
    36      background: -webkit-gradient(radial, 50% 50%, 0, 50% 50%, 500, from(rgb(240, 240, 240)), to(rgb(190, 190, 190)));
    37  
    38      -webkit-font-smoothing: antialiased;
    39    }
    40  
    41    .slides {
    42      width: 100%;
    43      height: 100%;
    44      left: 0;
    45      top: 0;
    46  
    47      position: absolute;
    48  
    49      -webkit-transform: translate3d(0, 0, 0);
    50    }
    51  
    52    .slides > article {
    53      display: block;
    54  
    55      position: absolute;
    56      overflow: hidden;
    57  
    58      width: 900px;
    59      height: 700px;
    60  
    61      left: 50%;
    62      top: 50%;
    63  
    64      margin-left: -450px;
    65      margin-top: -350px;
    66  
    67      padding: 40px 60px;
    68  
    69      box-sizing: border-box;
    70      -o-box-sizing: border-box;
    71      -moz-box-sizing: border-box;
    72      -webkit-box-sizing: border-box;
    73  
    74      border-radius: 10px;
    75      -o-border-radius: 10px;
    76      -moz-border-radius: 10px;
    77      -webkit-border-radius: 10px;
    78  
    79      background-color: white;
    80  
    81      border: 1px solid rgba(0, 0, 0, .3);
    82  
    83      transition: transform .3s ease-out;
    84      -o-transition: -o-transform .3s ease-out;
    85      -moz-transition: -moz-transform .3s ease-out;
    86      -webkit-transition: -webkit-transform .3s ease-out;
    87    }
    88    .slides.layout-widescreen > article {
    89      margin-left: -550px;
    90      width: 1100px;
    91    }
    92    .slides.layout-faux-widescreen > article {
    93      margin-left: -550px;
    94      width: 1100px;
    95  
    96      padding: 40px 160px;
    97    }
    98  
    99    .slides.layout-widescreen > article:not(.nobackground):not(.biglogo),
   100    .slides.layout-faux-widescreen > article:not(.nobackground):not(.biglogo) {
   101      background-position-x: 0, 840px;
   102    }
   103  
   104    /* Clickable/tappable areas */
   105  
   106    .slide-area {
   107      z-index: 1000;
   108  
   109      position: absolute;
   110      left: 0;
   111      top: 0;
   112      width: 150px;
   113      height: 700px;
   114  
   115      left: 50%;
   116      top: 50%;
   117  
   118      cursor: pointer;
   119      margin-top: -350px;
   120  
   121      tap-highlight-color: transparent;
   122      -o-tap-highlight-color: transparent;
   123      -moz-tap-highlight-color: transparent;
   124      -webkit-tap-highlight-color: transparent;
   125    }
   126    #prev-slide-area {
   127      margin-left: -550px;
   128    }
   129    #next-slide-area {
   130      margin-left: 400px;
   131    }
   132    .slides.layout-widescreen #prev-slide-area,
   133    .slides.layout-faux-widescreen #prev-slide-area {
   134      margin-left: -650px;
   135    }
   136    .slides.layout-widescreen #next-slide-area,
   137    .slides.layout-faux-widescreen #next-slide-area {
   138      margin-left: 500px;
   139    }
   140  
   141    /* Slides */
   142  
   143    .slides > article {
   144      display: none;
   145    }
   146    .slides > article.far-past {
   147      display: block;
   148      transform: translate(-2040px);
   149      -o-transform: translate(-2040px);
   150      -moz-transform: translate(-2040px);
   151      -webkit-transform: translate3d(-2040px, 0, 0);
   152    }
   153    .slides > article.past {
   154      display: block;
   155      transform: translate(-1020px);
   156      -o-transform: translate(-1020px);
   157      -moz-transform: translate(-1020px);
   158      -webkit-transform: translate3d(-1020px, 0, 0);
   159    }
   160    .slides > article.current {
   161      display: block;
   162      transform: translate(0);
   163      -o-transform: translate(0);
   164      -moz-transform: translate(0);
   165      -webkit-transform: translate3d(0, 0, 0);
   166    }
   167    .slides > article.next {
   168      display: block;
   169      transform: translate(1020px);
   170      -o-transform: translate(1020px);
   171      -moz-transform: translate(1020px);
   172      -webkit-transform: translate3d(1020px, 0, 0);
   173    }
   174    .slides > article.far-next {
   175      display: block;
   176      transform: translate(2040px);
   177      -o-transform: translate(2040px);
   178      -moz-transform: translate(2040px);
   179      -webkit-transform: translate3d(2040px, 0, 0);
   180    }
   181  
   182    .slides.layout-widescreen > article.far-past,
   183    .slides.layout-faux-widescreen > article.far-past {
   184      display: block;
   185      transform: translate(-2260px);
   186      -o-transform: translate(-2260px);
   187      -moz-transform: translate(-2260px);
   188      -webkit-transform: translate3d(-2260px, 0, 0);
   189    }
   190    .slides.layout-widescreen > article.past,
   191    .slides.layout-faux-widescreen > article.past {
   192      display: block;
   193      transform: translate(-1130px);
   194      -o-transform: translate(-1130px);
   195      -moz-transform: translate(-1130px);
   196      -webkit-transform: translate3d(-1130px, 0, 0);
   197    }
   198    .slides.layout-widescreen > article.current,
   199    .slides.layout-faux-widescreen > article.current {
   200      display: block;
   201      transform: translate(0);
   202      -o-transform: translate(0);
   203      -moz-transform: translate(0);
   204      -webkit-transform: translate3d(0, 0, 0);
   205    }
   206    .slides.layout-widescreen > article.next,
   207    .slides.layout-faux-widescreen > article.next {
   208      display: block;
   209      transform: translate(1130px);
   210      -o-transform: translate(1130px);
   211      -moz-transform: translate(1130px);
   212      -webkit-transform: translate3d(1130px, 0, 0);
   213    }
   214    .slides.layout-widescreen > article.far-next,
   215    .slides.layout-faux-widescreen > article.far-next {
   216      display: block;
   217      transform: translate(2260px);
   218      -o-transform: translate(2260px);
   219      -moz-transform: translate(2260px);
   220      -webkit-transform: translate3d(2260px, 0, 0);
   221    }
   222  }
   223  
   224  @media print {
   225    /* Set page layout */
   226    @page {
   227      size: A4 landscape;
   228    }
   229  
   230    body {
   231      display: block !important;
   232    }
   233  
   234    .slides > article {
   235      display: block;
   236  
   237      position: relative;
   238  
   239      page-break-inside: never;
   240      page-break-after: always;
   241  
   242      overflow: hidden;
   243    }
   244  
   245    h2 {
   246      position: static !important;
   247      margin-top: 400px !important;
   248      margin-bottom: 100px !important;
   249    }
   250  
   251    div.code {
   252      background: rgb(240, 240, 240);
   253    }
   254  
   255    /* Add explicit links */
   256    a:link:after, a:visited:after {
   257     content: " (" attr(href) ") ";
   258     font-size: 50%;
   259    }
   260  
   261    #help {
   262      display: none;
   263      visibility: hidden;
   264    }
   265  }
   266  
   267  /* Styles for slides */
   268  
   269  .slides > article {
   270    font-family: 'Open Sans', Arial, sans-serif;
   271  
   272    color: black;
   273    text-shadow: 0 1px 1px rgba(0, 0, 0, .1);
   274  
   275    font-size: 26px;
   276    line-height: 36px;
   277  
   278    letter-spacing: -1px;
   279  }
   280  
   281  b {
   282    font-weight: 600;
   283  }
   284  
   285  a {
   286    color: rgb(0, 102, 204);
   287    text-decoration: none;
   288  }
   289  a:visited {
   290    color: rgba(0, 102, 204, .75);
   291  }
   292  a:hover {
   293    color: black;
   294  }
   295  
   296  p {
   297    margin: 0;
   298    padding: 0;
   299  
   300    margin-top: 20px;
   301  }
   302  p:first-child {
   303    margin-top: 0;
   304  }
   305  
   306  h1 {
   307    font-size: 60px;
   308    line-height: 60px;
   309  
   310    padding: 0;
   311    margin: 0;
   312    margin-top: 200px;
   313    margin-bottom: 5px;
   314    padding-right: 40px;
   315  
   316    font-weight: 600;
   317  
   318    letter-spacing: -3px;
   319  
   320    color: rgb(51, 51, 51);
   321  }
   322  
   323  h2 {
   324    font-size: 45px;
   325    line-height: 45px;
   326  
   327    position: absolute;
   328    bottom: 150px;
   329  
   330    padding: 0;
   331    margin: 0;
   332    padding-right: 40px;
   333  
   334    font-weight: 600;
   335  
   336    letter-spacing: -2px;
   337  
   338    color: rgb(51, 51, 51);
   339  }
   340  
   341  h3 {
   342    font-size: 30px;
   343    line-height: 36px;
   344  
   345    padding: 0;
   346    margin: 0;
   347    padding-right: 40px;
   348  
   349    font-weight: 600;
   350  
   351    letter-spacing: -1px;
   352  
   353    color: rgb(51, 51, 51);
   354  }
   355  
   356  ul {
   357    margin: 0;
   358    padding: 0;
   359    margin-top: 20px;
   360    margin-left: 1.5em;
   361  }
   362  li {
   363    padding: 0;
   364    margin: 0 0 .5em 0;
   365  }
   366  
   367  div.code {
   368    padding: 5px 10px;
   369    margin-top: 20px;
   370    margin-bottom: 20px;
   371    overflow: hidden;
   372  
   373    background: rgb(240, 240, 240);
   374    border: 1px solid rgb(224, 224, 224);
   375  }
   376  pre {
   377    margin: 0;
   378    padding: 0;
   379  
   380    font-family: 'Droid Sans Mono', 'Courier New', monospace;
   381    font-size: 18px;
   382    line-height: 24px;
   383    letter-spacing: -1px;
   384  
   385    color: black;
   386  }
   387  
   388  pre.numbers span:before {
   389    content: attr(num);
   390    margin-right: 1em;
   391    display: inline-block;
   392  }
   393  
   394  code {
   395    font-size: 95%;
   396    font-family: 'Droid Sans Mono', 'Courier New', monospace;
   397  
   398    color: black;
   399  }
   400  
   401  article > .image,
   402  article > .video {
   403    text-align: center;
   404    margin-top: 40px;
   405  }
   406  
   407  article > .background {
   408    position: absolute;
   409    top: 0;
   410    left: 0;
   411    right: 0;
   412    bottom: 0;
   413    z-index: -1;
   414  }
   415  
   416  article > .background > img {
   417    max-height: 100%;
   418    max-width: 100%;
   419  }
   420  
   421  table {
   422    width: 100%;
   423    border-collapse: collapse;
   424    margin-top: 40px;
   425  }
   426  th {
   427    font-weight: 600;
   428    text-align: left;
   429  }
   430  td,
   431  th {
   432    border: 1px solid rgb(224, 224, 224);
   433    padding: 5px 10px;
   434    vertical-align: top;
   435  }
   436  
   437  p.link {
   438    margin-left: 20px;
   439  }
   440  
   441  /* Code */
   442  div.code {
   443    outline: 0px solid transparent;
   444  }
   445  div.playground {
   446    position: relative;
   447  }
   448  div.output {
   449    position: absolute;
   450    left: 50%;
   451    top: 50%;
   452    right: 40px;
   453    bottom: 40px;
   454    background: #202020;
   455    padding: 5px 10px;
   456    z-index: 2;
   457  
   458    border-radius: 10px;
   459    -o-border-radius: 10px;
   460    -moz-border-radius: 10px;
   461    -webkit-border-radius: 10px;
   462  
   463  }
   464  div.output pre {
   465    margin: 0;
   466    padding: 0;
   467    background: none;
   468    border: none;
   469    width: 100%;
   470    height: 100%;
   471    overflow: auto;
   472  }
   473  div.output .stdout, div.output pre {
   474    color: #e6e6e6;
   475  }
   476  div.output .stderr, div.output .error {
   477    color: rgb(255, 200, 200);
   478  }
   479  div.output .system, div.output .exit {
   480    color: rgb(255, 230, 120)
   481  }
   482  .buttons {
   483    position: relative;
   484    float: right;
   485    top: -60px;
   486    right: 10px;
   487  }
   488  div.output .buttons {
   489    position: absolute;
   490    float: none;
   491    top: auto;
   492    right: 5px;
   493    bottom: 5px;
   494  }
   495  
   496  /* Presenter details */
   497  .presenter {
   498    margin-top: 20px;
   499  }
   500  .presenter p,
   501  .presenter .link {
   502    margin: 0;
   503    font-size: 28px;
   504    line-height: 1.2em;
   505  }
   506  
   507  /* Output resize details */
   508  .ui-resizable-handle {
   509    position: absolute;
   510  }
   511  .ui-resizable-n {
   512    cursor: n-resize;
   513    height: 7px;
   514    width: 100%;
   515    top: -5px;
   516    left: 0;
   517  }
   518  .ui-resizable-w {
   519    cursor: w-resize;
   520    width: 7px;
   521    left: -5px;
   522    top: 0;
   523    height: 100%;
   524  }
   525  .ui-resizable-nw {
   526    cursor: nw-resize;
   527    width: 9px;
   528    height: 9px;
   529    left: -5px;
   530    top: -5px;
   531  }
   532  iframe {
   533    border: none;
   534  }
   535  figcaption {
   536    color: #666;
   537    text-align: center;
   538    font-size: 0.75em;
   539  }
   540  
   541  #help {
   542    font-family: 'Open Sans', Arial, sans-serif;
   543    text-align: center;
   544    color: white;
   545    background: #000;
   546    opacity: 0.5;
   547    position: fixed;
   548    bottom: 25px;
   549    left: 50px;
   550    right: 50px;
   551    padding: 20px;
   552  
   553    border-radius: 10px;
   554    -o-border-radius: 10px;
   555    -moz-border-radius: 10px;
   556    -webkit-border-radius: 10px;
   557  }
   558        </style>
   559      <script>
   560      // Copyright 2012 The Go Authors. All rights reserved.
   561      // Use of this source code is governed by a BSD-style
   562      // license that can be found in the LICENSE file.
   563  
   564      var PERMANENT_URL_PREFIX = '/static/';
   565  
   566      var SLIDE_CLASSES = ['far-past', 'past', 'current', 'next', 'far-next'];
   567  
   568      var PM_TOUCH_SENSITIVITY = 15;
   569  
   570      var curSlide;
   571  
   572      /* ---------------------------------------------------------------------- */
   573      /* classList polyfill by Eli Grey
   574       * (http://purl.eligrey.com/github/classList.js/blob/master/classList.js) */
   575  
   576      if (typeof document !== 'undefined' && !('classList' in document.createElement('a'))) {
   577  
   578      (function (view) {
   579  
   580      var
   581          classListProp = 'classList'
   582        , protoProp = 'prototype'
   583        , elemCtrProto = (view.HTMLElement || view.Element)[protoProp]
   584        , objCtr = Object
   585          strTrim = String[protoProp].trim || function () {
   586          return this.replace(/^\s+|\s+$/g, '');
   587        }
   588        , arrIndexOf = Array[protoProp].indexOf || function (item) {
   589          for (var i = 0, len = this.length; i < len; i++) {
   590            if (i in this && this[i] === item) {
   591              return i;
   592            }
   593          }
   594          return -1;
   595        }
   596        // Vendors: please allow content code to instantiate DOMExceptions
   597        , DOMEx = function (type, message) {
   598          this.name = type;
   599          this.code = DOMException[type];
   600          this.message = message;
   601        }
   602        , checkTokenAndGetIndex = function (classList, token) {
   603          if (token === '') {
   604            throw new DOMEx(
   605                'SYNTAX_ERR'
   606              , 'An invalid or illegal string was specified'
   607            );
   608          }
   609          if (/\s/.test(token)) {
   610            throw new DOMEx(
   611                'INVALID_CHARACTER_ERR'
   612              , 'String contains an invalid character'
   613            );
   614          }
   615          return arrIndexOf.call(classList, token);
   616        }
   617        , ClassList = function (elem) {
   618          var
   619              trimmedClasses = strTrim.call(elem.className)
   620            , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
   621          ;
   622          for (var i = 0, len = classes.length; i < len; i++) {
   623            this.push(classes[i]);
   624          }
   625          this._updateClassName = function () {
   626            elem.className = this.toString();
   627          };
   628        }
   629        , classListProto = ClassList[protoProp] = []
   630        , classListGetter = function () {
   631          return new ClassList(this);
   632        }
   633      ;
   634      // Most DOMException implementations don't allow calling DOMException's toString()
   635      // on non-DOMExceptions. Error's toString() is sufficient here.
   636      DOMEx[protoProp] = Error[protoProp];
   637      classListProto.item = function (i) {
   638        return this[i] || null;
   639      };
   640      classListProto.contains = function (token) {
   641        token += '';
   642        return checkTokenAndGetIndex(this, token) !== -1;
   643      };
   644      classListProto.add = function (token) {
   645        token += '';
   646        if (checkTokenAndGetIndex(this, token) === -1) {
   647          this.push(token);
   648          this._updateClassName();
   649        }
   650      };
   651      classListProto.remove = function (token) {
   652        token += '';
   653        var index = checkTokenAndGetIndex(this, token);
   654        if (index !== -1) {
   655          this.splice(index, 1);
   656          this._updateClassName();
   657        }
   658      };
   659      classListProto.toggle = function (token) {
   660        token += '';
   661        if (checkTokenAndGetIndex(this, token) === -1) {
   662          this.add(token);
   663        } else {
   664          this.remove(token);
   665        }
   666      };
   667      classListProto.toString = function () {
   668        return this.join(' ');
   669      };
   670  
   671      if (objCtr.defineProperty) {
   672        var classListPropDesc = {
   673            get: classListGetter
   674          , enumerable: true
   675          , configurable: true
   676        };
   677        try {
   678          objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
   679        } catch (ex) { // IE 8 doesn't support enumerable:true
   680          if (ex.number === -0x7FF5EC54) {
   681            classListPropDesc.enumerable = false;
   682            objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
   683          }
   684        }
   685      } else if (objCtr[protoProp].__defineGetter__) {
   686        elemCtrProto.__defineGetter__(classListProp, classListGetter);
   687      }
   688  
   689      }(self));
   690  
   691      }
   692      /* ---------------------------------------------------------------------- */
   693  
   694      /* Slide movement */
   695  
   696      function hideHelpText() {
   697        document.getElementById('help').style.display = 'none';
   698      };
   699  
   700      function getSlideEl(no) {
   701        if ((no < 0) || (no >= slideEls.length)) {
   702          return null;
   703        } else {
   704          return slideEls[no];
   705        }
   706      };
   707  
   708      function updateSlideClass(slideNo, className) {
   709        var el = getSlideEl(slideNo);
   710  
   711        if (!el) {
   712          return;
   713        }
   714  
   715        if (className) {
   716          el.classList.add(className);
   717        }
   718  
   719        for (var i in SLIDE_CLASSES) {
   720          if (className != SLIDE_CLASSES[i]) {
   721            el.classList.remove(SLIDE_CLASSES[i]);
   722          }
   723        }
   724      };
   725  
   726      function updateSlides() {
   727        if (window.trackPageview) window.trackPageview();
   728  
   729        for (var i = 0; i < slideEls.length; i++) {
   730          switch (i) {
   731            case curSlide - 2:
   732              updateSlideClass(i, 'far-past');
   733              break;
   734            case curSlide - 1:
   735              updateSlideClass(i, 'past');
   736              break;
   737            case curSlide:
   738              updateSlideClass(i, 'current');
   739              break;
   740            case curSlide + 1:
   741              updateSlideClass(i, 'next');
   742              break;
   743            case curSlide + 2:
   744              updateSlideClass(i, 'far-next');
   745              break;
   746            default:
   747              updateSlideClass(i);
   748              break;
   749          }
   750        }
   751  
   752        triggerLeaveEvent(curSlide - 1);
   753        triggerEnterEvent(curSlide);
   754  
   755        window.setTimeout(function() {
   756          // Hide after the slide
   757          disableSlideFrames(curSlide - 2);
   758        }, 301);
   759  
   760        enableSlideFrames(curSlide - 1);
   761        enableSlideFrames(curSlide + 2);
   762  
   763        updateHash();
   764      };
   765  
   766      function prevSlide() {
   767        hideHelpText();
   768        if (curSlide > 0) {
   769          curSlide--;
   770  
   771          updateSlides();
   772        }
   773  
   774        if (notesEnabled) localStorage.setItem('destSlide', curSlide);
   775      };
   776  
   777      function nextSlide() {
   778        hideHelpText();
   779        if (curSlide < slideEls.length - 1) {
   780          curSlide++;
   781  
   782          updateSlides();
   783        }
   784  
   785        if (notesEnabled) localStorage.setItem('destSlide', curSlide);
   786      };
   787  
   788      /* Slide events */
   789  
   790      function triggerEnterEvent(no) {
   791        var el = getSlideEl(no);
   792        if (!el) {
   793          return;
   794        }
   795  
   796        var onEnter = el.getAttribute('onslideenter');
   797        if (onEnter) {
   798          new Function(onEnter).call(el);
   799        }
   800  
   801        var evt = document.createEvent('Event');
   802        evt.initEvent('slideenter', true, true);
   803        evt.slideNumber = no + 1; // Make it readable
   804  
   805        el.dispatchEvent(evt);
   806      };
   807  
   808      function triggerLeaveEvent(no) {
   809        var el = getSlideEl(no);
   810        if (!el) {
   811          return;
   812        }
   813  
   814        var onLeave = el.getAttribute('onslideleave');
   815        if (onLeave) {
   816          new Function(onLeave).call(el);
   817        }
   818  
   819        var evt = document.createEvent('Event');
   820        evt.initEvent('slideleave', true, true);
   821        evt.slideNumber = no + 1; // Make it readable
   822  
   823        el.dispatchEvent(evt);
   824      };
   825  
   826      /* Touch events */
   827  
   828      function handleTouchStart(event) {
   829        if (event.touches.length == 1) {
   830          touchDX = 0;
   831          touchDY = 0;
   832  
   833          touchStartX = event.touches[0].pageX;
   834          touchStartY = event.touches[0].pageY;
   835  
   836          document.body.addEventListener('touchmove', handleTouchMove, true);
   837          document.body.addEventListener('touchend', handleTouchEnd, true);
   838        }
   839      };
   840  
   841      function handleTouchMove(event) {
   842        if (event.touches.length > 1) {
   843          cancelTouch();
   844        } else {
   845          touchDX = event.touches[0].pageX - touchStartX;
   846          touchDY = event.touches[0].pageY - touchStartY;
   847          event.preventDefault();
   848        }
   849      };
   850  
   851      function handleTouchEnd(event) {
   852        var dx = Math.abs(touchDX);
   853        var dy = Math.abs(touchDY);
   854  
   855        if ((dx > PM_TOUCH_SENSITIVITY) && (dy < (dx * 2 / 3))) {
   856          if (touchDX > 0) {
   857            prevSlide();
   858          } else {
   859            nextSlide();
   860          }
   861        }
   862  
   863        cancelTouch();
   864      };
   865  
   866      function cancelTouch() {
   867        document.body.removeEventListener('touchmove', handleTouchMove, true);
   868        document.body.removeEventListener('touchend', handleTouchEnd, true);
   869      };
   870  
   871      /* Preloading frames */
   872  
   873      function disableSlideFrames(no) {
   874        var el = getSlideEl(no);
   875        if (!el) {
   876          return;
   877        }
   878  
   879        var frames = el.getElementsByTagName('iframe');
   880        for (var i = 0, frame; frame = frames[i]; i++) {
   881          disableFrame(frame);
   882        }
   883      };
   884  
   885      function enableSlideFrames(no) {
   886        var el = getSlideEl(no);
   887        if (!el) {
   888          return;
   889        }
   890  
   891        var frames = el.getElementsByTagName('iframe');
   892        for (var i = 0, frame; frame = frames[i]; i++) {
   893          enableFrame(frame);
   894        }
   895      };
   896  
   897      function disableFrame(frame) {
   898        frame.src = 'about:blank';
   899      };
   900  
   901      function enableFrame(frame) {
   902        var src = frame._src;
   903  
   904        if (frame.src != src && src != 'about:blank') {
   905          frame.src = src;
   906        }
   907      };
   908  
   909      function setupFrames() {
   910        var frames = document.querySelectorAll('iframe');
   911        for (var i = 0, frame; frame = frames[i]; i++) {
   912          frame._src = frame.src;
   913          disableFrame(frame);
   914        }
   915  
   916        enableSlideFrames(curSlide);
   917        enableSlideFrames(curSlide + 1);
   918        enableSlideFrames(curSlide + 2);
   919      };
   920  
   921      function setupInteraction() {
   922        /* Clicking and tapping */
   923  
   924        var el = document.createElement('div');
   925        el.className = 'slide-area';
   926        el.id = 'prev-slide-area';
   927        el.addEventListener('click', prevSlide, false);
   928        document.querySelector('section.slides').appendChild(el);
   929  
   930        var el = document.createElement('div');
   931        el.className = 'slide-area';
   932        el.id = 'next-slide-area';
   933        el.addEventListener('click', nextSlide, false);
   934        document.querySelector('section.slides').appendChild(el);
   935  
   936        /* Swiping */
   937  
   938        document.body.addEventListener('touchstart', handleTouchStart, false);
   939      }
   940  
   941      /* Hash functions */
   942  
   943      function getCurSlideFromHash() {
   944        var slideNo = parseInt(location.hash.substr(1));
   945  
   946        if (slideNo) {
   947          curSlide = slideNo - 1;
   948        } else {
   949          curSlide = 0;
   950        }
   951      };
   952  
   953      function updateHash() {
   954        // TODO
   955        // location.replace('#' + (curSlide + 1));
   956      };
   957  
   958      /* Event listeners */
   959  
   960      function handleBodyKeyDown(event) {
   961        // If we're in a code element, only handle pgup/down.
   962        var inCode = event.target.classList.contains('code');
   963  
   964        switch (event.keyCode) {
   965          case 78: // 'N' opens presenter notes window
   966            if (!inCode && notesEnabled) toggleNotesWindow();
   967            break;
   968          case 72: // 'H' hides the help text
   969          case 27: // escape key
   970            if (!inCode) hideHelpText();
   971            break;
   972  
   973          case 39: // right arrow
   974          case 13: // Enter
   975          case 32: // space
   976            if (inCode) break;
   977          case 34: // PgDn
   978            nextSlide();
   979            event.preventDefault();
   980            break;
   981  
   982          case 37: // left arrow
   983          case 8: // Backspace
   984            if (inCode) break;
   985          case 33: // PgUp
   986            prevSlide();
   987            event.preventDefault();
   988            break;
   989  
   990          case 40: // down arrow
   991            if (inCode) break;
   992            nextSlide();
   993            event.preventDefault();
   994            break;
   995  
   996          case 38: // up arrow
   997            if (inCode) break;
   998            prevSlide();
   999            event.preventDefault();
  1000            break;
  1001        }
  1002      };
  1003  
  1004      function addEventListeners() {
  1005        document.addEventListener('keydown', handleBodyKeyDown, false);
  1006      };
  1007  
  1008      /* Initialization */
  1009  
  1010      function addFontStyle() {
  1011        var el = document.createElement('link');
  1012        el.rel = 'stylesheet';
  1013        el.type = 'text/css';
  1014        el.href = '//fonts.googleapis.com/css?family=' +
  1015                  'Open+Sans:regular,semibold,italic,italicsemibold|Droid+Sans+Mono';
  1016  
  1017        document.body.appendChild(el);
  1018      };
  1019  
  1020      function addGeneralStyle() {
  1021        var el = document.createElement('link');
  1022        el.rel = 'stylesheet';
  1023        el.type = 'text/css';
  1024        el.href = PERMANENT_URL_PREFIX + 'styles.css';
  1025        document.body.appendChild(el);
  1026  
  1027        var el = document.createElement('meta');
  1028        el.name = 'viewport';
  1029        el.content = 'width=1100,height=750';
  1030        document.querySelector('head').appendChild(el);
  1031  
  1032        var el = document.createElement('meta');
  1033        el.name = 'apple-mobile-web-app-capable';
  1034        el.content = 'yes';
  1035        document.querySelector('head').appendChild(el);
  1036      };
  1037  
  1038      function handleDomLoaded() {
  1039        slideEls = document.querySelectorAll('section.slides > article');
  1040  
  1041        setupFrames();
  1042  
  1043        addFontStyle();
  1044        // addGeneralStyle();
  1045        addEventListeners();
  1046  
  1047        updateSlides();
  1048  
  1049        setupInteraction();
  1050  
  1051        if (window.location.hostname == 'localhost' || window.location.hostname == '127.0.0.1' || window.location.hostname == '::1') {
  1052          hideHelpText();
  1053        }
  1054  
  1055        document.body.classList.add('loaded');
  1056  
  1057        setupNotesSync();
  1058      };
  1059  
  1060      function initialize() {
  1061        getCurSlideFromHash();
  1062  
  1063        if (window['_DEBUG']) {
  1064          PERMANENT_URL_PREFIX = '../';
  1065        }
  1066  
  1067        if (window['_DCL']) {
  1068          handleDomLoaded();
  1069        } else {
  1070          document.addEventListener('DOMContentLoaded', handleDomLoaded, false);
  1071        }
  1072      }
  1073  
  1074      // If ?debug exists then load the script relative instead of absolute
  1075      if (!window['_DEBUG'] && document.location.href.indexOf('?debug') !== -1) {
  1076        document.addEventListener('DOMContentLoaded', function() {
  1077          // Avoid missing the DomContentLoaded event
  1078          window['_DCL'] = true
  1079        }, false);
  1080  
  1081        window['_DEBUG'] = true;
  1082        var script = document.createElement('script');
  1083        script.type = 'text/javascript';
  1084        script.src = '../slides.js';
  1085        var s = document.getElementsByTagName('script')[0];
  1086        s.parentNode.insertBefore(script, s);
  1087  
  1088        // Remove this script
  1089        s.parentNode.removeChild(s);
  1090      } else {
  1091        initialize();
  1092      }
  1093  
  1094      /* Synchronize windows when notes are enabled */
  1095  
  1096      function setupNotesSync() {
  1097        if (!notesEnabled) return;
  1098  
  1099        function setupPlayResizeSync() {
  1100          var out = document.getElementsByClassName('output');
  1101          for (var i = 0; i < out.length; i++) {
  1102            $(out[i]).bind('resize', function(event) {
  1103              if ($(event.target).hasClass('ui-resizable')) {
  1104                localStorage.setItem('play-index', i);
  1105                localStorage.setItem('output-style', out[i].style.cssText);
  1106              }
  1107            })
  1108          }
  1109        };
  1110        function setupPlayCodeSync() {
  1111          var play = document.querySelectorAll('div.playground');
  1112          for (var i = 0; i < play.length; i++) {
  1113            play[i].addEventListener('input', inputHandler, false);
  1114  
  1115            function inputHandler(e) {
  1116              localStorage.setItem('play-index', i);
  1117              localStorage.setItem('play-code', e.target.innerHTML);
  1118            }
  1119          }
  1120        };
  1121  
  1122        setupPlayCodeSync();
  1123        setupPlayResizeSync();
  1124        localStorage.setItem('destSlide', curSlide);
  1125        window.addEventListener('storage', updateOtherWindow, false);
  1126      }
  1127  
  1128      // An update to local storage is caught only by the other window
  1129      // The triggering window does not handle any sync actions
  1130      function updateOtherWindow(e) {
  1131        // Ignore remove storage events which are not meant to update the other window
  1132        var isRemoveStorageEvent = !e.newValue;
  1133        if (isRemoveStorageEvent) return;
  1134  
  1135        var destSlide = localStorage.getItem('destSlide');
  1136        while (destSlide > curSlide) {
  1137          nextSlide();
  1138        }
  1139        while (destSlide < curSlide) {
  1140          prevSlide();
  1141        }
  1142  
  1143        updatePlay(e);
  1144        updateNotes();
  1145      }
  1146      </script>
  1147  
  1148      {{if .NotesEnabled}}
  1149      <script>
  1150        var sections = {{.Sections}};
  1151        var titleNotes = {{.TitleNotes}}
  1152      </script>
  1153      <script src='/static/notes.js'></script>
  1154      {{end}}
  1155  
  1156      <script>
  1157        // Initialize Google Analytics tracking code on production site only.
  1158        if (window["location"] && window["location"]["hostname"] == "talks.golang.org") {
  1159          var _gaq = _gaq || [];
  1160          _gaq.push(["_setAccount", "UA-11222381-6"]);
  1161          _gaq.push(["b._setAccount", "UA-49880327-6"]);
  1162          window.trackPageview = function() {
  1163            _gaq.push(["_trackPageview", location.pathname+location.hash]);
  1164            _gaq.push(["b._trackPageview", location.pathname+location.hash]);
  1165          };
  1166          window.trackPageview();
  1167          window.trackEvent = function(category, action, opt_label, opt_value, opt_noninteraction) {
  1168            _gaq.push(["_trackEvent", category, action, opt_label, opt_value, opt_noninteraction]);
  1169            _gaq.push(["b._trackEvent", category, action, opt_label, opt_value, opt_noninteraction]);
  1170          };
  1171        }
  1172      </script>
  1173    </head>
  1174  
  1175    <body style='display: none'>
  1176  
  1177      <section class='slides layout-widescreen'>
  1178  
  1179        <article>
  1180          <h1>{{.Title}}</h1>
  1181          {{with .Subtitle}}<h3>{{.}}</h3>{{end}}
  1182          {{if not .Time.IsZero}}<h3>{{.Time.Format "2 January 2006"}}</h3>{{end}}
  1183          {{range .Authors}}
  1184            <div class="presenter">
  1185              {{range .TextElem}}{{elem $.Template .}}{{end}}
  1186            </div>
  1187          {{end}}
  1188        </article>
  1189  
  1190    {{range $i, $s := .Sections}}
  1191    <!-- start of slide {{$s.Number}} -->
  1192        <article>
  1193        {{if $s.Elem}}
  1194          <h3>{{$s.Title}}</h3>
  1195          {{range $s.Elem}}{{elem $.Template .}}{{end}}
  1196        {{else}}
  1197          <h2>{{$s.Title}}</h2>
  1198        {{end}}
  1199        </article>
  1200    <!-- end of slide {{$i}} -->
  1201    {{end}}{{/* of Slide block */}}
  1202  
  1203        <article>
  1204          <h3>Thank you</h3>
  1205          {{range .Authors}}
  1206            <div class="presenter">
  1207              {{range .Elem}}{{elem $.Template .}}{{end}}
  1208            </div>
  1209          {{end}}
  1210        </article>
  1211  
  1212      </section>
  1213  
  1214      <div id="help">
  1215        Use the left and right arrow keys or click the left and right
  1216        edges of the page to navigate between slides.<br>
  1217        (Press 'H' or navigate to hide this message.)
  1218      </div>
  1219  
  1220      {{if .PlayEnabled}}
  1221      <script src='/play.js'></script>
  1222      {{end}}
  1223  
  1224      <script>
  1225        (function() {
  1226          // Load Google Analytics tracking code on production site only.
  1227          if (window["location"] && window["location"]["hostname"] == "talks.golang.org") {
  1228            var ga = document.createElement("script"); ga.type = "text/javascript"; ga.async = true;
  1229            ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";
  1230            var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ga, s);
  1231          }
  1232        })();
  1233      </script>
  1234    </body>
  1235  </html>
  1236  {{end}}
  1237  
  1238  {{define "newline"}}
  1239  <br>
  1240  {{end}}