Seong Lee
Seong Lee

Reputation: 10520

Refactoring repeated code in javascript prototype constructor

I have a open function that once triggered, simply plays video in a dedicated panel.

This function can be triggered in two ways - one with a click and another one with a page load (window load) with url that contains a valid anchor tag.

They all work fine but some codes of the window load handler are repetitive and I'm not too sure how I can keep this DRY.

Please take a look and point me in some directions on how I can write this better. I commented in open function which is for which.

$.videoWatch.prototype = {
  init: function() {
    this.$openLinks = this.$element.find(".open");
    this.$closeLinks = this.$element.find(".close");
    this.open();
    this.close();
  },
  _getContent: function(element) {
    var $parent = element.parent(),
        id = element.attr('href').substring(1),
        title = $parent.data('title'),
        desc = $parent.data('desc');

        return {
          title: title,
          desc: desc,
          id: id
        }
  },
  open: function() {

    var self = this;

    //open theatre with window load with #hash id
    window.onload = function() {
        var hash = location.hash;

        var $a = $('a[href="' + hash + '"]'),
            content = self._getContent($a),
            $li = $a.parents("li"),
            $theatreVideo = $(".playing"),
            $theatreTitle = $(".theatre-title"),
            $theatreText = $(".theatre-text");

        $(".theatre").attr('id', content.id);
        $theatreTitle.text(content.title);
        $theatreText.text(content.desc);

        if ($theatreText.text().length >= 90) {
          $(".theatre-text").css({
            'overflow': 'hidden',
            'max-height': '90px',
          });
          $moreButton.insertAfter($theatreText);
        }

        $a.parent().addClass("active");
        $(".theatre").insertAfter($li);
        $(".theatre").slideDown('fast', scrollToTheatre);
        oldIndex = $li.index();

    }

    //open theatre with click event
    self.$openLinks.on("click", function(e) {
      // e.preventDefault();
      if (curID == $(this).parent().attr("id")) {
        $("figure").removeClass("active");
        $("button.more").remove();
        $(".theatre").slideUp('fast');
        $('.playing').attr("src", "");
        removeHash();
        oldIndex = -1;
        curID = "";
        return false
      } else {
        curID = $(this).parent().attr("id");
      }

      var $a = $(this),
          content = self._getContent($a),
          $li = $a.parents("li"),
          $theatreVideo = $(".playing"),
          $theatreTitle = $(".theatre-title"),
          $theatreText = $(".theatre-text");


      $(".theatre").attr('id', content.id);
      $theatreTitle.text(content.title);
      $theatreText.text(content.desc);

      if ($theatreText.text().length >= 90) {
          $(".theatre-text").css({
            'overflow': 'hidden',
            'max-height': '90px',
          });
          $moreButton.insertAfter($theatreText);
      }

      if (!($li.index() == oldIndex)) {
        $("figure").removeClass("active");
        $(".theatre").hide(function(){
          $a.parent().addClass("active");
          $(".theatre").insertAfter($li);
          $(".theatre").slideDown('fast', scrollToTheatre);
          oldIndex = $li.index();
        });
      } else {
        $(".theatre").insertAfter($li); 
        scrollToTheatre();
        $("figure").removeClass("active");
        $a.parent().addClass("active");
      } 
    });
  },

  ...

Upvotes: 0

Views: 58

Answers (2)

RomanPerekhrest
RomanPerekhrest

Reputation: 92854

Simplified and refactored open method:

open: function() {

    var self = this;
    var serviceObj = {
        theatreVideo : $(".playing"),
        theatre: $(".theatre"),
        theatreTitle : $(".theatre-title"),
        theatreText : $(".theatre-text"),
        setTheatreContent: function(content){
            this.theatre.attr('id', content.id);
            this.theatreTitle.text(content.title);
            this.theatreText.text(content.desc);

            if (this.theatreText.text().length >= 90) {
               this.theatreText.css({
                   'overflow': 'hidden',
                   'max-height': '90px',
               });
               $moreButton.insertAfter(this.theatreText);
            }
        },
      activateTeatre: function(a, li){
          a.parent().addClass("active");
          this.theatre.insertAfter(li);
          this.theatre.slideDown('fast', scrollToTheatre);
          oldIndex = li.index();
      }

    };

    //open theatre with window load with #hash id
    window.onload = function() {
        var hash = location.hash;
        var $a = $('a[href="' + hash + '"]'),
            content = self._getContent($a),
            $li = $a.parents("li");

       serviceObj.setTheatreContent(content);
       serviceObj.activateTeatre($a, $li);

    }

    //open theatre with click event
    self.$openLinks.on("click", function(e) {
      // e.preventDefault();
      if (curID == $(this).parent().attr("id")) {
        $("figure").removeClass("active");
        $("button.more").remove();
        $(".theatre").slideUp('fast');
        $('.playing').attr("src", "");
        removeHash();
        oldIndex = -1;
        curID = "";
        return false
      } else {
        curID = $(this).parent().attr("id");
      }

      var $a = $(this),
          content = self._getContent($a),
          $li = $a.parents("li");

      serviceObj.setTheatreContent(content);

      if (!($li.index() == oldIndex)) {
        $("figure").removeClass("active");
        $(".theatre").hide(function(){
          serviceObj.activateTeatre($a, $li);
        });
      } else {
        $(".theatre").insertAfter($li); 
        scrollToTheatre();
        $("figure").removeClass("active");
        $a.parent().addClass("active");
      } 
    });
  },

Upvotes: 1

Gavriel
Gavriel

Reputation: 19237

1st of all there are variables that don't depend on the input, you could pull them to the class (I'll show just one example, as you asked for directions):

init: function() {
  this.$theatreVideo = $(".playing");

All the variables that do depend on the input, like $li could be moved to a function:

  var $a = $(this),
      $dependsOnA = self.dependsOnA($a);
  self.actionDependsOnA($dependsOnA); // see below



function dependsOnA($a) {
    return {
      a: $a,
      li: $a.parents("li"),
      content: self._getContent($a)
    }
}

Also the code that "repeats" can be moved to a function:

function actionDependsOnA($dependsOnA)
    $(".theatre").attr('id', $dependsOnA.content.id);
    $theatreTitle.text($dependsOnA.content.title);
    $theatreText.text($dependsOnA.content.desc);
}

Upvotes: 1

Related Questions