Firefoxのmarquee実装

Shibuya.esの後のバカ話をふと思い出したので見てみたら、こんな感じでメソッドが付いてた。

$('foo').init();
$('foo').start();
$('foo').stop();
$('foo')._doMove(aSkipSettingNewPosition);

メソッド叩いたら、普通に止まったり動いたりしたので、Firebugでcopy($('foo').init.toSource())とかしてみた。


こんな感じ。

function _doMove(aSkipSettingNewPosition) {
  this.stop();
  if (this.startNewDirection) {
    this.startNewDirection = false;
    if (this.directionField == "up" || this.directionField == "down") {
      var height = this.getAttribute("height") != "0"
        && this.getAttribute("height")
        || document.defaultView.getComputedStyle(this, "").height != "0px"
        && document.defaultView.getComputedStyle(this, "").height || "200px";
      if (/%/.test(height)) {
        height = parseInt("0" + height, 10);
        height = height / 100 * this.outerDiv.offsetHeight;
      }
      this.outerDiv.style.height = height;
      this.innerDiv.style.padding = height + " 0";
      this.innerDiv.style.whiteSpace = "";
    } else {
      this.outerDiv.style.height = "";
      this.innerDiv.style.padding = "0px";
      this.innerDiv.style.whiteSpace = "nowrap";
    }
    switch (this.directionField) {
      case "up":
        this.dirsign = 1;
        this.startAt = this.behaviorField == "alternate" ? this.originalHeight : 0;
        this.stopAt = this.innerDiv.offsetHeight - parseInt(this.outerDiv.style.height) - 
          (this.behaviorField == "alternate" ? this.originalHeight : 0);
        break;
      case "down":
        this.dirsign = -1;
        this.startAt = this.innerDiv.offsetHeight - parseInt(this.outerDiv.style.height) - 
          (this.behaviorField == "alternate" ? this.originalHeight : 0);
        this.stopAt = this.behaviorField == "alternate" ? this.originalHeight : 0;
        break;
      case "right":
        this.dirsign = -1;
        this.stopAt = this.behaviorField != "alternate" ?
          this.innerDiv.offsetLeft - this.outerDiv.offsetWidth : this.innerDiv.offsetWidth;
        this.startAt = this.outerDiv.offsetWidth +
          (this.behaviorField != "alternate" ? this.innerDiv.offsetWidth + this.stopAt : 0);
        break;
      case "left":
      default:
        this.dirsign = 1;
        this.startAt = this.behaviorField != "alternate" ?
          this.innerDiv.offsetLeft - this.outerDiv.offsetWidth : this.innerDiv.offsetWidth;
        this.stopAt = this.outerDiv.offsetWidth +
          (this.behaviorField != "alternate" ? this.innerDiv.offsetWidth + this.startAt : 0);
    }
    if (!aSkipSettingNewPosition) {
      this.newPosition = this.startAt;
    }
  }
  this.newPosition = parseInt(this.newPosition) + this.dirsign * this.scrollAmount;
  if (
     this.dirsign == 1 &&this.newPosition > this.stopAt ||
     this.dirsign == -1 && this.newPosition < this.stopAt
  ) {
    if (this.behaviorField == "alternate") {
      this.startNewDirection = true;
      const swap = {left:"right", down:"up", up:"down", right:"left"};
      this.directionField = swap[this.directionField];
    } else {
      this.newPosition = this.startAt;
    }
  }
  if (!this.startNewDirection) {
    if (this.directionField == "up" || this.directionField == "down") {
      this.outerDiv.scrollTop = this.newPosition;
    } else {
      this.outerDiv.scrollLeft = this.newPosition;
    }
  }
  var myThis = this;
  var lambda = function myTimeOutFunction() {
    myThis.start();
  };
    this.runId = window.setTimeout(lambda, this.scrollDelay);
}

function init() {
  var height;
  if (this.hasAttribute("height")) {
    height = this.getAttribute("height");
    this.outerDiv.style.height = height + "px";
  }
  this.outerDiv.style.width = this.width;
  if (this.hasAttribute("id")) {
    window[this.getAttribute("id")] = this;
  }
  if (this.hasAttribute("bgcolor")) {
    this.outerDiv.style.backgroundColor = this.getAttribute("bgcolor");
  }
  this.originalHeight = this.innerDiv.offsetHeight;
  this._doMove(false);
}

function start() {
  this._doMove(false);
}

function stop() {
  if (this.runId != 0) {
    clearTimeout(this.runId);
  }
  this.runId = 0;
}

普通にJavaScriptで実装されてる。なんかキモいことやりたくなってきたけど、時間が無いのでとりあえずここまで。