<commit_before>'use strict';

/* global queryRegExSelector, queryRegExSelectorAll, getYouTubeHtml5VideoUrl */
Polymer('polymer-hypervideo', {
  publish: {
    currentTime: 0,
    duration: null,
    actorsOffset: {}
  },
  created: function() {
  },
  ready: function() {
    var that = this;
    var spinner;
    var video = that.$.hypervideo;
    var container = that.$.container;

    var onMutation = function(observer, mutations) {
      var nodes = [];
      var chapters = [];
      for (var i = 0, lenI = mutations.length; i < lenI; i++) {
        var mutation = mutations[i];
        if (mutation.addedNodes) {
          for (var j = 0, lenJ = mutation.addedNodes.length; j < lenJ; j++) {
            if (/^polymer-data-/gi.test(mutation.addedNodes[j].nodeName)) {
              nodes.push(mutation.addedNodes[j]);
            }
          }
        }
      }
      if (nodes.length) {
        positionDataAnnotations(nodes);
        updateTimelineAnnotations(nodes);
      }
      that.onMutation(that, onMutation);
    };

    that.onMutation(that, onMutation);

    var CORS_PROXY = document.location.origin + '/cors/';
    document.addEventListener('trackready', function(e) {
      console.log('Received event (document): trackready');
      var data = e.detail;
      var track = document.createElement('track');
      var cuesRead = false;
      track.addEventListener('load', function(e) {
        if (!cuesRead) {
          console.log('Received event (track): load');
          cuesRead = true;
          return readCues(e.target.track.cues, data.kind);
        }
      }, false);
      track.addEventListener('cuechange', function() {
        console.log('Fired event: hypervideocuechange');
        that.fire(
          'hypervideocuechange',
          {
            activeCues: track.track.activeCues
          }
        );
      });
      var trackLoadedInterval = setInterval(function() {
        if (track.readyState >= 2) {
          clearInterval(trackLoadedInterval);
          if (!cuesRead) {
            console.log('Received event (track): readyState');
            cuesRead = true;
            return readCues(track.track.cues, data.kind);
          }
        }
      }, 100);
      track.src = data.src;
      track.default = true;
      track.kind = data.kind;
      if (track.kind === 'subtitles' || track.kind === 'captions') {
        track.srclang = 'en';
        track.track.mode = 'showing';
      } else if (track.kind === 'chapters') {
        var canvas = document.createElement('canvas');
        canvas.width = video.width;
        canvas.height = video.height;
        var ctx = canvas.getContext('2d');
        that.ctx = ctx;
        that.canvas = canvas;
      }
      video.appendChild(track);
    }, false);

    document.addEventListener('webcomponentstocready', function() {
      console.log('Received event (document): webcomponentstocready');
      // get all child <polymer-*> child nodes
      var webComponents = queryRegExSelectorAll(that, /^polymer-/gi);
      console.log('Fired event: webcomponentstoc');
      that.fire(
        'webcomponentstoc',
        {
          webComponentsToC: webComponents
        }
      );
    }, false);

    var updateTimelineAnnotations = function(opt_nodes) {
      // get all child <polymer-data-*> child nodes
      var dataAnnotations =
          opt_nodes || queryRegExSelectorAll(that, /^polymer-data-/gi);
      var annotations = [];
      dataAnnotations.forEach(function(annotation) {
        var type;
        if (/actor/gi.test(annotation.nodeName)) {
          type = 'actors';
        } else if (/overlay/gi.test(annotation.nodeName)) {
          type = 'overlays';
        } else {
          type = 'annotations';
        }
        annotations.push({
          start: parseInt(annotation.getAttribute('start'), 10),
          end: parseInt(annotation.getAttribute('end'), 10),
          type: type
        });
      });
      console.log('Fired event: dataannotations');
      that.fire(
        'dataannotations',
        {
          dataAnnotations: annotations
        }
      );

    };

    document.addEventListener('timelineready', function() {
      console.log('Received event (document): timelineready');
      updateTimelineAnnotations();
    }, false);

    // listen for events coming from the timeline component
    document.addEventListener('currenttimeupdate', function(e) {
      // console.log('Received event (document): currenttimeupdate');
      var data = e.detail;
      video.currentTime = data.currentTime;
      video.play();
    }, false);

    document.addEventListener('requeststillframes', function(e) {
      console.log('Received event (document): requeststillframes');
      spinner = showSpinner();
      var cues = e.detail.cues;
      if (!cues) {
        return;
      }
      var functions = [];
      cues.forEach(function(cue) {
        var start = cue.start;
        if (start > video.duration) {
          return;
        }
        functions.push({
          cue: cue,
          func: function() {
            video.currentTime = start;
          }
        });
      });
      var getNextStillFrame = function() {
        console.log('Received event (video): seeked');
        that.ctx.drawImage(video, 0, 0, video.clientWidth,
            video.clientHeight);
        var img = document.createElement('img');
        img.setAttribute('class', 'hypervideo');
        var url = that.canvas.toDataURL();
        img.src = url;
        var cue = functions[processedStillFrames].cue;
        console.log('Fired event: receivestillframe');
        that.fire(
          'receivestillframe',
          {
            img: img,
            text: cue.text,
            start: cue.start,
            end: cue.end
          }
        );
        processedStillFrames++;
        if (functions[processedStillFrames]) {
          return functions[processedStillFrames].func();
        } else {
          video.removeEventListener('seeked', getNextStillFrame);
          video.currentTime = 0;
          that.fire('allstillframesreceived');
          spinner.remove();
        }
      };
      var processedStillFrames = 0;
      video.addEventListener('seeked', getNextStillFrame);
      functions[processedStillFrames].func();
    });

    var initializeVideo = function() {
      // either add sources for regular video
      if (that.src) {
        that.src.split(/\s/g).forEach(function(src) {
          var source = document.createElement('source');
          source.src = src;
          video.appendChild(source);
        });
      // or add sources for YouTube video
      } else if (that.youtubevideoid) {
        getYouTubeHtml5VideoUrl(that.youtubevideoid,
            function(err, videoSources) {
          if (err) {
            return;
          }
          for (var videoSource in videoSources) {
            videoSource = videoSources[videoSource];
            var source = document.createElement('source');
            source.src = CORS_PROXY +
                encodeURIComponent(videoSource.original_url);
            source.type = videoSource.type.replace(/\+/g, ' ')
                .replace(/"/g, '\"');
            video.appendChild(source);
          }
        });
      }
      // determine video dimensions
      if (that.width) {
        that.width = parseInt(that.width, 10);
      } else {
        that.width = 400;
      }
      video.width = that.width;
      if (that.height) {
        that.height = parseInt(that.height, 10);
      } else {
        that.height = 225;
      }
      video.height = that.height;
      // add poster
      if (that.poster) {
        video.poster = that.poster;
      }
      // mute video
      if (that.muted !== null && that.muted !== 'false') {
        video.muted = true;
      }
    };

    var showSpinner = function() {
      // show spinner while the hypervideo gets prepared
      var splashDiv = document.createElement('div');
      splashDiv.classList.add('spinner');
      var splashSpinner = document.createElement('div');
      splashSpinner.classList.add('progress');
      splashDiv.appendChild(splashSpinner);
      splashDiv.style.width = video.width + 'px';
      splashDiv.style.height = video.height + 'px';
      splashDiv.style.position = 'absolute';
      splashDiv.style.top = video.offsetTop + 'px';
      splashDiv.style.left = video.offsetLeft + 'px';
      splashSpinner.style.position = 'relative';
      splashSpinner.style.top = (video.offsetHeight / 2 - 60 / 2) + 'px';
      splashSpinner.style.left = (video.offsetWidth / 2 - 60 / 2) + 'px';
      var loadingDiv = document.createElement('div');
      loadingDiv.textContent = '*';
      splashSpinner.appendChild(loadingDiv);
      container.appendChild(splashDiv);
      return splashDiv;
    };

    var positionDataAnnotations = function(opt_nodes) {
      // positions data annotations on top of the video
      var polymerData =
          opt_nodes || queryRegExSelectorAll(that, /^polymer-data-/gi);
      polymerData.forEach(function(node) {
        node.style.position = 'absolute';
        node.style.top = (video.offsetTop + 0.66 * video.offsetHeight) +
            'px';
        node.style.left = (video.offsetLeft + (0.05 * that.width)) + 'px';
        node.style.width = (0.9 * that.width) + 'px';
        node.style.display = 'none';
      });
    };

    var readCues = function(cues, kind) {
      if (!cues) {
        return;
      }
      var cueData = [];
      for (var i = 0, lenI = cues.length; i < lenI; i++) {
        var cue = cues.item ? cues.item(i) : cues[i];
        cueData.push({
          start: parseInt(cue.startTime, 10),
          end: parseInt(cue.endTime, 10),
          text: cue.text,
          id: cue.id,
          type: kind
        });
      }
      console.log('Fired event: cuesread');
      that.fire(
        'cuesread',
        {
          cueData: cueData,
          kind: kind
        }
      );
    };

    video.addEventListener('loadedmetadata', function() {
      console.log('Received event (video): loadedmetadata');
      that.duration = video.duration;
      // adjust the timeline dimensions according to the video duration
      var polymerTimelines = that.querySelectorAll('polymer-timeline');
      for (var i = 0, lenI = polymerTimelines.length; i < lenI; i++) {
        polymerTimelines[i].style.left = (video.offsetLeft +
            (0.05 * that.width)) + 'px';
      }
      var polymerData = queryRegExSelector(that, /^polymer-data-/gi);
      console.log('Fired event: hypervideoloadedmetadata');
      that.fire(
        'hypervideoloadedmetadata',
        {
          duration: that.duration,
          height: that.height,
          width: that.width,
          actorsOffset: {
            left: polymerData ? polymerData.style.left.replace('px', '') : null,
            top: polymerData ? polymerData.style.top.replace('px', '') : null
          }
        }
      );

      // alternative views
      if (that.alternativeviews) {
        var videos = [video];
        var videoWidth = Math.floor(that.width / 5);
        var ratio = that.width / that.height;

        function showControls(e) {
          return e.target.setAttribute('controls', true);
        }

        var hideControls = function hideControls(e) {
          return e.target.removeAttribute('controls');
        };

        var playAll = function playAll() {
          for (var i = 0; i < videos.length; i++) {
            videos[i].play();
          }
        };

        var pauseAll = function pauseAll() {
          for (var i = 0; i < videos.length; i++) {
            videos[i].pause();
          }
        };

        var seekAll = function seekAll(e) {
          for (var i = 0; i < videos.length; i++) {
            var currentVideo = videos[i];
            if (currentVideo === e.target) {
              continue;
            }
            currentVideo.currentTime = e.target.currentTime;
          }
        };

        var transitionend = function transitioned(e) {
          for (var i = 0; i < videos.length; i++) {
            var currentVideo = videos[i];
            currentVideo.style.zIndex = 'auto';
          }
        }

        var makeBig = function makeBig(e) {
          for (var i = 0, j = 0; i < videos.length; i++) {
            var currentVideo = videos[i];
            if (currentVideo === e.target) {
              currentVideo.classList.remove('small');
              currentVideo.classList.add('big');
              currentVideo.addEventListener('mouseover', showControls);
              currentVideo.addEventListener('mouseout', hideControls);
              currentVideo.addEventListener('seeked', seekAll);
              currentVideo.width = that.width;
              currentVideo.height = that.width / ratio;
              currentVideo.style.top = 0;
              currentVideo.style.left = 0;
              currentVideo.style.zIndex = 10000;
            } else {
              currentVideo.classList.remove('big');
              currentVideo.classList.add('small');
              currentVideo.removeEventListener('mouseover', showControls);
              currentVideo.removeEventListener('mouseout', hideControls);
              currentVideo.removeEventListener('seeked', seekAll);
              currentVideo.style.left = (j * videoWidth) + 'px';
              currentVideo.style.top =
                  (that.height - (videoWidth / ratio) - 50) + 'px';
              currentVideo.width = videoWidth;
              currentVideo.height = videoWidth / ratio;
              currentVideo.removeAttribute('controls');
              j++;
            }
          }
        };

        that.alternativeviews.split(/\s/).forEach(function(views) {
          views = JSON.parse(views);
          var content = container.querySelector('content');
          for (var videoSource in views) {
            if (video.currentSrc.indexOf(videoSource) === -1) {
              continue;
            }
            for (var id in views[videoSource]) {
              var alternativeView = views[videoSource][id];
              var viewVideo = document.createElement('video');
              var viewSource = document.createElement('source');
              viewSource.src = alternativeView.src;
              viewVideo.appendChild(viewSource);
              viewVideo.id = id;
              viewVideo.setAttribute('title', alternativeView.title);
              viewVideo.classList.add('hypervideo');
              video.parentNode.insertBefore(viewVideo, content);
              videos.push(viewVideo);
            }
          }
        });

        (function init() {
          for (var i = 0; i < videos.length; i++) {
            var currentVideo = videos[i];

            currentVideo.addEventListener('play', playAll);

            currentVideo.addEventListener('pause', pauseAll);

            currentVideo.addEventListener('click', makeBig);

            currentVideo.addEventListener('transitionend', transitionend);

            if (i === 0) {
              currentVideo.classList.add('big');
              currentVideo.addEventListener('mouseover', showControls);
              currentVideo.addEventListener('mouseout', hideControls);
              currentVideo.addEventListener('seeked', seekAll);
              currentVideo.width = that.width;
              currentVideo.muted = false;
            } else {
              currentVideo.classList.add('small');
              currentVideo.style.left = ((i - 1) * videoWidth) + 'px';
              currentVideo.style.top =
                  (that.height - (videoWidth / ratio) - 50) + 'px';
              currentVideo.width = videoWidth;
              currentVideo.muted = true;
            }
          }
        })();
      }

    }, false);

    // publish timeupdate events
    video.addEventListener('timeupdate', function() {
      // console.log('Received event (video): timeupdate');
      that.currentTime = video.currentTime;
      // console.log('Fired event: hypervideotimeupdate');
      that.fire(
        'hypervideotimeupdate',
        {
          currentTime: that.currentTime
        }
      );
    }, false);

    spinner = showSpinner();
    setTimeout(function() {
      initializeVideo();
      positionDataAnnotations();
      spinner.remove();
    }, 50);
  },
  pause: function() {
    return this.$.hypervideo.pause();
  },
  play: function() {
    return this.$.hypervideo.play();
  }
});<commit_msg>Corrected z-index.<commit_after>'use strict';

/* global queryRegExSelector, queryRegExSelectorAll, getYouTubeHtml5VideoUrl */
Polymer('polymer-hypervideo', {
  publish: {
    currentTime: 0,
    duration: null,
    actorsOffset: {}
  },
  created: function() {
  },
  ready: function() {
    var that = this;
    var spinner;
    var video = that.$.hypervideo;
    var container = that.$.container;

    var onMutation = function(observer, mutations) {
      var nodes = [];
      var chapters = [];
      for (var i = 0, lenI = mutations.length; i < lenI; i++) {
        var mutation = mutations[i];
        if (mutation.addedNodes) {
          for (var j = 0, lenJ = mutation.addedNodes.length; j < lenJ; j++) {
            if (/^polymer-data-/gi.test(mutation.addedNodes[j].nodeName)) {
              nodes.push(mutation.addedNodes[j]);
            }
          }
        }
      }
      if (nodes.length) {
        positionDataAnnotations(nodes);
        updateTimelineAnnotations(nodes);
      }
      that.onMutation(that, onMutation);
    };

    that.onMutation(that, onMutation);

    var CORS_PROXY = document.location.origin + '/cors/';
    document.addEventListener('trackready', function(e) {
      console.log('Received event (document): trackready');
      var data = e.detail;
      var track = document.createElement('track');
      var cuesRead = false;
      track.addEventListener('load', function(e) {
        if (!cuesRead) {
          console.log('Received event (track): load');
          cuesRead = true;
          return readCues(e.target.track.cues, data.kind);
        }
      }, false);
      track.addEventListener('cuechange', function() {
        console.log('Fired event: hypervideocuechange');
        that.fire(
          'hypervideocuechange',
          {
            activeCues: track.track.activeCues
          }
        );
      });
      var trackLoadedInterval = setInterval(function() {
        if (track.readyState >= 2) {
          clearInterval(trackLoadedInterval);
          if (!cuesRead) {
            console.log('Received event (track): readyState');
            cuesRead = true;
            return readCues(track.track.cues, data.kind);
          }
        }
      }, 100);
      track.src = data.src;
      track.default = true;
      track.kind = data.kind;
      if (track.kind === 'subtitles' || track.kind === 'captions') {
        track.srclang = 'en';
        track.track.mode = 'showing';
      } else if (track.kind === 'chapters') {
        var canvas = document.createElement('canvas');
        canvas.width = video.width;
        canvas.height = video.height;
        var ctx = canvas.getContext('2d');
        that.ctx = ctx;
        that.canvas = canvas;
      }
      video.appendChild(track);
    }, false);

    document.addEventListener('webcomponentstocready', function() {
      console.log('Received event (document): webcomponentstocready');
      // get all child <polymer-*> child nodes
      var webComponents = queryRegExSelectorAll(that, /^polymer-/gi);
      console.log('Fired event: webcomponentstoc');
      that.fire(
        'webcomponentstoc',
        {
          webComponentsToC: webComponents
        }
      );
    }, false);

    var updateTimelineAnnotations = function(opt_nodes) {
      // get all child <polymer-data-*> child nodes
      var dataAnnotations =
          opt_nodes || queryRegExSelectorAll(that, /^polymer-data-/gi);
      var annotations = [];
      dataAnnotations.forEach(function(annotation) {
        var type;
        if (/actor/gi.test(annotation.nodeName)) {
          type = 'actors';
        } else if (/overlay/gi.test(annotation.nodeName)) {
          type = 'overlays';
        } else {
          type = 'annotations';
        }
        annotations.push({
          start: parseInt(annotation.getAttribute('start'), 10),
          end: parseInt(annotation.getAttribute('end'), 10),
          type: type
        });
      });
      console.log('Fired event: dataannotations');
      that.fire(
        'dataannotations',
        {
          dataAnnotations: annotations
        }
      );

    };

    document.addEventListener('timelineready', function() {
      console.log('Received event (document): timelineready');
      updateTimelineAnnotations();
    }, false);

    // listen for events coming from the timeline component
    document.addEventListener('currenttimeupdate', function(e) {
      // console.log('Received event (document): currenttimeupdate');
      var data = e.detail;
      video.currentTime = data.currentTime;
      video.play();
    }, false);

    document.addEventListener('requeststillframes', function(e) {
      console.log('Received event (document): requeststillframes');
      spinner = showSpinner();
      var cues = e.detail.cues;
      if (!cues) {
        return;
      }
      var functions = [];
      cues.forEach(function(cue) {
        var start = cue.start;
        if (start > video.duration) {
          return;
        }
        functions.push({
          cue: cue,
          func: function() {
            video.currentTime = start;
          }
        });
      });
      var getNextStillFrame = function() {
        console.log('Received event (video): seeked');
        that.ctx.drawImage(video, 0, 0, video.clientWidth,
            video.clientHeight);
        var img = document.createElement('img');
        img.setAttribute('class', 'hypervideo');
        var url = that.canvas.toDataURL();
        img.src = url;
        var cue = functions[processedStillFrames].cue;
        console.log('Fired event: receivestillframe');
        that.fire(
          'receivestillframe',
          {
            img: img,
            text: cue.text,
            start: cue.start,
            end: cue.end
          }
        );
        processedStillFrames++;
        if (functions[processedStillFrames]) {
          return functions[processedStillFrames].func();
        } else {
          video.removeEventListener('seeked', getNextStillFrame);
          video.currentTime = 0;
          that.fire('allstillframesreceived');
          spinner.remove();
        }
      };
      var processedStillFrames = 0;
      video.addEventListener('seeked', getNextStillFrame);
      functions[processedStillFrames].func();
    });

    var initializeVideo = function() {
      // either add sources for regular video
      if (that.src) {
        that.src.split(/\s/g).forEach(function(src) {
          var source = document.createElement('source');
          source.src = src;
          video.appendChild(source);
        });
      // or add sources for YouTube video
      } else if (that.youtubevideoid) {
        getYouTubeHtml5VideoUrl(that.youtubevideoid,
            function(err, videoSources) {
          if (err) {
            return;
          }
          for (var videoSource in videoSources) {
            videoSource = videoSources[videoSource];
            var source = document.createElement('source');
            source.src = CORS_PROXY +
                encodeURIComponent(videoSource.original_url);
            source.type = videoSource.type.replace(/\+/g, ' ')
                .replace(/"/g, '\"');
            video.appendChild(source);
          }
        });
      }
      // determine video dimensions
      if (that.width) {
        that.width = parseInt(that.width, 10);
      } else {
        that.width = 400;
      }
      video.width = that.width;
      if (that.height) {
        that.height = parseInt(that.height, 10);
      } else {
        that.height = 225;
      }
      video.height = that.height;
      // add poster
      if (that.poster) {
        video.poster = that.poster;
      }
      // mute video
      if (that.muted !== null && that.muted !== 'false') {
        video.muted = true;
      }
    };

    var showSpinner = function() {
      // show spinner while the hypervideo gets prepared
      var splashDiv = document.createElement('div');
      splashDiv.classList.add('spinner');
      var splashSpinner = document.createElement('div');
      splashSpinner.classList.add('progress');
      splashDiv.appendChild(splashSpinner);
      splashDiv.style.width = video.width + 'px';
      splashDiv.style.height = video.height + 'px';
      splashDiv.style.position = 'absolute';
      splashDiv.style.top = video.offsetTop + 'px';
      splashDiv.style.left = video.offsetLeft + 'px';
      splashSpinner.style.position = 'relative';
      splashSpinner.style.top = (video.offsetHeight / 2 - 60 / 2) + 'px';
      splashSpinner.style.left = (video.offsetWidth / 2 - 60 / 2) + 'px';
      var loadingDiv = document.createElement('div');
      loadingDiv.textContent = '*';
      splashSpinner.appendChild(loadingDiv);
      container.appendChild(splashDiv);
      return splashDiv;
    };

    var positionDataAnnotations = function(opt_nodes) {
      // positions data annotations on top of the video
      var polymerData =
          opt_nodes || queryRegExSelectorAll(that, /^polymer-data-/gi);
      polymerData.forEach(function(node) {
        node.style.position = 'absolute';
        node.style.top = (video.offsetTop + 0.66 * video.offsetHeight) +
            'px';
        node.style.left = (video.offsetLeft + (0.05 * that.width)) + 'px';
        node.style.width = (0.9 * that.width) + 'px';
        node.style.display = 'none';
      });
    };

    var readCues = function(cues, kind) {
      if (!cues) {
        return;
      }
      var cueData = [];
      for (var i = 0, lenI = cues.length; i < lenI; i++) {
        var cue = cues.item ? cues.item(i) : cues[i];
        cueData.push({
          start: parseInt(cue.startTime, 10),
          end: parseInt(cue.endTime, 10),
          text: cue.text,
          id: cue.id,
          type: kind
        });
      }
      console.log('Fired event: cuesread');
      that.fire(
        'cuesread',
        {
          cueData: cueData,
          kind: kind
        }
      );
    };

    video.addEventListener('loadedmetadata', function() {
      console.log('Received event (video): loadedmetadata');
      that.duration = video.duration;
      // adjust the timeline dimensions according to the video duration
      var polymerTimelines = that.querySelectorAll('polymer-timeline');
      for (var i = 0, lenI = polymerTimelines.length; i < lenI; i++) {
        polymerTimelines[i].style.left = (video.offsetLeft +
            (0.05 * that.width)) + 'px';
      }
      var polymerData = queryRegExSelector(that, /^polymer-data-/gi);
      console.log('Fired event: hypervideoloadedmetadata');
      that.fire(
        'hypervideoloadedmetadata',
        {
          duration: that.duration,
          height: that.height,
          width: that.width,
          actorsOffset: {
            left: polymerData ? polymerData.style.left.replace('px', '') : null,
            top: polymerData ? polymerData.style.top.replace('px', '') : null
          }
        }
      );

      // alternative views
      if (that.alternativeviews) {
        var videos = [video];
        var videoWidth = Math.floor(that.width / 5);
        var ratio = that.width / that.height;

        function showControls(e) {
          return e.target.setAttribute('controls', true);
        }

        var hideControls = function hideControls(e) {
          return e.target.removeAttribute('controls');
        };

        var playAll = function playAll() {
          for (var i = 0; i < videos.length; i++) {
            videos[i].play();
          }
        };

        var pauseAll = function pauseAll() {
          for (var i = 0; i < videos.length; i++) {
            videos[i].pause();
          }
        };

        var seekAll = function seekAll(e) {
          for (var i = 0; i < videos.length; i++) {
            var currentVideo = videos[i];
            if (currentVideo === e.target) {
              continue;
            }
            currentVideo.currentTime = e.target.currentTime;
          }
        };

        var transitionend = function transitioned(e) {
          for (var i = 0; i < videos.length; i++) {
            var currentVideo = videos[i];
            if (currentVideo.classList.contains('small')) {
              currentVideo.style.zIndex = 10000;
            } else {
              currentVideo.style.zIndex = 'auto';
            }
          }
        }

        var makeBig = function makeBig(e) {
          for (var i = 0, j = 0; i < videos.length; i++) {
            var currentVideo = videos[i];
            if (currentVideo === e.target) {
              currentVideo.classList.remove('small');
              currentVideo.classList.add('big');
              currentVideo.addEventListener('mouseover', showControls);
              currentVideo.addEventListener('mouseout', hideControls);
              currentVideo.addEventListener('seeked', seekAll);
              currentVideo.width = that.width;
              currentVideo.height = that.width / ratio;
              currentVideo.style.top = 0;
              currentVideo.style.left = 0;
              currentVideo.style.zIndex = 10000;
            } else {
              currentVideo.classList.remove('big');
              currentVideo.classList.add('small');
              currentVideo.removeEventListener('mouseover', showControls);
              currentVideo.removeEventListener('mouseout', hideControls);
              currentVideo.removeEventListener('seeked', seekAll);
              currentVideo.style.left = (j * videoWidth) + 'px';
              currentVideo.style.top =
                  (that.height - (videoWidth / ratio) - 50) + 'px';
              currentVideo.width = videoWidth;
              currentVideo.height = videoWidth / ratio;
              currentVideo.removeAttribute('controls');
              j++;
            }
          }
        };

        that.alternativeviews.split(/\s/).forEach(function(views) {
          views = JSON.parse(views);
          var content = container.querySelector('content');
          for (var videoSource in views) {
            if (video.currentSrc.indexOf(videoSource) === -1) {
              continue;
            }
            for (var id in views[videoSource]) {
              var alternativeView = views[videoSource][id];
              var viewVideo = document.createElement('video');
              var viewSource = document.createElement('source');
              viewSource.src = alternativeView.src;
              viewVideo.appendChild(viewSource);
              viewVideo.id = id;
              viewVideo.setAttribute('title', alternativeView.title);
              viewVideo.classList.add('hypervideo');
              video.parentNode.insertBefore(viewVideo, content);
              videos.push(viewVideo);
            }
          }
        });

        (function init() {
          for (var i = 0; i < videos.length; i++) {
            var currentVideo = videos[i];

            currentVideo.addEventListener('play', playAll);

            currentVideo.addEventListener('pause', pauseAll);

            currentVideo.addEventListener('click', makeBig);

            currentVideo.addEventListener('transitionend', transitionend);

            if (i === 0) {
              currentVideo.classList.add('big');
              currentVideo.addEventListener('mouseover', showControls);
              currentVideo.addEventListener('mouseout', hideControls);
              currentVideo.addEventListener('seeked', seekAll);
              currentVideo.width = that.width;
              currentVideo.muted = false;
            } else {
              currentVideo.classList.add('small');
              currentVideo.style.left = ((i - 1) * videoWidth) + 'px';
              currentVideo.style.top =
                  (that.height - (videoWidth / ratio) - 50) + 'px';
              currentVideo.width = videoWidth;
              currentVideo.muted = true;
            }
          }
        })();
      }

    }, false);

    // publish timeupdate events
    video.addEventListener('timeupdate', function() {
      // console.log('Received event (video): timeupdate');
      that.currentTime = video.currentTime;
      // console.log('Fired event: hypervideotimeupdate');
      that.fire(
        'hypervideotimeupdate',
        {
          currentTime: that.currentTime
        }
      );
    }, false);

    spinner = showSpinner();
    setTimeout(function() {
      initializeVideo();
      positionDataAnnotations();
      spinner.remove();
    }, 50);
  },
  pause: function() {
    return this.$.hypervideo.pause();
  },
  play: function() {
    return this.$.hypervideo.play();
  }
});<|endoftext|>


<commit_before>// Protractor configuration file,
// see link for more information https://github.com/angular/protractor/blob/master/lib/config.ts
const {SpecReporter} = require('jasmine-spec-reporter');

const config = {};
const capabilities = {
    browserName: 'chrome',
    chromeOptions: {
        // Use headless Chrome https://github.com/angular/protractor/blob/master/docs/browser-setup.md#using-headless-chrome
        args: ['--headless', '--js-flags=--expose-gc'],
        perfLoggingPrefs: {
            traceCategories: 'v8,blink.console,disabled-by-default-devtools.timeline,devtools.timeline'
        }
    },
    loggingPrefs: {
        performance: 'ALL',
        browser: 'ALL'
    }
};

// On Travis we use Saucelabs browsers.
if (process.env.TRAVIS) {
    capabilities.build = `TRAVIS #${process.env.TRAVIS_BUILD_NUMBER} (${process.env.TRAVIS_BUILD_ID})`;
    capabilities['tunnel-identifier'] = process.env.TRAVIS_JOB_NUMBER;
    capabilities.name = 'E2E - Angular Lab';

    config.sauceUser = process.env.SAUCE_USERNAME;
    config.sauceKey = process.env.SAUCE_ACCESS_KEY;
}

Object.assign(config, {
    capabilities,
    allScriptsTimeout: 120000,
    specs: [
        './e2e/**/*.e2e-spec.ts'
    ],
    // https://github.com/angular/protractor/blob/master/docs/server-setup.md#connecting-directly-to-browser-drivers
    directConnect: !process.env.TRAVIS,
    baseUrl: 'http://localhost:4224/',
    framework: 'jasmine',
    jasmineNodeOpts: {
        showColors: true,
        showTiming: true,
        defaultTimeoutInterval: 120000,
        print: () => {}
    },
    // Option for Angular to test against Angular 2+ applications on the page.
    // Protractor will wait for the app to be stable before each action, and search within all apps when finding elements.
    // rootElement: 'rj-lab',
    // TODO: Use above when https://github.com/angular/protractor/issues/4336 is fixed
    useAllAngular2AppRoots: true,
    // Turn off control flow (https://github.com/angular/protractor/tree/master/exampleTypescript/asyncAwait)
    SELENIUM_PROMISE_MANAGER: false,
    onPrepare: () => {
        // Add jasmine spec reporter
        jasmine.getEnv()
            .addReporter(new SpecReporter({spec: {displayStacktrace: true}}));
        // Include jasmine expect
        require('jasmine-expect');
        // Transpile all TS to JS
        require('ts-node')
            .register({
                project: 'e2e/tsconfig.e2e.json'
            });
    }
});

module.exports = {
    config
};
<commit_msg>chore: disable gpu when running e2e tests<commit_after>// Protractor configuration file,
// see link for more information https://github.com/angular/protractor/blob/master/lib/config.ts
const {SpecReporter} = require('jasmine-spec-reporter');

const config = {};
const capabilities = {
    browserName: 'chrome',
    chromeOptions: {
        // Use headless Chrome https://github.com/angular/protractor/blob/master/docs/browser-setup.md#using-headless-chrome
        args: [
            '--headless',
            '--disable-gpu',
            '--js-flags=--expose-gc'
        ],
        perfLoggingPrefs: {
            traceCategories: 'v8,blink.console,disabled-by-default-devtools.timeline,devtools.timeline'
        }
    },
    loggingPrefs: {
        performance: 'ALL',
        browser: 'ALL'
    }
};

// On Travis we use Saucelabs browsers.
if (process.env.TRAVIS) {
    capabilities.build = `TRAVIS #${process.env.TRAVIS_BUILD_NUMBER} (${process.env.TRAVIS_BUILD_ID})`;
    capabilities['tunnel-identifier'] = process.env.TRAVIS_JOB_NUMBER;
    capabilities.name = 'Angular Lab (E2E)';

    config.sauceUser = process.env.SAUCE_USERNAME;
    config.sauceKey = process.env.SAUCE_ACCESS_KEY;
}

Object.assign(config, {
    capabilities,
    allScriptsTimeout: 120000,
    specs: [
        './e2e/**/*.e2e-spec.ts'
    ],
    // https://github.com/angular/protractor/blob/master/docs/server-setup.md#connecting-directly-to-browser-drivers
    directConnect: !process.env.TRAVIS,
    baseUrl: 'http://localhost:4224/',
    framework: 'jasmine',
    jasmineNodeOpts: {
        showColors: true,
        showTiming: true,
        defaultTimeoutInterval: 120000,
        print: () => {}
    },
    // Option for Angular to test against Angular 2+ applications on the page.
    // Protractor will wait for the app to be stable before each action, and search within all apps when finding elements.
    // rootElement: 'rj-lab',
    // TODO: Use above when https://github.com/angular/protractor/issues/4336 is fixed
    useAllAngular2AppRoots: true,
    // Turn off control flow (https://github.com/angular/protractor/tree/master/exampleTypescript/asyncAwait)
    SELENIUM_PROMISE_MANAGER: false,
    onPrepare: () => {
        // Add jasmine spec reporter
        jasmine.getEnv()
            .addReporter(new SpecReporter({spec: {displayStacktrace: true}}));
        // Include jasmine expect
        require('jasmine-expect');
        // Transpile all TS to JS
        require('ts-node')
            .register({
                project: 'e2e/tsconfig.e2e.json'
            });
    }
});

module.exports = {
    config
};
<|endoftext|>


<commit_before>'use strict';

/* global queryRegExSelector, queryRegExSelectorAll, getYouTubeHtml5VideoUrl */
Polymer('polymer-hypervideo', {
  publish: {
    currentTime: 0,
    duration: null,
    actorsOffset: {}
  },
  created: function() {
  },
  ready: function() {
    var that = this;
    var spinner;
    var video = that.$.hypervideo;
    var container = that.$.container;

    var onMutation = function(observer, mutations) {
      var nodes = [];
      var chapters = [];
      for (var i = 0, lenI = mutations.length; i < lenI; i++) {
        var mutation = mutations[i];
        if (mutation.addedNodes) {
          for (var j = 0, lenJ = mutation.addedNodes.length; j < lenJ; j++) {
            if (/^polymer-data-/gi.test(mutation.addedNodes[j].nodeName)) {
              nodes.push(mutation.addedNodes[j]);
            }
          }
        }
      }
      if (nodes.length) {
        positionDataAnnotations(nodes);
        updateTimelineAnnotations(nodes);
      }
      that.onMutation(that, onMutation);
    };

    that.onMutation(that, onMutation);

    var CORS_PROXY = document.location.origin + '/cors/';
    document.addEventListener('trackready', function(e) {
      console.log('Received event (document): trackready');
      var data = e.detail;
      var track = document.createElement('track');
      var cuesRead = false;
      track.addEventListener('load', function(e) {
        if (!cuesRead) {
          console.log('Received event (track): load');
          cuesRead = true;
          return readCues(e.target.track.cues, data.kind);
        }
      }, false);
      track.addEventListener('cuechange', function() {
        console.log('Fired event: hypervideocuechange');
        that.fire(
          'hypervideocuechange',
          {
            activeCues: track.track.activeCues
          }
        );
      });
      var trackLoadedInterval = setInterval(function() {
        if (track.readyState >= 2) {
          clearInterval(trackLoadedInterval);
          if (!cuesRead) {
            console.log('Received event (track): readyState');
            cuesRead = true;
            return readCues(track.track.cues, data.kind);
          }
        }
      }, 100);
      track.src = data.src;
      track.default = true;
      track.kind = data.kind;
      if (track.kind === 'subtitles' || track.kind === 'captions') {
        track.srclang = 'en';
        track.track.mode = 'showing';
      } else if (track.kind === 'chapters') {
        var canvas = document.createElement('canvas');
        canvas.width = video.width;
        canvas.height = video.height;
        var ctx = canvas.getContext('2d');
        that.ctx = ctx;
        that.canvas = canvas;
      }
      video.appendChild(track);
    }, false);

    document.addEventListener('webcomponentstocready', function() {
      console.log('Received event (document): webcomponentstocready');
      // get all child <polymer-*> child nodes
      var webComponents = queryRegExSelectorAll(that, /^polymer-/gi);
      console.log('Fired event: webcomponentstoc');
      that.fire(
        'webcomponentstoc',
        {
          webComponentsToC: webComponents
        }
      );
    }, false);

    var updateTimelineAnnotations = function(opt_nodes) {
      // get all child <polymer-data-*> child nodes
      var dataAnnotations =
          opt_nodes || queryRegExSelectorAll(that, /^polymer-data-/gi);
      var annotations = [];
      dataAnnotations.forEach(function(annotation) {
        var type;
        if (/actor/gi.test(annotation.nodeName)) {
          type = 'actors';
        } else if (/overlay/gi.test(annotation.nodeName)) {
          type = 'overlays';
        } else {
          type = 'annotations';
        }
        annotations.push({
          start: parseInt(annotation.getAttribute('start'), 10),
          end: parseInt(annotation.getAttribute('end'), 10),
          type: type
        });
      });
      console.log('Fired event: dataannotations');
      that.fire(
        'dataannotations',
        {
          dataAnnotations: annotations
        }
      );

    };

    document.addEventListener('timelineready', function() {
      console.log('Received event (document): timelineready');
      updateTimelineAnnotations();
    }, false);

    // listen for events coming from the timeline component
    document.addEventListener('currenttimeupdate', function(e) {
      // console.log('Received event (document): currenttimeupdate');
      var data = e.detail;
      video.currentTime = data.currentTime;
      video.play();
    }, false);

    document.addEventListener('requeststillframes', function(e) {
      console.log('Received event (document): requeststillframes');
      spinner = showSpinner();
      var cues = e.detail.cues;
      if (!cues) {
        return;
      }
      var functions = [];
      cues.forEach(function(cue) {
        var start = cue.start;
        if (start > video.duration) {
          return;
        }
        functions.push({
          cue: cue,
          func: function() {
            video.currentTime = start;
          }
        });
      });
      var getNextStillFrame = function() {
        console.log('Received event (video): seeked');
        that.ctx.drawImage(video, 0, 0, video.clientWidth,
            video.clientHeight);
        var img = document.createElement('img');
        img.setAttribute('class', 'hypervideo');
        var url = that.canvas.toDataURL();
        img.src = url;
        var cue = functions[processedStillFrames].cue;
        console.log('Fired event: receivestillframe');
        that.fire(
          'receivestillframe',
          {
            img: img,
            text: cue.text,
            start: cue.start,
            end: cue.end
          }
        );
        processedStillFrames++;
        if (functions[processedStillFrames]) {
          return functions[processedStillFrames].func();
        } else {
          video.removeEventListener('seeked', getNextStillFrame);
          video.currentTime = 0;
          that.fire('allstillframesreceived');
          spinner.remove();
        }
      };
      var processedStillFrames = 0;
      video.addEventListener('seeked', getNextStillFrame);
      functions[processedStillFrames].func();
    });

    var initializeVideo = function() {
      // either add sources for regular video
      if (that.src) {
        that.src.split(/\s/g).forEach(function(src) {
          var source = document.createElement('source');
          source.src = src;
          video.appendChild(source);
        });
      // or add sources for YouTube video
      } else if (that.youtubevideoid) {
        getYouTubeHtml5VideoUrl(that.youtubevideoid,
            function(err, videoSources) {
          if (err) {
            return;
          }
          for (var videoSource in videoSources) {
            videoSource = videoSources[videoSource];
            var source = document.createElement('source');
            source.src = CORS_PROXY +
                encodeURIComponent(videoSource.original_url);
            source.type = videoSource.type.replace(/\+/g, ' ')
                .replace(/"/g, '\"');
            video.appendChild(source);
          }
        });
      }
      // determine video dimensions
      if (that.width) {
        that.width = parseInt(that.width, 10);
      } else {
        that.width = 400;
      }
      video.width = that.width;
      if (that.height) {
        that.height = parseInt(that.height, 10);
      } else {
        that.height = 225;
      }
      video.height = that.height;
      // add poster
      if (that.poster) {
        video.poster = that.poster;
      }
      // mute video
      if (that.muted !== null && that.muted !== 'false') {
        video.muted = true;
      }
    };

    var showSpinner = function() {
      // show spinner while the hypervideo gets prepared
      var splashDiv = document.createElement('div');
      splashDiv.classList.add('spinner');
      var splashSpinner = document.createElement('div');
      splashSpinner.classList.add('progress');
      splashDiv.appendChild(splashSpinner);
      splashDiv.style.width = video.width + 'px';
      splashDiv.style.height = video.height + 'px';
      splashDiv.style.position = 'absolute';
      splashDiv.style.top = video.offsetTop + 'px';
      splashDiv.style.left = video.offsetLeft + 'px';
      splashSpinner.style.position = 'relative';
      splashSpinner.style.top = (video.offsetHeight / 2 - 60 / 2) + 'px';
      splashSpinner.style.left = (video.offsetWidth / 2 - 60 / 2) + 'px';
      var loadingDiv = document.createElement('div');
      loadingDiv.textContent = '*';
      splashSpinner.appendChild(loadingDiv);
      container.appendChild(splashDiv);
      return splashDiv;
    };

    var positionDataAnnotations = function(opt_nodes) {
      // positions data annotations on top of the video
      var polymerData =
          opt_nodes || queryRegExSelectorAll(that, /^polymer-data-/gi);
      polymerData.forEach(function(node) {
        node.style.position = 'absolute';
        node.style.top = (video.offsetTop + 0.66 * video.offsetHeight) +
            'px';
        node.style.left = (video.offsetLeft + (0.05 * that.width)) + 'px';
        node.style.width = (0.9 * that.width) + 'px';
        node.style.display = 'none';
      });
    };

    var readCues = function(cues, kind) {
      if (!cues) {
        return;
      }
      var cueData = [];
      for (var i = 0, lenI = cues.length; i < lenI; i++) {
        var cue = cues.item ? cues.item(i) : cues[i];
        cueData.push({
          start: parseInt(cue.startTime, 10),
          end: parseInt(cue.endTime, 10),
          text: cue.text,
          id: cue.id,
          type: kind
        });
      }
      console.log('Fired event: cuesread');
      that.fire(
        'cuesread',
        {
          cueData: cueData,
          kind: kind
        }
      );
    };

    video.addEventListener('loadedmetadata', function() {
      console.log('Received event (video): loadedmetadata');
      that.duration = video.duration;
      // adjust the timeline dimensions according to the video duration
      var polymerTimelines = that.querySelectorAll('polymer-timeline');
      for (var i = 0, lenI = polymerTimelines.length; i < lenI; i++) {
        polymerTimelines[i].style.left = (video.offsetLeft +
            (0.05 * that.width)) + 'px';
      }
      var polymerData = queryRegExSelector(that, /^polymer-data-/gi);
      console.log('Fired event: hypervideoloadedmetadata');
      that.fire(
        'hypervideoloadedmetadata',
        {
          duration: that.duration,
          height: that.height,
          width: that.width,
          actorsOffset: {
            left: polymerData ? polymerData.style.left.replace('px', '') : null,
            top: polymerData ? polymerData.style.top.replace('px', '') : null
          }
        }
      );

      // alternative views
      if (that.alternativeviews) {
        var videos = [video];
        var videoWidth = Math.floor(that.width / 5);

        function showControls(e) {
          return e.target.setAttribute('controls', true);
        }

        var hideControls = function hideControls(e) {
          return e.target.removeAttribute('controls');
        };

        var playAll = function playAll() {
          for (var i = 0; i < videos.length; i++) {
            videos[i].play();
          }
        };

        var pauseAll = function pauseAll() {
          for (var i = 0; i < videos.length; i++) {
            videos[i].pause();
          }
        };

        var seekAll = function seekAll(e) {
          for (var i = 0; i < videos.length; i++) {
            var currentVideo = videos[i];
            if (currentVideo === e.target) {
              continue;
            }
            currentVideo.currentTime = e.target.currentTime;
          }
        };

        var makeBig = function makeBig(e) {
          for (var i = 0, j = 0; i < videos.length; i++) {
            var currentVideo = videos[i];
            if (currentVideo === e.target) {
              currentVideo.classList.remove('small');
              currentVideo.classList.add('big');
              currentVideo.addEventListener('mouseover', showControls);
              currentVideo.addEventListener('mouseout', hideControls);
              currentVideo.addEventListener('seeked', seekAll);
              currentVideo.style.left = 0;
            } else {
              currentVideo.classList.remove('big');
              currentVideo.classList.add('small');
              currentVideo.removeEventListener('mouseover', showControls);
              currentVideo.removeEventListener('mouseout', hideControls);
              currentVideo.removeEventListener('seeked', seekAll);
              currentVideo.style.left = (j * videoWidth) + 'px';
              currentVideo.removeAttribute('controls');
              j++;
            }
          }
        };

        that.alternativeviews.split(/\s/).forEach(function(views) {
          views = JSON.parse(views);
          var content = container.querySelector('content');
          for (var videoSource in views) {
            if (video.currentSrc.indexOf(videoSource) === -1) {
              continue;
            }
            for (var id in views[videoSource]) {
              var alternativeView = views[videoSource][id];
              console.log(alternativeView);
              var viewVideo = document.createElement('video');
              var viewSource = document.createElement('source');
              viewSource.src = alternativeView.src;
              viewVideo.appendChild(viewSource);
              viewVideo.id = id;
              viewVideo.setAttribute('title', alternativeView.title);
              video.parentNode.insertBefore(viewVideo, content);
              videos.push(viewVideo);
            }
          }
        });

        (function init() {
          for (var i = 0; i < videos.length; i++) {
            var currentVideo = videos[i];

            currentVideo.addEventListener('play', playAll);

            currentVideo.addEventListener('pause', pauseAll);

            currentVideo.addEventListener('click', makeBig);

            var ratio = that.width / that.height;
            if (i === 0) {
              currentVideo.classList.add('big');
              currentVideo.addEventListener('mouseover', showControls);
              currentVideo.addEventListener('mouseout', hideControls);
              currentVideo.addEventListener('seeked', seekAll);
              currentVideo.width = that.width;
              currentVideo.muted = false;
            } else {
              currentVideo.classList.add('small');
              currentVideo.style.left = ((i - 1) * videoWidth) + 'px';
              currentVideo.style.top =
              (that.height - (videoWidth / ratio) - 50) + 'px';
              currentVideo.width = videoWidth;
              currentVideo.muted = true;
            }
          }
        })();
      }

    }, false);

    // publish timeupdate events
    video.addEventListener('timeupdate', function() {
      // console.log('Received event (video): timeupdate');
      that.currentTime = video.currentTime;
      // console.log('Fired event: hypervideotimeupdate');
      that.fire(
        'hypervideotimeupdate',
        {
          currentTime: that.currentTime
        }
      );
    }, false);

    spinner = showSpinner();
    setTimeout(function() {
      initializeVideo();
      positionDataAnnotations();
      spinner.remove();
    }, 50);
  },
  pause: function() {
    return this.$.hypervideo.pause();
  },
  play: function() {
    return this.$.hypervideo.play();
  }
});<commit_msg>Added width changes to makeBig function.<commit_after>'use strict';

/* global queryRegExSelector, queryRegExSelectorAll, getYouTubeHtml5VideoUrl */
Polymer('polymer-hypervideo', {
  publish: {
    currentTime: 0,
    duration: null,
    actorsOffset: {}
  },
  created: function() {
  },
  ready: function() {
    var that = this;
    var spinner;
    var video = that.$.hypervideo;
    var container = that.$.container;

    var onMutation = function(observer, mutations) {
      var nodes = [];
      var chapters = [];
      for (var i = 0, lenI = mutations.length; i < lenI; i++) {
        var mutation = mutations[i];
        if (mutation.addedNodes) {
          for (var j = 0, lenJ = mutation.addedNodes.length; j < lenJ; j++) {
            if (/^polymer-data-/gi.test(mutation.addedNodes[j].nodeName)) {
              nodes.push(mutation.addedNodes[j]);
            }
          }
        }
      }
      if (nodes.length) {
        positionDataAnnotations(nodes);
        updateTimelineAnnotations(nodes);
      }
      that.onMutation(that, onMutation);
    };

    that.onMutation(that, onMutation);

    var CORS_PROXY = document.location.origin + '/cors/';
    document.addEventListener('trackready', function(e) {
      console.log('Received event (document): trackready');
      var data = e.detail;
      var track = document.createElement('track');
      var cuesRead = false;
      track.addEventListener('load', function(e) {
        if (!cuesRead) {
          console.log('Received event (track): load');
          cuesRead = true;
          return readCues(e.target.track.cues, data.kind);
        }
      }, false);
      track.addEventListener('cuechange', function() {
        console.log('Fired event: hypervideocuechange');
        that.fire(
          'hypervideocuechange',
          {
            activeCues: track.track.activeCues
          }
        );
      });
      var trackLoadedInterval = setInterval(function() {
        if (track.readyState >= 2) {
          clearInterval(trackLoadedInterval);
          if (!cuesRead) {
            console.log('Received event (track): readyState');
            cuesRead = true;
            return readCues(track.track.cues, data.kind);
          }
        }
      }, 100);
      track.src = data.src;
      track.default = true;
      track.kind = data.kind;
      if (track.kind === 'subtitles' || track.kind === 'captions') {
        track.srclang = 'en';
        track.track.mode = 'showing';
      } else if (track.kind === 'chapters') {
        var canvas = document.createElement('canvas');
        canvas.width = video.width;
        canvas.height = video.height;
        var ctx = canvas.getContext('2d');
        that.ctx = ctx;
        that.canvas = canvas;
      }
      video.appendChild(track);
    }, false);

    document.addEventListener('webcomponentstocready', function() {
      console.log('Received event (document): webcomponentstocready');
      // get all child <polymer-*> child nodes
      var webComponents = queryRegExSelectorAll(that, /^polymer-/gi);
      console.log('Fired event: webcomponentstoc');
      that.fire(
        'webcomponentstoc',
        {
          webComponentsToC: webComponents
        }
      );
    }, false);

    var updateTimelineAnnotations = function(opt_nodes) {
      // get all child <polymer-data-*> child nodes
      var dataAnnotations =
          opt_nodes || queryRegExSelectorAll(that, /^polymer-data-/gi);
      var annotations = [];
      dataAnnotations.forEach(function(annotation) {
        var type;
        if (/actor/gi.test(annotation.nodeName)) {
          type = 'actors';
        } else if (/overlay/gi.test(annotation.nodeName)) {
          type = 'overlays';
        } else {
          type = 'annotations';
        }
        annotations.push({
          start: parseInt(annotation.getAttribute('start'), 10),
          end: parseInt(annotation.getAttribute('end'), 10),
          type: type
        });
      });
      console.log('Fired event: dataannotations');
      that.fire(
        'dataannotations',
        {
          dataAnnotations: annotations
        }
      );

    };

    document.addEventListener('timelineready', function() {
      console.log('Received event (document): timelineready');
      updateTimelineAnnotations();
    }, false);

    // listen for events coming from the timeline component
    document.addEventListener('currenttimeupdate', function(e) {
      // console.log('Received event (document): currenttimeupdate');
      var data = e.detail;
      video.currentTime = data.currentTime;
      video.play();
    }, false);

    document.addEventListener('requeststillframes', function(e) {
      console.log('Received event (document): requeststillframes');
      spinner = showSpinner();
      var cues = e.detail.cues;
      if (!cues) {
        return;
      }
      var functions = [];
      cues.forEach(function(cue) {
        var start = cue.start;
        if (start > video.duration) {
          return;
        }
        functions.push({
          cue: cue,
          func: function() {
            video.currentTime = start;
          }
        });
      });
      var getNextStillFrame = function() {
        console.log('Received event (video): seeked');
        that.ctx.drawImage(video, 0, 0, video.clientWidth,
            video.clientHeight);
        var img = document.createElement('img');
        img.setAttribute('class', 'hypervideo');
        var url = that.canvas.toDataURL();
        img.src = url;
        var cue = functions[processedStillFrames].cue;
        console.log('Fired event: receivestillframe');
        that.fire(
          'receivestillframe',
          {
            img: img,
            text: cue.text,
            start: cue.start,
            end: cue.end
          }
        );
        processedStillFrames++;
        if (functions[processedStillFrames]) {
          return functions[processedStillFrames].func();
        } else {
          video.removeEventListener('seeked', getNextStillFrame);
          video.currentTime = 0;
          that.fire('allstillframesreceived');
          spinner.remove();
        }
      };
      var processedStillFrames = 0;
      video.addEventListener('seeked', getNextStillFrame);
      functions[processedStillFrames].func();
    });

    var initializeVideo = function() {
      // either add sources for regular video
      if (that.src) {
        that.src.split(/\s/g).forEach(function(src) {
          var source = document.createElement('source');
          source.src = src;
          video.appendChild(source);
        });
      // or add sources for YouTube video
      } else if (that.youtubevideoid) {
        getYouTubeHtml5VideoUrl(that.youtubevideoid,
            function(err, videoSources) {
          if (err) {
            return;
          }
          for (var videoSource in videoSources) {
            videoSource = videoSources[videoSource];
            var source = document.createElement('source');
            source.src = CORS_PROXY +
                encodeURIComponent(videoSource.original_url);
            source.type = videoSource.type.replace(/\+/g, ' ')
                .replace(/"/g, '\"');
            video.appendChild(source);
          }
        });
      }
      // determine video dimensions
      if (that.width) {
        that.width = parseInt(that.width, 10);
      } else {
        that.width = 400;
      }
      video.width = that.width;
      if (that.height) {
        that.height = parseInt(that.height, 10);
      } else {
        that.height = 225;
      }
      video.height = that.height;
      // add poster
      if (that.poster) {
        video.poster = that.poster;
      }
      // mute video
      if (that.muted !== null && that.muted !== 'false') {
        video.muted = true;
      }
    };

    var showSpinner = function() {
      // show spinner while the hypervideo gets prepared
      var splashDiv = document.createElement('div');
      splashDiv.classList.add('spinner');
      var splashSpinner = document.createElement('div');
      splashSpinner.classList.add('progress');
      splashDiv.appendChild(splashSpinner);
      splashDiv.style.width = video.width + 'px';
      splashDiv.style.height = video.height + 'px';
      splashDiv.style.position = 'absolute';
      splashDiv.style.top = video.offsetTop + 'px';
      splashDiv.style.left = video.offsetLeft + 'px';
      splashSpinner.style.position = 'relative';
      splashSpinner.style.top = (video.offsetHeight / 2 - 60 / 2) + 'px';
      splashSpinner.style.left = (video.offsetWidth / 2 - 60 / 2) + 'px';
      var loadingDiv = document.createElement('div');
      loadingDiv.textContent = '*';
      splashSpinner.appendChild(loadingDiv);
      container.appendChild(splashDiv);
      return splashDiv;
    };

    var positionDataAnnotations = function(opt_nodes) {
      // positions data annotations on top of the video
      var polymerData =
          opt_nodes || queryRegExSelectorAll(that, /^polymer-data-/gi);
      polymerData.forEach(function(node) {
        node.style.position = 'absolute';
        node.style.top = (video.offsetTop + 0.66 * video.offsetHeight) +
            'px';
        node.style.left = (video.offsetLeft + (0.05 * that.width)) + 'px';
        node.style.width = (0.9 * that.width) + 'px';
        node.style.display = 'none';
      });
    };

    var readCues = function(cues, kind) {
      if (!cues) {
        return;
      }
      var cueData = [];
      for (var i = 0, lenI = cues.length; i < lenI; i++) {
        var cue = cues.item ? cues.item(i) : cues[i];
        cueData.push({
          start: parseInt(cue.startTime, 10),
          end: parseInt(cue.endTime, 10),
          text: cue.text,
          id: cue.id,
          type: kind
        });
      }
      console.log('Fired event: cuesread');
      that.fire(
        'cuesread',
        {
          cueData: cueData,
          kind: kind
        }
      );
    };

    video.addEventListener('loadedmetadata', function() {
      console.log('Received event (video): loadedmetadata');
      that.duration = video.duration;
      // adjust the timeline dimensions according to the video duration
      var polymerTimelines = that.querySelectorAll('polymer-timeline');
      for (var i = 0, lenI = polymerTimelines.length; i < lenI; i++) {
        polymerTimelines[i].style.left = (video.offsetLeft +
            (0.05 * that.width)) + 'px';
      }
      var polymerData = queryRegExSelector(that, /^polymer-data-/gi);
      console.log('Fired event: hypervideoloadedmetadata');
      that.fire(
        'hypervideoloadedmetadata',
        {
          duration: that.duration,
          height: that.height,
          width: that.width,
          actorsOffset: {
            left: polymerData ? polymerData.style.left.replace('px', '') : null,
            top: polymerData ? polymerData.style.top.replace('px', '') : null
          }
        }
      );

      // alternative views
      if (that.alternativeviews) {
        var videos = [video];
        var videoWidth = Math.floor(that.width / 5);

        function showControls(e) {
          return e.target.setAttribute('controls', true);
        }

        var hideControls = function hideControls(e) {
          return e.target.removeAttribute('controls');
        };

        var playAll = function playAll() {
          for (var i = 0; i < videos.length; i++) {
            videos[i].play();
          }
        };

        var pauseAll = function pauseAll() {
          for (var i = 0; i < videos.length; i++) {
            videos[i].pause();
          }
        };

        var seekAll = function seekAll(e) {
          for (var i = 0; i < videos.length; i++) {
            var currentVideo = videos[i];
            if (currentVideo === e.target) {
              continue;
            }
            currentVideo.currentTime = e.target.currentTime;
          }
        };

        var makeBig = function makeBig(e) {
          for (var i = 0, j = 0; i < videos.length; i++) {
            var currentVideo = videos[i];
            if (currentVideo === e.target) {
              currentVideo.classList.remove('small');
              currentVideo.classList.add('big');
              currentVideo.width = that.width;
              currentVideo.addEventListener('mouseover', showControls);
              currentVideo.addEventListener('mouseout', hideControls);
              currentVideo.addEventListener('seeked', seekAll);
              currentVideo.style.left = 0;
            } else {
              currentVideo.classList.remove('big');
              currentVideo.classList.add('small');
              currentVideo.removeEventListener('mouseover', showControls);
              currentVideo.removeEventListener('mouseout', hideControls);
              currentVideo.removeEventListener('seeked', seekAll);
              currentVideo.style.left = (j * videoWidth) + 'px';
              currentVideo.width = videoWidth;
              currentVideo.removeAttribute('controls');
              j++;
            }
          }
        };

        that.alternativeviews.split(/\s/).forEach(function(views) {
          views = JSON.parse(views);
          var content = container.querySelector('content');
          for (var videoSource in views) {
            if (video.currentSrc.indexOf(videoSource) === -1) {
              continue;
            }
            for (var id in views[videoSource]) {
              var alternativeView = views[videoSource][id];
              console.log(alternativeView);
              var viewVideo = document.createElement('video');
              var viewSource = document.createElement('source');
              viewSource.src = alternativeView.src;
              viewVideo.appendChild(viewSource);
              viewVideo.id = id;
              viewVideo.setAttribute('title', alternativeView.title);
              video.parentNode.insertBefore(viewVideo, content);
              videos.push(viewVideo);
            }
          }
        });

        (function init() {
          for (var i = 0; i < videos.length; i++) {
            var currentVideo = videos[i];

            currentVideo.addEventListener('play', playAll);

            currentVideo.addEventListener('pause', pauseAll);

            currentVideo.addEventListener('click', makeBig);

            var ratio = that.width / that.height;
            if (i === 0) {
              currentVideo.classList.add('big');
              currentVideo.addEventListener('mouseover', showControls);
              currentVideo.addEventListener('mouseout', hideControls);
              currentVideo.addEventListener('seeked', seekAll);
              currentVideo.width = that.width;
              currentVideo.muted = false;
            } else {
              currentVideo.classList.add('small');
              currentVideo.style.left = ((i - 1) * videoWidth) + 'px';
              currentVideo.style.top =
                  (that.height - (videoWidth / ratio) - 50) + 'px';
              currentVideo.width = videoWidth;
              currentVideo.muted = true;
            }
          }
        })();
      }

    }, false);

    // publish timeupdate events
    video.addEventListener('timeupdate', function() {
      // console.log('Received event (video): timeupdate');
      that.currentTime = video.currentTime;
      // console.log('Fired event: hypervideotimeupdate');
      that.fire(
        'hypervideotimeupdate',
        {
          currentTime: that.currentTime
        }
      );
    }, false);

    spinner = showSpinner();
    setTimeout(function() {
      initializeVideo();
      positionDataAnnotations();
      spinner.remove();
    }, 50);
  },
  pause: function() {
    return this.$.hypervideo.pause();
  },
  play: function() {
    return this.$.hypervideo.play();
  }
});<|endoftext|>


<commit_before>// An example configuration file.
exports.config = {
  // Do not start a Selenium Standalone sever - only run this using chrome.
  chromeOnly: true,
  chromeDriver: './node_modules/protractor/selenium/chromedriver',

  // Capabilities to be passed to the webdriver instance.
  capabilities: {
    'browserName': 'chrome',
    'chromeOptions': {
      'args': ['show-fps-counter=true']
    }

  },

  // Spec patterns are relative to the current working directly when
  // protractor is called.
  specs: ['test/e2e/**/*.spec.js'],

  // Options to be passed to Jasmine-node.
  jasmineNodeOpts: {
    showColors: true,
    defaultTimeoutInterval: 30000
  }

};<commit_msg>4 error ignore<commit_after>// An example configuration file.
exports.config = {
  // Do not start a Selenium Standalone sever - only run this using chrome.
  chromeOnly: true,
  chromeDriver: './node_modules/protractor/selenium/chromedriver',

  // Capabilities to be passed to the webdriver instance.
  capabilities: {
    'browserName': 'chrome',
    'chromeOptions': {
      'args': ['--test-type', 'show-fps-counter=true']
    }

  },

  // Spec patterns are relative to the current working directly when
  // protractor is called.
  specs: ['test/e2e/**/*.spec.js'],

  // Options to be passed to Jasmine-node.
  jasmineNodeOpts: {
    showColors: true,
    defaultTimeoutInterval: 30000
  }

};<|endoftext|>


<commit_before>"use strict"

const generateElements = (emojiInput) => {
  const clickLink = (event) => {
    emojiInput.value = emojiInput.value + event.target.innerHTML
    emojiPicker.style.display = 'none';
  }

  emojiInput.style = `width: 100%`

  const emojiContainer = document.createElement('div')
  emojiContainer.style = `position: relative;`

  const parent = emojiInput.parentNode;
  parent.replaceChild(emojiContainer, emojiInput)
  emojiContainer.appendChild(emojiInput)

  const emojiPicker = document.createElement('div')
  emojiPicker.style = `position: absolute;
    right: 0;
    z-index: 999;
    display: none;
    width: 225px;
    padding: 5px 2px 5px 5px;
    margin-top: 5px;
    overflow: hidden;
    background: #fff;
    border: 1px #dfdfdf solid;
    border-radius: 3px;
    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);`

  const emojiTrigger = document.createElement('a')
  emojiTrigger.style = `position: absolute;
    top: 2px;
    right: 2px;
    text-decoration: none;`
  emojiTrigger.setAttribute('href', "javascript:void(0)")
  emojiTrigger.innerHTML = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"17\" height=\"17\" viewBox=\"0 0 12 14\"><path d=\"M8.9 8.4q-0.3 0.9-1.1 1.5t-1.8 0.6-1.8-0.6-1.1-1.5q-0.1-0.2 0-0.4t0.3-0.2q0.2-0.1 0.4 0t0.2 0.3q0.2 0.6 0.7 1t1.2 0.4 1.2-0.4 0.7-1q0.1-0.2 0.3-0.3t0.4 0 0.3 0.2 0 0.4zM5 5q0 0.4-0.3 0.7t-0.7 0.3-0.7-0.3-0.3-0.7 0.3-0.7 0.7-0.3 0.7 0.3 0.3 0.7zM9 5q0 0.4-0.3 0.7t-0.7 0.3-0.7-0.3-0.3-0.7 0.3-0.7 0.7-0.3 0.7 0.3 0.3 0.7zM11 7q0-1-0.4-1.9t-1.1-1.6-1.6-1.1-1.9-0.4-1.9 0.4-1.6 1.1-1.1 1.6-0.4 1.9 0.4 1.9 1.1 1.6 1.6 1.1 1.9 0.4 1.9-0.4 1.6-1.1 1.1-1.6 0.4-1.9zM12 7q0 1.6-0.8 3t-2.2 2.2-3 0.8-3-0.8-2.2-2.2-0.8-3 0.8-3 2.2-2.2 3-0.8 3 0.8 2.2 2.2 0.8 3z\"/></svg>"
  emojiTrigger.onclick = () => {
    emojiPicker.style.display = emojiPicker.style.display === 'block' ? 'none' : 'block';
  }

  emojiContainer.appendChild(emojiTrigger)

  const emojiList = document.createElement('ul')
  emojiList.style = `padding: 0;
    list-style: none;`
  const emojis = [0x1F601, 0x1F604, 0x1F60D];

  emojis.map((item) => {
      const emojiLi = document.createElement('li')
      emojiLi.style = `display: inline-block;
        margin: 5px;`

      const emojiLink = document.createElement('a')
      emojiLink.style = `text-decoration: none;
        position: initial;
        font-size: 24px;`
      emojiLink.setAttribute('href', "javascript:void(0)")
      emojiLink.innerHTML = String.fromCodePoint(item)
      emojiLink.onclick = clickLink

      emojiList.appendChild(emojiLink)
  })

  emojiPicker.appendChild(emojiList)
  emojiContainer.appendChild(emojiPicker)
}

window.EmojiPicker = {
  init: () => {
    const emojiInputs = document.querySelectorAll('[data-emoji="true"]');

    emojiInputs.forEach((element) => {
      generateElements(element)
    })
  }
}
<commit_msg>Container position<commit_after>"use strict"

const generateElements = (emojiInput) => {
  const clickLink = (event) => {
    emojiInput.value = emojiInput.value + event.target.innerHTML
    emojiPicker.style.display = 'none';
  }

  emojiInput.style = `width: 100%`

  const emojiContainer = document.createElement('div')
  emojiContainer.style = `position: relative;`

  const parent = emojiInput.parentNode;
  parent.replaceChild(emojiContainer, emojiInput)
  emojiContainer.appendChild(emojiInput)

  const emojiPicker = document.createElement('div')
  emojiPicker.style = `position: absolute;
    right: 2px;
    top: 20px;
    z-index: 999;
    display: none;
    width: 225px;
    padding: 5px 2px 5px 5px;
    margin-top: 5px;
    overflow: hidden;
    background: #fff;
    border: 1px #dfdfdf solid;
    border-radius: 3px;
    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);`

  const emojiTrigger = document.createElement('a')
  emojiTrigger.style = `position: absolute;
    top: 2px;
    right: 2px;
    text-decoration: none;`
  emojiTrigger.setAttribute('href', "javascript:void(0)")
  emojiTrigger.innerHTML = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"17\" height=\"17\" viewBox=\"0 0 12 14\"><path d=\"M8.9 8.4q-0.3 0.9-1.1 1.5t-1.8 0.6-1.8-0.6-1.1-1.5q-0.1-0.2 0-0.4t0.3-0.2q0.2-0.1 0.4 0t0.2 0.3q0.2 0.6 0.7 1t1.2 0.4 1.2-0.4 0.7-1q0.1-0.2 0.3-0.3t0.4 0 0.3 0.2 0 0.4zM5 5q0 0.4-0.3 0.7t-0.7 0.3-0.7-0.3-0.3-0.7 0.3-0.7 0.7-0.3 0.7 0.3 0.3 0.7zM9 5q0 0.4-0.3 0.7t-0.7 0.3-0.7-0.3-0.3-0.7 0.3-0.7 0.7-0.3 0.7 0.3 0.3 0.7zM11 7q0-1-0.4-1.9t-1.1-1.6-1.6-1.1-1.9-0.4-1.9 0.4-1.6 1.1-1.1 1.6-0.4 1.9 0.4 1.9 1.1 1.6 1.6 1.1 1.9 0.4 1.9-0.4 1.6-1.1 1.1-1.6 0.4-1.9zM12 7q0 1.6-0.8 3t-2.2 2.2-3 0.8-3-0.8-2.2-2.2-0.8-3 0.8-3 2.2-2.2 3-0.8 3 0.8 2.2 2.2 0.8 3z\"/></svg>"
  emojiTrigger.onclick = () => {
    emojiPicker.style.display = emojiPicker.style.display === 'block' ? 'none' : 'block';
  }

  emojiContainer.appendChild(emojiTrigger)

  const emojiList = document.createElement('ul')
  emojiList.style = `padding: 0;
    list-style: none;`
  const emojis = [0x1F601, 0x1F604, 0x1F60D];

  emojis.map((item) => {
      const emojiLi = document.createElement('li')
      emojiLi.style = `display: inline-block;
        margin: 5px;`

      const emojiLink = document.createElement('a')
      emojiLink.style = `text-decoration: none;
        position: initial;
        font-size: 24px;`
      emojiLink.setAttribute('href', "javascript:void(0)")
      emojiLink.innerHTML = String.fromCodePoint(item)
      emojiLink.onclick = clickLink

      emojiList.appendChild(emojiLink)
  })

  emojiPicker.appendChild(emojiList)
  emojiContainer.appendChild(emojiPicker)
}

window.EmojiPicker = {
  init: () => {
    const emojiInputs = document.querySelectorAll('[data-emoji="true"]');

    emojiInputs.forEach((element) => {
      generateElements(element)
    })
  }
}
<|endoftext|>


<commit_before>const electron = require('electron')
const clipboard = electron.clipboard
const path = require('path')
const shell = electron.shell
const remote = electron.remote
const {
  dialog,
  Menu,
  MenuItem
} = remote
const fs = require('fs')

// Global variables
var scripts = ''
var styles = ''
var currentEditor = ''
var editor = []
var menu, output, html, css, js, editorLabels

// Functions for AddIns
const getScr = () => scripts
const getSty = () => styles
const getCurEditor = () => {
  getEditor()
  return currentEditor
}

function getEditor () {
  if (html.hasFocus()) {
    currentEditor = html
  }
  if (css.hasFocus()) {
    currentEditor = css
  }
  if (js.hasFocus()) {
    currentEditor = js
  }
}

function toggleEditors (editorI) {
  if (editorI === html) {
    css.focus()
  }
  if (editorI === css) {
    js.focus()
  }
  if (editorI === js) {
    html.focus()
  }
}

function newFile () {
  fileEntry = null
  hasWriteAccess = false
}

function handleNewButton (i) {
  if (false) {
    newFile()
    editor[i].setValue('')
  } else {
    window.open(path.join('file://', __dirname, '/index.html'))
  }
}

// Context menu init()
function initContextMenu () {
  menu = new Menu()
  menu.append(new MenuItem({
    label: 'Copy',
    click: function () {
      var editor = getCurEditor()
      var text = editor.getSelection()
      clipboard.writeText(text)
    }
  }))
  menu.append(new MenuItem({
    label: 'Cut',
    click: function () {
      var editor = getCurEditor()
      var text = editor.getSelection()
      clipboard.writeText(text)
      editor.replaceSelection('')
    }
  }))
  menu.append(new MenuItem({
    label: 'Paste',
    click: function () {
      var editor = getCurEditor()
      editor.replaceSelection(clipboard.readText())
    }
  }))

  window.addEventListener('contextmenu', function (ev) {
    ev.preventDefault()
    menu.popup(remote.getCurrentWindow(), ev.x, ev.y)
  }, false)
}

// Main Functions for Electron
onload = function () {
  initContextMenu()

  var helpMenu = document.getElementById('help-menu')
  var helpa = helpMenu.getElementsByTagName('a')
  for (var i = 0; i < helpa.length; i++) {
    helpa[i].addEventListener('click', function (e) {
      e.preventDefault()
      shell.openExternal(this.href)
    })
  }

  document.getElementById('min-button').addEventListener('click', function (e) {
    const window = remote.getCurrentWindow()
    window.minimize()
  })

  document.getElementById('max-button').addEventListener('click', function (e) {
    const window = remote.getCurrentWindow()
    if (!window.isMaximized()) {
      window.maximize()
    } else {
      window.unmaximize()
    }
  })

  document.getElementById('close-button').addEventListener('click', function (e) {
    const window = remote.getCurrentWindow()
    window.close()
  })

  document.getElementById('close-window').addEventListener('click', function (e) {
    const window = remote.getCurrentWindow()
    window.close()
  })
  document.getElementById('new').addEventListener('click', handleNewButton)

  editor[0] = CodeMirror(
    document.getElementById('html-editor'), {
      mode: {
        name: 'htmlmixed'
      },
      lineNumbers: true,
      lineWrapping: true,
      autofocus: true,
      indentWithTabs: false,
      indentUnit: 2,
      smartIndent: true,
      scrollbarStyle: 'overlay',
      theme: 'base16-ocean-dark'
    })

  editor[1] = CodeMirror(
    document.getElementById('css-editor'), {
      mode: {
        name: 'css'
      },
      lineNumbers: true,
      lineWrapping: true,
      indentWithTabs: false,
      indentUnit: 2,
      smartIndent: true,
      scrollbarStyle: 'overlay',
      theme: 'base16-ocean-dark'
    })

  editor[2] = CodeMirror(
    document.getElementById('js-editor'), {
      mode: {
        name: 'javascript',
        json: true
      },
      lineNumbers: true,
      lineWrapping: true,
      indentWithTabs: false,
      indentUnit: 2,
      smartIndent: true,
      scrollbarStyle: 'overlay',
      theme: 'base16-ocean-dark'
    })

  output = document.getElementById('output')
  editorLabels = document.getElementsByClassName('editor-label')
  html = editor[0]
  css = editor[1]
  js = editor[2]

  html.on('change', function (change) {
    paint()
  })

  css.on('change', function (change) {
    paint()
  })

  js.on('change', function (change) {
    paint()
  })

  html.on('focus', function (change) {
    removeFocus(editorLabels)
    editorLabels[0].classList.add('editor-focus')
  })

  css.on('focus', function (change) {
    removeFocus(editorLabels)
    editorLabels[1].classList.add('editor-focus')
  })

  js.on('focus', function (change) {
    removeFocus(editorLabels)
    editorLabels[2].classList.add('editor-focus')
  })

  fileMenu()
  addScript()
  addStyle()
  shortcuts()
  newFile()
  onresize()
}

function removeFocus (editor) {
  for (var i = 0; i < editor.length; i++) {
    editor[i].classList.remove('editor-focus')
  }
}

onresize = function () {
  for (var i = 0; i < 3; i++) {
    editor[i].refresh()
  }
}

function paint () {
  output.srcdoc = '' + '' + getSty() + '' + '' + '' + html.getValue() + getScr() + '' + '' + ''
  console.log(output.srcdoc)
}

function toggleStatus (i, span) {
  if (span[i].classList.contains('status-active')) {
    span[i].classList.remove('status-active')
  } else {
    span[i].classList.add('status-active')
  }
}

function fileMenu () {
  var saveButton = document.getElementById('save')
  saveButton.addEventListener('click', saveFunction)
}

function saveFunction () {
  var path = dialog.showOpenDialog({
    properties: ['openDirectory']
  })
  if (path === undefined) return
  var htmlString = '\n' + '\n' + '<title> Add Title Here </title>\n' + '<link type="text/css" rel="stylesheet" href="style.css"/>\n' + '\n' + '\n' + html.getValue() + '\n\n' + '\n' + ''
  // Write HTML
  fs.writeFile(path + '/index.html', htmlString, (err) => {
    if (err) {
      console.error(err)
    }
    console.log('success HTML')
  })
  // Write CSS
  fs.writeFile(path + '/style.css', css.getValue(), (err) => {
    if (err) {
      console.error(err)
    }
    console.log('success CSS')
  })
  // Write JS
  fs.writeFile(path + '/script.js', js.getValue(), (err) => {
    if (err) {
      console.error(err)
    }
    console.log('success JS')
  })

  dialog.showMessageBox({
    message: 'Saved to ' + path + '\\',
    buttons: ['OK']
  })
}

function addScript () {
  var jsMenu = document.getElementById('js-menu')
  var jsButtons = jsMenu.getElementsByTagName('a')
  let jsSpan = jsMenu.querySelectorAll('span')
  var ScrFlags = [0, 0, 0, 0, 0]
  jsButtons[0].addEventListener('click', function (e) {
    var aniStr = ""
    if (ScrFlags[0] === 0) {
      scripts += aniStr
      ScrFlags[0] = 1
      console.log('Anime added!')
      toggleStatus(0, jsSpan)
    } else {
      scripts = scripts.replace(aniStr, '')
      ScrFlags[0] = 0
      console.log('Anime removed!')
      toggleStatus(0, jsSpan)
    }
  })
  jsButtons[1].addEventListener('click', function (e) {
    var jQStr = ""
    if (ScrFlags[2] === 0) {
      toggleStatus(2, jsSpan)
      scripts += jQStr
      ScrFlags[2] = 1
      console.log('jQuery added!')
    }
    if (ScrFlags[1] === 0) {
      scripts += bootjsStr
      ScrFlags[1] = 1
      console.log('Bootstrap added!')
      toggleStatus(1, jsSpan)
    } else {
      scripts = scripts.replace(bootjsStr, '')
      ScrFlags[1] = 0
      console.log('Bootstrap removed!')
      toggleStatus(1, jsSpan)
    }
  })
  jsButtons[2].addEventListener('click', function (e) {
    var jQStr = ""
    if (ScrFlags[2] === 0) {
      scripts += jQStr
      ScrFlags[2] = 1
      console.log('jQuery added!')
      toggleStatus(2, jsSpan)
    } else if (ScrFlags[1] === 0) {
      scripts = scripts.replace(jQStr, '')
      ScrFlags[2] = 0
      console.log('jQuery removed!')
      toggleStatus(2, jsSpan)
    }
  })
  jsButtons[3].addEventListener('click', function (e) {
    var p5Str = ""
    if (ScrFlags[3] === 0) {
      scripts += p5Str
      ScrFlags[3] = 1
      console.log('p5.js added!')
      toggleStatus(3, jsSpan)
    } else {
      scripts = scripts.replace(p5Str, '')
      ScrFlags[3] = 0
      console.log('p5.js removed!')
      toggleStatus(3, jsSpan)
    }
  })
  jsButtons[4].addEventListener('click', function (e) {
    var js3Str = ""
    if (ScrFlags[4] === 0) {
      scripts += js3Str
      ScrFlags[4] = 1
      console.log('Three.js added!')
      toggleStatus(4, jsSpan)
    } else {
      scripts = scripts.replace(js3Str, '')
      ScrFlags[4] = 0
      console.log('Three.js removed!')
      toggleStatus(4, jsSpan)
    }
  })
};

function addStyle () {
  var cssMenu = document.getElementById('css-menu')
  var cssButtons = cssMenu.getElementsByTagName('a')
  let cssSpan = cssMenu.querySelectorAll('span')
  var StyFlags = [0, 0, 0]
  cssButtons[0].addEventListener('click', function (e) {
    var aniStr = "<link rel='stylesheet' type='text/css' href='lib/animate.css'>"
    if (StyFlags[0] === 0) {
      aniStr = "<link rel='stylesheet' type='text/css' href='lib/animate.css'>"
      styles += aniStr
      StyFlags[0] = 1
      console.log('Animate added!')
      toggleStatus(0, cssSpan)
    } else {
      styles = styles.replace(aniStr, '')
      StyFlags[0] = 0
      console.log('Animate removed!')
      toggleStatus(0, cssSpan)
    }
  })
  cssButtons[1].addEventListener('click', function (e) {
    var bootStr = "<link rel='stylesheet' type='text/css' href='lib/bootstrap.min.css'>"
    if (StyFlags[1] === 0) {
      styles += bootStr
      StyFlags[1] = 1
      console.log('Bootstrap added!')
      toggleStatus(1, cssSpan)
    } else {
      styles = styles.replace(bootStr, '')
      StyFlags[1] = 0
      console.log('Bootstrap removed!')
      toggleStatus(1, cssSpan)
    }
  })
  cssButtons[2].addEventListener('click', function (e) {
    var faStr = "<link rel='stylesheet' type='text/css' href='lib/font-awesome.min.css'>"
    if (StyFlags[2] === 0) {
      styles += faStr
      StyFlags[2] = 1
      console.log('Font Awesome added!')
      toggleStatus(2, cssSpan)
    } else {
      styles = styles.replace(faStr, '')
      StyFlags[2] = 0
      console.log('Font Awesome removed!')
      toggleStatus(2, cssSpan)
    }
  })
};

function shortcuts () {
  window.addEventListener('keydown', (e) => {
    console.log(e)
    if (e.ctrlKey && e.key === 'Tab') {
      console.warn('Ctrl + Tab')
      var selectedEditor = getCurEditor()
      toggleEditors(selectedEditor)
    }
    if (e.key === 'F12') {
      remote.getCurrentWindow().toggleDevTools()
    }
    if (e.ctrlKey && (e.key === 's' || e.key === 'S')) {
      saveFunction()
    }
    if (e.ctrlKey && (e.key === 'n' || e.key === 'N')) {
      handleNewButton()
    }
  })
}
<commit_msg>Save! :tada:<commit_after>const electron = require('electron')
const clipboard = electron.clipboard
const path = require('path')
const shell = electron.shell
const remote = electron.remote
const {
  dialog,
  Menu,
  MenuItem
} = remote
const fs = require('fs')

// Global variables
var scripts = ''
var styles = ''
var currentEditor = ''
var editor = []
var menu, output, html, css, js, editorLabels
var ScrFlags = [0, 0, 0, 0, 0]
var StyFlags = [0, 0, 0]

var jsLib = [
  ['anime.min.js', ""],
  ['bootstrap.min.js', ""],
  ['jquery-3.1.1.min.js', ""],
  ['p5.min.js', ""],
  ['three.min.js', ""]
]
var cssLib = [
  ['animate.css', "<link rel='stylesheet' type='text/css' href='lib/animate.css'>"],
  ['bootstrap.min.css', "<link rel='stylesheet' type='text/css' href='lib/bootstrap.min.css'>"],
  ['font-awesome.min.css', "<link rel='stylesheet' type='text/css' href='lib/font-awesome.min.css'>"]
]

function getCssLibs () {
  var cssHtml = ''
  for (var i = 0; i < cssLib.length; i++) {
    if (StyFlags[i] === 1) {
      cssHtml += cssLib[i][1].replace('lib/', '')
    }
  }
  console.log(cssHtml)
  return cssHtml
}

function getJsLibs () {
  var jsHtml = ''
  for (var i = 0; i < jsLib.length; i++) {
    if (ScrFlags[i] === 1) {
      jsHtml += jsLib[i][1].replace('lib/', '')
    }
  }
  console.log(jsHtml)
  return jsHtml
}

// Functions for AddIns
const getScr = () => scripts
const getSty = () => styles
const getCurEditor = () => {
  getEditor()
  return currentEditor
}

function getEditor () {
  if (html.hasFocus()) {
    currentEditor = html
  }
  if (css.hasFocus()) {
    currentEditor = css
  }
  if (js.hasFocus()) {
    currentEditor = js
  }
}

function toggleEditors (editorI) {
  if (editorI === html) {
    css.focus()
  }
  if (editorI === css) {
    js.focus()
  }
  if (editorI === js) {
    html.focus()
  }
}

function newFile () {
  fileEntry = null
  hasWriteAccess = false
}

function handleNewButton (i) {
  if (false) {
    newFile()
    editor[i].setValue('')
  } else {
    window.open(path.join('file://', __dirname, '/index.html'))
  }
}

// Context menu init()
function initContextMenu () {
  menu = new Menu()
  menu.append(new MenuItem({
    label: 'Copy',
    click: function () {
      var editor = getCurEditor()
      var text = editor.getSelection()
      clipboard.writeText(text)
    }
  }))
  menu.append(new MenuItem({
    label: 'Cut',
    click: function () {
      var editor = getCurEditor()
      var text = editor.getSelection()
      clipboard.writeText(text)
      editor.replaceSelection('')
    }
  }))
  menu.append(new MenuItem({
    label: 'Paste',
    click: function () {
      var editor = getCurEditor()
      editor.replaceSelection(clipboard.readText())
    }
  }))

  window.addEventListener('contextmenu', function (ev) {
    ev.preventDefault()
    menu.popup(remote.getCurrentWindow(), ev.x, ev.y)
  }, false)
}

// Main Functions for Electron
onload = function () {
  initContextMenu()

  var helpMenu = document.getElementById('help-menu')
  var helpa = helpMenu.getElementsByTagName('a')
  for (var i = 0; i < helpa.length; i++) {
    helpa[i].addEventListener('click', function (e) {
      e.preventDefault()
      shell.openExternal(this.href)
    })
  }

  document.getElementById('min-button').addEventListener('click', function (e) {
    const window = remote.getCurrentWindow()
    window.minimize()
  })

  document.getElementById('max-button').addEventListener('click', function (e) {
    const window = remote.getCurrentWindow()
    if (!window.isMaximized()) {
      window.maximize()
    } else {
      window.unmaximize()
    }
  })

  document.getElementById('close-button').addEventListener('click', function (e) {
    const window = remote.getCurrentWindow()
    window.close()
  })

  document.getElementById('close-window').addEventListener('click', function (e) {
    const window = remote.getCurrentWindow()
    window.close()
  })
  document.getElementById('new').addEventListener('click', handleNewButton)

  editor[0] = CodeMirror(
    document.getElementById('html-editor'), {
      mode: {
        name: 'htmlmixed'
      },
      lineNumbers: true,
      lineWrapping: true,
      autofocus: true,
      indentWithTabs: false,
      indentUnit: 2,
      smartIndent: true,
      scrollbarStyle: 'overlay',
      theme: 'base16-ocean-dark'
    })

  editor[1] = CodeMirror(
    document.getElementById('css-editor'), {
      mode: {
        name: 'css'
      },
      lineNumbers: true,
      lineWrapping: true,
      indentWithTabs: false,
      indentUnit: 2,
      smartIndent: true,
      scrollbarStyle: 'overlay',
      theme: 'base16-ocean-dark'
    })

  editor[2] = CodeMirror(
    document.getElementById('js-editor'), {
      mode: {
        name: 'javascript',
        json: true
      },
      lineNumbers: true,
      lineWrapping: true,
      indentWithTabs: false,
      indentUnit: 2,
      smartIndent: true,
      scrollbarStyle: 'overlay',
      theme: 'base16-ocean-dark'
    })

  output = document.getElementById('output')
  editorLabels = document.getElementsByClassName('editor-label')
  html = editor[0]
  css = editor[1]
  js = editor[2]

  html.on('change', function (change) {
    paint()
  })

  css.on('change', function (change) {
    paint()
  })

  js.on('change', function (change) {
    paint()
  })

  html.on('focus', function (change) {
    removeFocus(editorLabels)
    editorLabels[0].classList.add('editor-focus')
  })

  css.on('focus', function (change) {
    removeFocus(editorLabels)
    editorLabels[1].classList.add('editor-focus')
  })

  js.on('focus', function (change) {
    removeFocus(editorLabels)
    editorLabels[2].classList.add('editor-focus')
  })

  fileMenu()
  addScript()
  addStyle()
  shortcuts()
  newFile()
  onresize()
}

function removeFocus (editor) {
  for (var i = 0; i < editor.length; i++) {
    editor[i].classList.remove('editor-focus')
  }
}

onresize = function () {
  for (var i = 0; i < 3; i++) {
    editor[i].refresh()
  }
}

function paint () {
  output.srcdoc = '' + '' + getSty() + '' + '' + '' + html.getValue() + getScr() + '' + '' + ''
  console.log(output.srcdoc)
}

function toggleStatus (i, span) {
  if (span[i].classList.contains('status-active')) {
    span[i].classList.remove('status-active')
  } else {
    span[i].classList.add('status-active')
  }
}

function fileMenu () {
  var saveButton = document.getElementById('save')
  saveButton.addEventListener('click', saveFunction)
}

function saveFunction () {
  var path = dialog.showOpenDialog({
    properties: ['openDirectory']
  })
  if (path === undefined) return
  var htmlString = '\n' + '\n' + '<title> Add Title Here </title>\n' + getCssLibs() + '<link type="text/css" rel="stylesheet" href="style.css"/>\n' + '\n' + '\n' + html.getValue() + getJsLibs() + '\n\n' + '\n' + ''
  // Write HTML
  fs.writeFile(path + '/index.html', htmlString, (err) => {
    if (err) {
      console.error(err)
    }
    console.log('success HTML')
  })
  // Write CSS
  fs.writeFile(path + '/style.css', css.getValue(), (err) => {
    if (err) {
      console.error(err)
    }
    console.log('success CSS')
  })
  // Write JS
  fs.writeFile(path + '/script.js', js.getValue(), (err) => {
    if (err) {
      console.error(err)
    }
    console.log('success JS')
  })

  // TODO: No error checking is done here, fix it
  for (var i = 0; i < ScrFlags.length; i++) {
    if (ScrFlags[i] === 1) {
      fs.createReadStream('lib/' + jsLib[i][0]).pipe(fs.createWriteStream(path + '/' + jsLib[i][0]))
    }
  }

  for (var j = 0; j < StyFlags.length; j++) {
    if (StyFlags[j] === 1) {
      fs.createReadStream('lib/' + cssLib[j][0]).pipe(fs.createWriteStream(path + '/' + cssLib[j][0]))
    }
  }

  dialog.showMessageBox({
    message: 'Saved to ' + path + '\\',
    buttons: ['OK']
  })
}

function addScript () {
  var jsMenu = document.getElementById('js-menu')
  var jsButtons = jsMenu.getElementsByTagName('a')
  let jsSpan = jsMenu.querySelectorAll('span')
  jsButtons[0].addEventListener('click', function (e) {
    var aniScr = jsLib[0][1]
    if (ScrFlags[0] === 0) {
      scripts += aniScr
      ScrFlags[0] = 1
      console.log('Anime added!')
      toggleStatus(0, jsSpan)
    } else {
      scripts = scripts.replace(aniScr, '')
      ScrFlags[0] = 0
      console.log('Anime removed!')
      toggleStatus(0, jsSpan)
    }
  })
  jsButtons[1].addEventListener('click', function (e) {
    var jqScr = jsLib[2][1]
    var boScr = jsLib[1][1]
    if (ScrFlags[2] === 0) {
      toggleStatus(2, jsSpan)
      scripts += jqScr
      ScrFlags[2] = 1
      console.log('jQuery added!')
    }
    if (ScrFlags[1] === 0) {
      scripts += boScr
      ScrFlags[1] = 1
      console.log('Bootstrap added!')
      toggleStatus(1, jsSpan)
    } else {
      scripts = scripts.replace(boScr, '')
      ScrFlags[1] = 0
      console.log('Bootstrap removed!')
      toggleStatus(1, jsSpan)
    }
  })
  jsButtons[2].addEventListener('click', function (e) {
    var jqScr = jsLib[2][1]
    if (ScrFlags[2] === 0) {
      scripts += jqScr
      ScrFlags[2] = 1
      console.log('jQuery added!')
      toggleStatus(2, jsSpan)
    } else if (ScrFlags[1] === 0) {
      scripts = scripts.replace(jqScr, '')
      ScrFlags[2] = 0
      console.log('jQuery removed!')
      toggleStatus(2, jsSpan)
    }
  })
  jsButtons[3].addEventListener('click', function (e) {
    var p5Scr = jsLib[3][1]
    if (ScrFlags[3] === 0) {
      scripts += p5Scr
      ScrFlags[3] = 1
      console.log('p5.js added!')
      toggleStatus(3, jsSpan)
    } else {
      scripts = scripts.replace(p5Scr, '')
      ScrFlags[3] = 0
      console.log('p5.js removed!')
      toggleStatus(3, jsSpan)
    }
  })
  jsButtons[4].addEventListener('click', function (e) {
    var thScr = jsLib[4][1]
    if (ScrFlags[4] === 0) {
      scripts += thScr
      ScrFlags[4] = 1
      console.log('Three.js added!')
      toggleStatus(4, jsSpan)
    } else {
      scripts = scripts.replace(thScr, '')
      ScrFlags[4] = 0
      console.log('Three.js removed!')
      toggleStatus(4, jsSpan)
    }
  })
};

function addStyle () {
  var cssMenu = document.getElementById('css-menu')
  var cssButtons = cssMenu.getElementsByTagName('a')
  let cssSpan = cssMenu.querySelectorAll('span')
  cssButtons[0].addEventListener('click', function (e) {
    var anSty = cssLib[0][1]
    if (StyFlags[0] === 0) {
      styles += anSty
      StyFlags[0] = 1
      console.log('Animate added!')
      toggleStatus(0, cssSpan)
    } else {
      styles = styles.replace(anSty, '')
      StyFlags[0] = 0
      console.log('Animate removed!')
      toggleStatus(0, cssSpan)
    }
  })
  cssButtons[1].addEventListener('click', function (e) {
    var boSty = cssLib[1][1]
    if (StyFlags[1] === 0) {
      styles += boSty
      StyFlags[1] = 1
      console.log('Bootstrap added!')
      toggleStatus(1, cssSpan)
    } else {
      styles = styles.replace(boSty, '')
      StyFlags[1] = 0
      console.log('Bootstrap removed!')
      toggleStatus(1, cssSpan)
    }
  })
  cssButtons[2].addEventListener('click', function (e) {
    var faSty = cssLib[2][1]
    if (StyFlags[2] === 0) {
      styles += faSty
      StyFlags[2] = 1
      console.log('Font Awesome added!')
      toggleStatus(2, cssSpan)
    } else {
      styles = styles.replace(faSty, '')
      StyFlags[2] = 0
      console.log('Font Awesome removed!')
      toggleStatus(2, cssSpan)
    }
  })
};

function shortcuts () {
  window.addEventListener('keydown', (e) => {
    console.log(e)
    if (e.ctrlKey && e.key === 'Tab') {
      console.warn('Ctrl + Tab')
      var selectedEditor = getCurEditor()
      toggleEditors(selectedEditor)
    }
    if (e.key === 'F12') {
      remote.getCurrentWindow().toggleDevTools()
    }
    if (e.ctrlKey && (e.key === 's' || e.key === 'S')) {
      saveFunction()
    }
    if (e.ctrlKey && (e.key === 'n' || e.key === 'N')) {
      handleNewButton()
    }
  })
}
<|endoftext|>