diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9c5f108
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.project
+node_modules
+bower_components
\ No newline at end of file
diff --git a/Gruntfile.js b/Gruntfile.js
new file mode 100644
index 0000000..59834cf
--- /dev/null
+++ b/Gruntfile.js
@@ -0,0 +1,96 @@
+/*global module:false*/
+module.exports = function (grunt) {
+
+ // Project configuration.
+ grunt.initConfig({
+ // Metadata.
+ pkg: grunt.file.readJSON('package.json'),
+ banner: '/*! jquery.typer.js <%= pkg.version %>- <%= grunt.template.today("yyyy-mm-dd") %> */\n',
+ // Task configuration.
+ concat: {
+ options: {
+ banner: '<%= banner %>',
+ stripBanners: true
+ },
+ dist: {
+ src: ['src/jquery.typer.js'],
+ dest: 'dist/jquery.typer.js'
+ }
+ },
+ uglify: {
+ options: {
+ banner: '<%= banner %>'
+ },
+ dist: {
+ src: '<%= concat.dist.dest %>',
+ dest: 'dist/jquery.typer.min.js'
+ }
+ },
+ copy: {
+ dist: {
+ src:'src/jquery.typer.js',
+ dest: 'dist/jquery.typer.js'
+ }
+ },
+ jshint: {
+ options: {
+ curly: true,
+ eqeqeq: true,
+ immed: true,
+ latedef: true,
+ newcap: true,
+ noarg: true,
+ sub: true,
+ undef: true,
+ unused: true,
+ boss: true,
+ eqnull: true,
+ browser: true,
+ globals: {
+ jQuery: true
+ }
+ },
+ gruntfile: {
+ src: 'Gruntfile.js'
+ },
+ dist: {
+ options: {
+ curly: true,
+ eqeqeq: true,
+ immed: true,
+ latedef: true,
+ newcap: true,
+ noarg: true,
+ sub: true,
+ undef: true,
+ unused: true,
+ boss: true,
+ eqnull: true,
+ browser: true,
+ globals: {
+ jQuery: true,
+ console: true
+ }
+ },
+ src: 'src/jquery.typer.js'
+ }
+ },
+ watch: {
+ gruntfile: {
+ files: '<%= jshint.gruntfile.src %>',
+ tasks: ['jshint:gruntfile']
+ }
+ }
+ });
+
+ // These plugins provide necessary tasks.
+ grunt.loadNpmTasks('grunt-contrib-concat');
+ grunt.loadNpmTasks('grunt-contrib-uglify');
+ grunt.loadNpmTasks('grunt-contrib-jshint');
+ grunt.loadNpmTasks('grunt-contrib-watch');
+ grunt.loadNpmTasks('grunt-contrib-copy');
+
+ // Default task.
+ grunt.registerTask('dist', ['jshint:dist', 'concat:dist', 'uglify:dist', 'copy:dist']);
+
+};
diff --git a/README.md b/README.md
index 3be0145..111501a 100644
--- a/README.md
+++ b/README.md
@@ -36,6 +36,8 @@ There are some options that are available to you as well:
typeDelay : 200,
clearOnHighlight : true,
typerDataAttr : 'data-typer-targets',
+ tapeColor : 'auto' // 'auto' or a css color value
+ typerOrder : 'random', // or 'sequential'
typerInterval : 2000
}
```
@@ -45,6 +47,11 @@ Set the options individually:
```javascript
$.typer.options.highlightSpeed = 500;
```
+
+## Contributing
+
+Make your changes on `src/jquery.typer.js`. To generate updated minified distribution versions run `$ grunt dist`.
+
## About
jquery.typer.js was originally developed for [LayerVault](http://layervault.com) by [Kelly Sutton](http://kellysutton.com).
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..53d44af
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,29 @@
+{
+ "name": "jquery-typer",
+ "version": "1.0.0",
+ "homepage": "https://github.com/kontur/jquery.typer.js",
+ "authors": [
+ "Various",
+ "check github repo"
+ ],
+ "description": "JQuery plugin for typing out text",
+ "main": "./src/jquery.typer.js",
+ "keywords": [
+ "JQuery",
+ "plugin",
+ "text",
+ "typewriter"
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "jquery": ">=1.11.0"
+ },
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "bower_components",
+ "app/bower_components",
+ "test",
+ "tests"
+ ]
+}
diff --git a/dist/jquery.typer.js b/dist/jquery.typer.js
new file mode 100644
index 0000000..6ce6513
--- /dev/null
+++ b/dist/jquery.typer.js
@@ -0,0 +1,285 @@
+String.prototype.rightChars = function(n){
+ if (n <= 0) {
+ return "";
+ }
+ else if (n > this.length) {
+ return this;
+ }
+ else {
+ return this.substring(this.length, this.length - n);
+ }
+};
+
+(function($) {
+ var opts,
+ highlight,
+ clearText,
+ type,
+ spanWithColor,
+ clearDelay,
+ typeDelay,
+ clearData,
+ isNumber,
+ typeWithAttribute,
+ getHighlightInterval,
+ getTypeInterval,
+ intervalHandle,
+ typerInterval;
+
+
+ spanWithColor = function(color, backgroundColor) {
+ return $('')
+ .css('color', color)
+ .css('background-color', backgroundColor);
+ };
+
+ isNumber = function (n) {
+ return !isNaN(parseFloat(n)) && isFinite(n);
+ };
+
+ clearData = function ($e) {
+ $e.removeData([
+ 'typePosition',
+ 'highlightPosition',
+ 'leftStop',
+ 'rightStop',
+ 'primaryColor',
+ 'backgroundColor',
+ 'text',
+ 'typing'
+ ]);
+ };
+
+ type = function ($e) {
+ var
+ // position = $e.data('typePosition'),
+ text = $e.data('text'),
+ oldLeft = $e.data('oldLeft'),
+ oldRight = $e.data('oldRight');
+
+ // if (!isNumber(position)) {
+ // position = $e.data('leftStop');
+ // }
+
+ if (!text || text.length === 0) {
+ clearData($e);
+ return;
+ }
+
+ $e.text(
+ oldLeft +
+ text.charAt(0) +
+ oldRight
+ ).data({
+ oldLeft: oldLeft + text.charAt(0),
+ text: text.substring(1)
+ });
+
+ // $e.text($e.text() + text.substring(position, position + 1));
+
+ // $e.data('typePosition', position + 1);
+
+ setTimeout(function () {
+ type($e);
+ }, getTypeInterval());
+ };
+
+ clearText = function ($e) {
+ $e.find('span').remove();
+
+ setTimeout(function () {
+ type($e);
+ }, typeDelay());
+ };
+
+ highlight = function ($e) {
+ var
+ position = $e.data('highlightPosition'),
+ leftText,
+ highlightedText,
+ rightText,
+ options = $e.data('options');
+
+ if (!isNumber(position)) {
+ position = $e.data('rightStop') + 1;
+ }
+
+ if (position <= $e.data('leftStop')) {
+ setTimeout(function () {
+ clearText($e);
+ }, clearDelay());
+ return;
+ }
+
+ leftText = $e.text().substring(0, position - 1);
+ highlightedText = $e.text().substring(position - 1, $e.data('rightStop') + 1);
+ rightText = $e.text().substring($e.data('rightStop') + 1);
+
+ $e.html(leftText)
+ .append(
+ spanWithColor(
+ options.highlightColor === 'auto' ? $e.css('background-color') : options.highlightColor,
+ options.backgroundColor === 'auto' ? $e.css('color') : options.backgroundColor
+ )
+ .append(highlightedText)
+ )
+ .append(rightText);
+
+ $e.data('highlightPosition', position - 1);
+
+ setTimeout(function () {
+ return highlight($e);
+ }, getHighlightInterval());
+ };
+
+ typeWithAttribute = (function () {
+ var last = 0;
+
+ return function($e) {
+ var targets;
+ var options = $e.data('options');
+
+ if ($e.data('typing')) {
+ return;
+ }
+
+ try {
+ targets = JSON.parse($e.attr(options.typerDataAttr)).targets;
+ } catch (e) {}
+
+ if (typeof targets === "undefined") {
+ targets = $.map($e.attr(options.typerDataAttr).split(','), function (e) {
+ return $.trim(e);
+ });
+ }
+
+ if (options.typerOrder === 'random') {
+ $e.typeTo(targets[Math.floor(Math.random()*targets.length)]);
+ }
+ else if (options.typerOrder === 'sequential') {
+ $e.typeTo(targets[last]);
+ last = (last < targets.length - 1) ? last + 1 : 0;
+ }
+ else {
+ console.error("Type order of '" + options.typerOrder + "' not supported");
+ clearInterval(intervalHandle);
+ }
+ };
+ })();
+
+ //-- Methods to attach to jQuery sets
+
+ $.fn.typer = function(options) {
+ var $elements = $(this);
+
+ if ($elements.length < 1) {
+ return;
+ }
+
+ opts = jQuery.extend({}, $.fn.typer.defaults, options);
+
+ return $elements.each(function () {
+ var $e = $(this);
+ $e.data('options', opts);
+
+ if (typeof $e.attr(opts.typerDataAttr) === "undefined") {
+ return;
+ }
+
+ typeWithAttribute($e);
+ intervalHandle = setInterval(function () {
+ typeWithAttribute($e);
+ }, typerInterval());
+ });
+ };
+
+ $.fn.typeTo = function (newString, options) {
+ var
+ $e = $(this),
+ currentText = $e.text(),
+ i = 0,
+ j = 0,
+ opts = jQuery.extend({}, $.fn.typer.defaults, options, $e.data('options'));
+
+ if (currentText === newString) {
+ if (opts.debug === true) {
+ console.log("Our strings our equal, nothing to type");
+ }
+ return $e;
+ }
+
+ if (currentText !== $e.html()) {
+ if (opts.debug === true) {
+ console.error("Typer does not work on elements with child elements.");
+ }
+ return $e;
+ }
+
+ $e.data('typing', true);
+
+ if (opts.highlightEverything !== true) {
+ while (currentText.charAt(i) === newString.charAt(i)) {
+ i++;
+ }
+
+ while (currentText.rightChars(j) === newString.rightChars(j)) {
+ j++;
+ }
+ }
+
+ newString = newString.substring(i, newString.length - j + 1);
+
+ $e.data({
+ options: opts,
+ oldLeft: currentText.substring(0, i),
+ oldRight: currentText.rightChars(j - 1),
+ leftStop: i,
+ rightStop: currentText.length - j,
+ //primaryColor: opts.backgroundColor === 'auto' ? $e.data('primaryColor') : opts.backgroundColor,
+ //backgroundColor: $e.css('background-color'),
+ text: newString
+ });
+
+ highlight($e);
+
+ return $e;
+ };
+
+ //-- Helper methods. These can one day be customized further to include things like ranges of delays.
+
+ getHighlightInterval = function () {
+ return opts.highlightSpeed;
+ };
+
+ getTypeInterval = function () {
+ return opts.typeSpeed;
+ };
+
+ clearDelay = function () {
+ return opts.clearDelay;
+ };
+
+ typeDelay = function () {
+ return opts.typeDelay;
+ };
+
+ typerInterval = function () {
+ return opts.typerInterval;
+ };
+
+ $.fn.typer.defaults = {
+ highlightSpeed : 20,
+ typeSpeed : 100,
+ clearDelay : 500,
+ typeDelay : 200,
+ clearOnHighlight : true,
+ highlightEverything : true,
+ typerDataAttr : 'data-typer-targets',
+ typerInterval : 2000,
+ debug : false,
+ backgroundColor : 'auto',
+ highlightColor : 'auto',
+ typerOrder : 'random'
+ };
+
+})(jQuery);
diff --git a/dist/jquery.typer.min.js b/dist/jquery.typer.min.js
new file mode 100644
index 0000000..9780bf8
--- /dev/null
+++ b/dist/jquery.typer.min.js
@@ -0,0 +1,2 @@
+/*! jquery.typer.js 1.0.0- 2015-03-29 */
+String.prototype.rightChars=function(a){return 0>=a?"":a>this.length?this:this.substring(this.length,this.length-a)},function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o;f=function(b,c){return a("").css("color",b).css("background-color",c)},j=function(a){return!isNaN(parseFloat(a))&&isFinite(a)},i=function(a){a.removeData(["typePosition","highlightPosition","leftStop","rightStop","primaryColor","backgroundColor","text","typing"])},e=function(a){var b=a.data("text"),c=a.data("oldLeft"),d=a.data("oldRight");return b&&0!==b.length?(a.text(c+b.charAt(0)+d).data({oldLeft:c+b.charAt(0),text:b.substring(1)}),void setTimeout(function(){e(a)},m())):void i(a)},d=function(a){a.find("span").remove(),setTimeout(function(){e(a)},h())},c=function(a){var b,e,h,i=a.data("highlightPosition"),k=a.data("options");return j(i)||(i=a.data("rightStop")+1),i<=a.data("leftStop")?void setTimeout(function(){d(a)},g()):(b=a.text().substring(0,i-1),e=a.text().substring(i-1,a.data("rightStop")+1),h=a.text().substring(a.data("rightStop")+1),a.html(b).append(f("auto"===k.highlightColor?a.css("background-color"):k.highlightColor,"auto"===k.backgroundColor?a.css("color"):k.backgroundColor).append(e)).append(h),a.data("highlightPosition",i-1),void setTimeout(function(){return c(a)},l()))},k=function(){var b=0;return function(c){var d,e=c.data("options");if(!c.data("typing")){try{d=JSON.parse(c.attr(e.typerDataAttr)).targets}catch(f){}"undefined"==typeof d&&(d=a.map(c.attr(e.typerDataAttr).split(","),function(b){return a.trim(b)})),"random"===e.typerOrder?c.typeTo(d[Math.floor(Math.random()*d.length)]):"sequential"===e.typerOrder?(c.typeTo(d[b]),b=b",
+ "bugs": {
+ "url": "https://github.com/kontur/jquery.typer.js/issues"
+ },
+ "homepage": "https://github.com/kontur/jquery.typer.js"
+}
diff --git a/src/jquery.typer.js b/src/jquery.typer.js
index d1520cc..6ce6513 100644
--- a/src/jquery.typer.js
+++ b/src/jquery.typer.js
@@ -11,35 +11,23 @@ String.prototype.rightChars = function(n){
};
(function($) {
- var
- options = {
- highlightSpeed : 20,
- typeSpeed : 100,
- clearDelay : 500,
- typeDelay : 200,
- clearOnHighlight : true,
- typerDataAttr : 'data-typer-targets',
- typerInterval : 2000
- },
- highlight,
- clearText,
- backspace,
- type,
- spanWithColor,
- clearDelay,
- typeDelay,
- clearData,
- isNumber,
- typeWithAttribute,
- getHighlightInterval,
- getTypeInterval,
- typerInterval;
+ var opts,
+ highlight,
+ clearText,
+ type,
+ spanWithColor,
+ clearDelay,
+ typeDelay,
+ clearData,
+ isNumber,
+ typeWithAttribute,
+ getHighlightInterval,
+ getTypeInterval,
+ intervalHandle,
+ typerInterval;
- spanWithColor = function(color, backgroundColor) {
- if (color === 'rgba(0, 0, 0, 0)') {
- color = 'rgb(255, 255, 255)';
- }
+ spanWithColor = function(color, backgroundColor) {
return $('')
.css('color', color)
.css('background-color', backgroundColor);
@@ -78,7 +66,6 @@ String.prototype.rightChars = function(n){
return;
}
-
$e.text(
oldLeft +
text.charAt(0) +
@@ -110,7 +97,8 @@ String.prototype.rightChars = function(n){
position = $e.data('highlightPosition'),
leftText,
highlightedText,
- rightText;
+ rightText,
+ options = $e.data('options');
if (!isNumber(position)) {
position = $e.data('rightStop') + 1;
@@ -130,8 +118,8 @@ String.prototype.rightChars = function(n){
$e.html(leftText)
.append(
spanWithColor(
- $e.data('backgroundColor'),
- $e.data('primaryColor')
+ options.highlightColor === 'auto' ? $e.css('background-color') : options.highlightColor,
+ options.backgroundColor === 'auto' ? $e.css('color') : options.backgroundColor
)
.append(highlightedText)
)
@@ -144,90 +132,111 @@ String.prototype.rightChars = function(n){
}, getHighlightInterval());
};
- typeWithAttribute = function ($e) {
- var targets;
+ typeWithAttribute = (function () {
+ var last = 0;
- if ($e.data('typing')) {
- return;
- }
+ return function($e) {
+ var targets;
+ var options = $e.data('options');
- try {
- targets = JSON.parse($e.attr($.typer.options.typerDataAttr)).targets;
- } catch (e) {}
+ if ($e.data('typing')) {
+ return;
+ }
- if (typeof targets === "undefined") {
- targets = $.map($e.attr($.typer.options.typerDataAttr).split(','), function (e) {
- return $.trim(e);
- });
- }
+ try {
+ targets = JSON.parse($e.attr(options.typerDataAttr)).targets;
+ } catch (e) {}
- $e.typeTo(targets[Math.floor(Math.random()*targets.length)]);
- };
+ if (typeof targets === "undefined") {
+ targets = $.map($e.attr(options.typerDataAttr).split(','), function (e) {
+ return $.trim(e);
+ });
+ }
- // Expose our options to the world.
- $.typer = (function () {
- return { options: options };
+ if (options.typerOrder === 'random') {
+ $e.typeTo(targets[Math.floor(Math.random()*targets.length)]);
+ }
+ else if (options.typerOrder === 'sequential') {
+ $e.typeTo(targets[last]);
+ last = (last < targets.length - 1) ? last + 1 : 0;
+ }
+ else {
+ console.error("Type order of '" + options.typerOrder + "' not supported");
+ clearInterval(intervalHandle);
+ }
+ };
})();
- $.extend($.typer, {
- options: options
- });
-
//-- Methods to attach to jQuery sets
- $.fn.typer = function() {
+ $.fn.typer = function(options) {
var $elements = $(this);
+ if ($elements.length < 1) {
+ return;
+ }
+
+ opts = jQuery.extend({}, $.fn.typer.defaults, options);
+
return $elements.each(function () {
var $e = $(this);
+ $e.data('options', opts);
- if (typeof $e.attr($.typer.options.typerDataAttr) === "undefined") {
+ if (typeof $e.attr(opts.typerDataAttr) === "undefined") {
return;
}
typeWithAttribute($e);
- setInterval(function () {
+ intervalHandle = setInterval(function () {
typeWithAttribute($e);
}, typerInterval());
});
};
- $.fn.typeTo = function (newString) {
+ $.fn.typeTo = function (newString, options) {
var
$e = $(this),
currentText = $e.text(),
i = 0,
- j = 0;
+ j = 0,
+ opts = jQuery.extend({}, $.fn.typer.defaults, options, $e.data('options'));
if (currentText === newString) {
- console.log("Our strings our equal, nothing to type");
+ if (opts.debug === true) {
+ console.log("Our strings our equal, nothing to type");
+ }
return $e;
}
if (currentText !== $e.html()) {
- console.error("Typer does not work on elements with child elements.");
+ if (opts.debug === true) {
+ console.error("Typer does not work on elements with child elements.");
+ }
return $e;
}
$e.data('typing', true);
- while (currentText.charAt(i) === newString.charAt(i)) {
- i++;
- }
+ if (opts.highlightEverything !== true) {
+ while (currentText.charAt(i) === newString.charAt(i)) {
+ i++;
+ }
- while (currentText.rightChars(j) === newString.rightChars(j)) {
- j++;
+ while (currentText.rightChars(j) === newString.rightChars(j)) {
+ j++;
+ }
}
newString = newString.substring(i, newString.length - j + 1);
$e.data({
+ options: opts,
oldLeft: currentText.substring(0, i),
oldRight: currentText.rightChars(j - 1),
leftStop: i,
rightStop: currentText.length - j,
- primaryColor: $e.css('color'),
- backgroundColor: $e.css('background-color'),
+ //primaryColor: opts.backgroundColor === 'auto' ? $e.data('primaryColor') : opts.backgroundColor,
+ //backgroundColor: $e.css('background-color'),
text: newString
});
@@ -239,22 +248,38 @@ String.prototype.rightChars = function(n){
//-- Helper methods. These can one day be customized further to include things like ranges of delays.
getHighlightInterval = function () {
- return $.typer.options.highlightSpeed;
+ return opts.highlightSpeed;
};
getTypeInterval = function () {
- return $.typer.options.typeSpeed;
- },
+ return opts.typeSpeed;
+ };
clearDelay = function () {
- return $.typer.options.clearDelay;
- },
+ return opts.clearDelay;
+ };
typeDelay = function () {
- return $.typer.options.typeDelay;
+ return opts.typeDelay;
};
typerInterval = function () {
- return $.typer.options.typerInterval;
+ return opts.typerInterval;
};
+
+ $.fn.typer.defaults = {
+ highlightSpeed : 20,
+ typeSpeed : 100,
+ clearDelay : 500,
+ typeDelay : 200,
+ clearOnHighlight : true,
+ highlightEverything : true,
+ typerDataAttr : 'data-typer-targets',
+ typerInterval : 2000,
+ debug : false,
+ backgroundColor : 'auto',
+ highlightColor : 'auto',
+ typerOrder : 'random'
+ };
+
})(jQuery);
diff --git a/test.html b/test.html
index a9311f0..37c0a8f 100644
--- a/test.html
+++ b/test.html
@@ -1,20 +1,204 @@
+ jquery.typer.js test page
-
-
+
+
+
- Hello, World!
- Welcome
+Typer testing and samples!
+
+
+
+
Default with data-typer-targets
+
+
Welcome
+
+
+
+
+
+
Default, automatically using the element's text color as highlightColor
+
$("#element").typer();
+
+
Hello World!
+
+
+
+
+
+
Default, automatically using the element's text color as highlightColor
+
$("#element").typer();
+
+
Hello World!
+
+
+
+
+
+
With option backgroundColor
+
$("#element").typer({
+ backgroundColor: 'orange'
+});
+
+
+
Hello World!
+
+
+
+
+
+
With option highlightColor
+
$("#element").typer({
+ highlightColor: 'orange'
+});
+
+
+
Hello World!
+
+
+
+
+
+
With option highlightColor and backgroundColor combined
+
$("#element").typer({
+ highlightColor: 'orange',
+ backgroundColor: 'purple'
+});
+
+
Hello World!
+
+
+
+
+
+
With option random
+
Randomize the strings in data-typer-targets="lorem,ipsum,dol,solor"
+
$("#element").typer({
+ typerOrder: 'random'
+});
+
+
Hello World!
+
+
+
+
+
+
With option sequential
+
Type the strings in data-typer-targets="lorem,ipsum,dol,solor" in sequence
+
$("#element").typer({
+ typerOrder: 'sequential'
+});
+
+
Hello World!
+
+
+
+
+
+
Using .typeTo()
+
$("#element").typeTo("Hello Typer!");
+
+
+
+
- Welcome
-