8
\$\begingroup\$

The following code is complete and works perfectly. What I want to do to is make it more modular in a way where I can use the code again - similar to an api. I also hardly ever code in javascript, and I think my code looks disgusting, I feel like there are cleaner ways to write what I've written but I just don't have enough knowledge yet. If anyone has some advice/suggestion that would be appreciated.

The purpose of the module is to give the effect of a sentence being typed, then being backspaced out one character at a time. Here is a demo on my site: meneliktucker.me.

There are four main values to set:

  1. sentences() - which is an array of sentences to be written out.
  2. pause_sentence_time - the amount of time the sentence will pause after be written out - so the user can read the sentence before the sentence is deleted.
  3. write_time - the time in ms to print a character
  4. delete_time - the time in ms to delete a character

var delete_characters, delete_time, loop_characters,
loop_sentences, pause_sentence_time, print_char, sentences,
str_distance, write_time;

pause_sentence_time = 750;
write_time = 60;
delete_time = 40;

sentences = function() {
  var all_sentences;
  return all_sentences = ['is a student at the uOttawa.',
                       'loves to build things.'];
};

window.automatic_typing = function() {
  var char_array;
  char_array = sentences()[0].split('');
  loop_characters(char_array, 0, 0);
};

loop_sentences = function(prev_index) {
  var char_array, char_index, current_index;
  current_index = (prev_index + 1) % sentences().length;
  char_index = str_distance(prev_index);
  char_array = sentences()[current_index].split('');
  loop_characters(char_array, char_index, current_index);
};

loop_characters = function(char_array, char_index, index) {
  var timer;
  timer = 60;
  if (char_index === char_array.length) {
    timer = 750;
  }
  setTimeout((function() {
    if (char_index === char_array.length) {
      return delete_characters(index, str_distance(index));
    }
  print_char(char_array[char_index++]);
  loop_characters(char_array, char_index, index);
  }), timer);
};

print_char = function(c) {
  $('.automatic-typing').append(c);
};

delete_characters = function(index, dist) {
  setTimeout((function() {
    var temp;
    temp = $('.automatic-typing').text();
    if (temp.length === dist) {
      return loop_sentences(index);
    }
    $('.automatic-typing').text(temp.slice(0, temp.length - 1));
    delete_characters(index, dist);
  }), 40);
};

//The purpose of this function is to count the number of letters that
//the current and next sentence share from the start of both sentences.
//ex. the distance between 'this is cool' and 'this is not cool' is 7.

str_distance = function(index) {
  var counter, i, next_index, next_str_array, str_array, _i, _ref;
  str_array = sentences()[index].split('');
  next_index = index + 1;
  next_str_array = sentences()[next_index % sentences().length].split('');
  counter = 0;
  for (i = _i = 0, _ref = str_array.length; _i <= _ref; i = _i += 1) {
    if (str_array[i] === next_str_array[i]) {
      counter++;
    } else {
      break;
    }
  }
  if (str_array[counter] !== " " && counter !== 0) {
    while (true) {
      if (str_array[--counter] === " ") {
        break;
      }
    }
  }
  return counter;
};
\$\endgroup\$
3
\$\begingroup\$

Here is an update of what I've done:

I decided to make the code I provided earlier into a jQuery plugin. I reviewed jQuery plugins that I've used in the past then re-designed my code the JavaScript way. By using common feature in the JavaScript language such as the call method and utilizing object properties and prototypes.

I wrote it so you can call this jQuery plugin by simply entering in the element you want to have the effect apply to and then inputting your own customized values for the pause time, write time, delete time and sentence array.

Here is a sample of how to do that:

  $('.automatic-typing').automaticTyping({
    writeTime   :  60,
    deleteTime  :  40,
    pauseTime   :  750,
    sentences   : ['Enter in a sentence here',
                  'Another here', 
                  '... As many as you want.'
                   ]
  });

Here is the re-designed code:

(function($) {
  "use strict";
  var methods = {
    init: function(options){

      options = $.extend({
        writeTime         :   60,
        deleteTime        :   60,
        pauseTime         :   1000,
        sentences         :   [
       'if you are seeing this',
       'you have not set your own values'
        ],
        charArray         :   [], //do not set this value and values below this point
        sentencesIndex    :   0,  
        charIndex         :   0,
        distance          :   0   
      }, options);

      this.each(function(){

        options = $.extend(true, {}, options); //deep copy the options object for every element
        options.charArray = options.sentences[0].split("");
        methods.loopCharacters.call(this, options);

      });

    },

    loopSentences: function(options){

      options.sentencesIndex = (options.sentencesIndex + 1) % options.sentences.length;
      options.charIndex = options.distance;
      options.charArray = options.sentences[options.sentencesIndex].split("");
      methods.loopCharacters.call(this, options);

    },

    loopCharacters: function(options){

      var i = options.charIndex;
      var len = options.charArray.length;
      var timer = options.writeTime;

      if (i === len) {
        timer = options.pauseTime;
      }

      setTimeout((function() {
        if (i === len) {
          methods.setDistance.call(this, options);
          return methods.deleteCharacters.call(this, options);
        }

        $(this).append(options.charArray[options.charIndex]);
        options.charIndex++;
        methods.loopCharacters.call(this, options);

      }).bind(this), timer);

    },

    deleteCharacters: function(options){

      setTimeout((function() {
        var currentSentence = $(this).text();

        if (currentSentence.length === options.distance) {
          return methods.loopSentences.call(this, options);
        }

        $(this).text(currentSentence.slice(0, currentSentence.length - 1));
        methods.deleteCharacters.call(this, options);

      }).bind(this), options.deleteTime);

    },

    setDistance: function(options){

      var nextSentenceIndex = options.sentencesIndex + 1;
      var cArr = options.charArray;
      var nextcArr = options.sentences[nextSentenceIndex % options.sentences.length].split('');
      var counter = 0;

      for (var i = 0; i <= cArr.length; i++) {
        if (cArr[i] === nextcArr[i]) {
      counter++;
        } else { break; }
      }

      if (cArr[counter] !== " " && counter !== 0) {
        while (true) { 
      if (cArr[--counter] === " ") { break; } 
        }
      }

      options.distance = counter;
    }

  };

  $.fn.automaticTyping = function(method){

    if ( typeof method === 'object' ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.');
    }

  };

})(jQuery);
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.