aboutsummaryrefslogblamecommitdiffstats
path: root/etherpad/src/static/js/broadcast_slider.js
blob: 371663ebe17a20b5bef7d31eabf8acbedd75446b (plain) (tree)











































































































































                                                                                                             
                                              


































































































































































































































































                                                                                                                                                                                 
  
/**
 * Copyright 2009 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var global = this;

(function() { // wrap this code in its own namespace
  var sliderLength = 1000;
  var sliderPos = 0;
  var sliderActive = false;
  var slidercallbacks = [];
  var savedRevisions = [];
  var sliderPlaying = false;

  function disableSelection(element) {
    element.onselectstart = function() {
      return false;
    };
    element.unselectable = "on";
    element.style.MozUserSelect = "none";
    element.style.cursor = "default";
  }
  var _callSliderCallbacks = function(newval) {
    sliderPos = newval;
    for(var i=0; i<slidercallbacks.length; i++) {
      slidercallbacks[i](newval);
    }
  }

  var updateSliderElements = function() {
    for(var i=0; i<savedRevisions.length; i++) {
      var position = parseInt(savedRevisions[i].attr('pos'));
      savedRevisions[i].css('left', (position * ($("#ui-slider-bar").width()-2) / (sliderLength * 1.0)) - 1);
    }
    $("#ui-slider-handle").css('left', sliderPos * ($("#ui-slider-bar").width()-2) / (sliderLength * 1.0));
  }

  var addSavedRevision = function(position, info) {
    var newSavedRevision = $('<div></div>');
    newSavedRevision.addClass("star");

    newSavedRevision.attr('pos', position);
    newSavedRevision.css('position', 'absolute');
    newSavedRevision.css('left', (position * ($("#ui-slider-bar").width()-2) / (sliderLength * 1.0)) - 1);
    $("#timeslider-slider").append(newSavedRevision);
    newSavedRevision.mouseup(function(evt) {
      BroadcastSlider.setSliderPosition(position);
    });
    savedRevisions.push(newSavedRevision);
  };

  var removeSavedRevision = function (position) {
    var element = $("div.star [pos="+position+"]");
    savedRevisions.remove(element);
    element.remove();
    return element;
  };

  /* Begin small 'API' */
  function onSlider(callback) {
    slidercallbacks.push(callback);
  }

  function getSliderPosition() {
    return sliderPos;
  }

  function setSliderPosition(newpos) {
    newpos = Number(newpos);
    if(newpos < 0 || newpos > sliderLength) return;
    $("#ui-slider-handle").css('left', newpos * ($("#ui-slider-bar").width()-2) / (sliderLength * 1.0));
    $("a.tlink").map(function() {
      $(this).attr('href', $(this).attr('thref').replace("%revision%", newpos));
    });
    $("#revision_label").html("Version " + newpos);

    if(newpos == 0) {
      $("#leftstar").css('opacity', .5);
      $("#leftstep").css('opacity', .5);
    } else {
      $("#leftstar").css('opacity', 1);
      $("#leftstep").css('opacity', 1);
    }

    if(newpos == sliderLength) {
      $("#rightstar").css('opacity', .5);
      $("#rightstep").css('opacity', .5);
    } else {
      $("#rightstar").css('opacity', 1);
      $("#rightstep").css('opacity', 1);
    }

    sliderPos = newpos;
    _callSliderCallbacks(newpos);
  }

  function getSliderLength() {
    return sliderLength;
  }

  function setSliderLength(newlength) {
    sliderLength = newlength;
    updateSliderElements();
  }

  // just take over the whole slider screen with a reconnect message
  function showReconnectUI() {
    if(!clientVars.sliderEnabled || !clientVars.supportsSlider) {
        $("#padmain, #rightbars").css('top', "95px");
        $("#timeslider").show();
    }
    $('#error').show();
  }

  function setAuthors(authors) {
    $("#authorstable").empty();
    var numAnonymous = 0;
    var numNamed = 0;
    authors.forEach(function(author) {
      if(author.name) {
        numNamed ++;
        var tr = $('<tr></tr>');
        var swatchtd = $('<td></td>');
        var swatch = $('<div class="swatch"></div>');
        swatch.css('background-color', clientVars.colorPalette[author.colorId]);
        swatchtd.append(swatch);
        tr.append(swatchtd);
        var nametd = $('<td></td>');
        nametd.text(author.name || "unnamed");
        tr.append(nametd);
        $("#authorstable").append(tr);
      } else {
        numAnonymous ++;
      }
    });
    if(numAnonymous > 0) {
      var html = "<tr><td colspan=\"2\" style=\"color:#999; padding-left: 10px\">"+(numNamed>0?"...and ":"")+numAnonymous+" unnamed author"+(numAnonymous>1?"s":"")+"</td></tr>";
      $("#authorstable").append($(html));
    } if(authors.length == 0) {
      $("#authorstable").append($("<tr><td colspan=\"2\" style=\"color:#999; padding-left: 10px\">No Authors</td></tr>"))
    }
  }

  global.BroadcastSlider = {
    onSlider: onSlider,
    getSliderPosition: getSliderPosition,
    setSliderPosition: setSliderPosition,
    getSliderLength: getSliderLength,
    setSliderLength: setSliderLength,
    isSliderActive: function() {return sliderActive;},
    playpause: playpause,
    addSavedRevision: addSavedRevision,
    showReconnectUI : showReconnectUI,
    setAuthors: setAuthors
  }

  function playButtonUpdater() {
    if(sliderPlaying) {
      if(getSliderPosition()+1 > sliderLength) {
        $("#playpause_button_icon").toggleClass('pause');
        sliderPlaying = false;
        return;
      }
      setSliderPosition(getSliderPosition()+1);

      setTimeout(playButtonUpdater, 100);
    }
  }

  function playpause() {
    $("#playpause_button_icon").toggleClass('pause');

    if(!sliderPlaying) {
      if(getSliderPosition() == sliderLength)
        setSliderPosition(0);
      sliderPlaying = true;
      playButtonUpdater();
    } else {
      sliderPlaying = false;
    }
  }

  // assign event handlers to html UI elements after page load
  $(window).load(function() {
    disableSelection($("#playpause_button")[0]);
    disableSelection($("#timeslider")[0]);

    if(clientVars.sliderEnabled && clientVars.supportsSlider) {
      $(document).keyup(function(e) {
        var code = -1;
        if (!e) var e = window.event;
        if (e.keyCode) code = e.keyCode;
        else if (e.which) code = e.which;

        if(code == 37) { // left
          if(!e.shiftKey) {
            setSliderPosition(getSliderPosition() - 1);
          } else {
            var nextStar = 0; // default to first revision in document
            for(var i=0; i<savedRevisions.length; i++) {
              var pos = parseInt(savedRevisions[i].attr('pos'));
              if(pos < getSliderPosition() && nextStar < pos)
                nextStar = pos;
            }
            setSliderPosition(nextStar);
          }
        } else if(code == 39) {
          if(!e.shiftKey) {
            setSliderPosition(getSliderPosition() + 1);
          } else {
            var nextStar = sliderLength; // default to last revision in document
            for(var i=0; i<savedRevisions.length; i++) {
              var pos = parseInt(savedRevisions[i].attr('pos'));
              if(pos > getSliderPosition() && nextStar > pos)
                nextStar = pos;
              }
            setSliderPosition(nextStar);
          }
        } else if(code == 32)
          playpause();

      });
    }

    $(window).resize(function() {
      updateSliderElements();
    });

    $("#ui-slider-bar").mousedown(function(evt) {
      setSliderPosition(Math.floor((evt.clientX-$("#ui-slider-bar").offset().left) * sliderLength / 742));
      $("#ui-slider-handle").css('left', (evt.clientX-$("#ui-slider-bar").offset().left));
      $("#ui-slider-handle").trigger(evt);
    });

    // Slider dragging
    $("#ui-slider-handle").mousedown(function(evt) {
      this.startLoc = evt.clientX;
      this.currentLoc = parseInt($(this).css('left'));
      var self = this;
      sliderActive = true;
      $(document).mousemove(function(evt2) {
        $(self).css('pointer', 'move')
        var newloc = self.currentLoc + (evt2.clientX - self.startLoc);
        if(newloc < 0) newloc = 0;
        if(newloc > ($("#ui-slider-bar").width()-2)) newloc = ($("#ui-slider-bar").width()-2);
        $("#revision_label").html("Version " + Math.floor(newloc * sliderLength / ($("#ui-slider-bar").width()-2)));
        $(self).css('left', newloc);
        if(getSliderPosition() != Math.floor(newloc * sliderLength / ($("#ui-slider-bar").width()-2)))
          _callSliderCallbacks(Math.floor(newloc * sliderLength / ($("#ui-slider-bar").width()-2)))
      });
      $(document).mouseup(function(evt2) {
        $(document).unbind('mousemove');
        $(document).unbind('mouseup');
        sliderActive = false;
        var newloc = self.currentLoc + (evt2.clientX - self.startLoc);
        if(newloc < 0) newloc = 0;
        if(newloc > ($("#ui-slider-bar").width()-2)) newloc = ($("#ui-slider-bar").width()-2);
        $(self).css('left', newloc);
        // if(getSliderPosition() != Math.floor(newloc * sliderLength / ($("#ui-slider-bar").width()-2)))
        setSliderPosition(Math.floor(newloc * sliderLength / ($("#ui-slider-bar").width()-2)))
        self.currentLoc = parseInt($(self).css('left'));
      });
    })

    // play/pause toggling
    $("#playpause_button").mousedown(function(evt) {
      var self = this;

      $(self).css('background-image', 'url(/static/img/pad/timeslider/crushed_button_depressed.png)');
      $(self).mouseup(function(evt2) {
        $(self).css('background-image', 'url(/static/img/pad/timeslider/crushed_button_undepressed.png)');
        $(self).unbind('mouseup');
        BroadcastSlider.playpause();
      });
      $(document).mouseup(function(evt2) {
        $(self).css('background-image', 'url(/static/img/pad/timeslider/crushed_button_undepressed.png)');
        $(document).unbind('mouseup');
      });
    });

    // next/prev saved revision and changeset
    $('.stepper').mousedown(function(evt) {
      var self = this;
      var origcss = $(self).css('background-position');
      if (! origcss) {
        origcss = $(self).css('background-position-x')+" "+$(self).css('background-position-y');
      }
      var origpos = parseInt(origcss.split(" ")[1]);
      var newpos = (origpos - 43);
      if(newpos < 0) newpos += 87;

      var newcss = (origcss.split(" ")[0] + " " + newpos + "px");
      if($(self).css('opacity') != 1.0)
        newcss = origcss;

      $(self).css('background-position', newcss)

      $(self).mouseup(function(evt2) {
        $(self).css('background-position',origcss);
        $(self).unbind('mouseup');
        $(document).unbind('mouseup');
        if($(self).attr("id") == ("leftstep")) {
          setSliderPosition(getSliderPosition() - 1);
        }
        else if($(self).attr("id") == ("rightstep")) {
          setSliderPosition(getSliderPosition() + 1);
        }
        else if($(self).attr("id") == ("leftstar")) {
          var nextStar = 0; // default to first revision in document
          for(var i=0; i<savedRevisions.length; i++) {
            var pos = parseInt(savedRevisions[i].attr('pos'));
            if(pos < getSliderPosition() && nextStar < pos)
              nextStar = pos;
          }
          setSliderPosition(nextStar);
        }
        else if($(self).attr("id") == ("rightstar")) {
          var nextStar = sliderLength; // default to last revision in document
          for(var i=0; i<savedRevisions.length; i++) {
            var pos = parseInt(savedRevisions[i].attr('pos'));
            if(pos > getSliderPosition() && nextStar > pos)
              nextStar = pos;
            }
          setSliderPosition(nextStar);
        }
      });
      $(document).mouseup(function(evt2) {
        $(self).css('background-position',origcss);
        $(self).unbind('mouseup');
        $(document).unbind('mouseup');
      });
    })

    if(clientVars) {
      if(clientVars.fullWidth) {
        $("#padpage").css('width', '100%');
        $("#revision").css('position', "absolute")
        $("#revision").css('right', "20px")
        $("#revision").css('top', "20px")
        $("#padmain").css('left', '0px');
        $("#padmain").css('right', '197px');
        $("#padmain").css('width', 'auto');
        $("#rightbars").css('right', '7px');
        $("#rightbars").css('margin-right', '0px');
        $("#timeslider").css('width', 'auto');
      }

      if(clientVars.disableRightBar) {
        $("#rightbars").css('display', 'none');
        $('#padmain').css('width', 'auto');
        if(clientVars.fullWidth)
          $("#padmain").css('right', '7px');
        else
          $("#padmain").css('width', '860px');
        $("#revision").css('position', "absolute");
        $("#revision").css('right', "20px");
        $("#revision").css('top', "20px");
      }


      if(clientVars.sliderEnabled) {
        if(clientVars.supportsSlider) {
          $("#padmain, #rightbars").css('top', "95px");
          $("#timeslider").show();
          setSliderLength(clientVars.totalRevs);
          setSliderPosition(clientVars.revNum);
          clientVars.savedRevisions.forEach(function(revision) {
            addSavedRevision(revision.revNum, revision);
          })
        } else {
          // slider is not supported
          $("#padmain, #rightbars").css('top', "95px");
          $("#timeslider").show();
          $("#error").html("The timeslider feature is not supported on this pad. <a href=\"/ep/about/faq#disabledslider\">Why not?</a>");
          $("#error").show();
        }
      } else {
        if(clientVars.supportsSlider) {
          setSliderLength(clientVars.totalRevs);
          setSliderPosition(clientVars.revNum);
        }
      }
    }
  });
})();

BroadcastSlider.onSlider(function(loc) {
  $("#viewlatest").html(loc==BroadcastSlider.getSliderLength()?"Viewing latest content":"View latest content");
})