Skip to content

Instantly share code, notes, and snippets.

@jdaly13
Last active August 29, 2015 14:02
Show Gist options
  • Save jdaly13/b2367b0b231a16611280 to your computer and use it in GitHub Desktop.
Save jdaly13/b2367b0b231a16611280 to your computer and use it in GitHub Desktop.
wordgame
/* Word Game jQuery plugin
*
* @param {object} options
* @returns {settings object that override default}
* jQuery plugin
* current dependencies are jQuery ... duh
*/
(function ($) {
$.fn.WordGame = function (options) {
var $container = $(this),
defaults = {
index: 0, // this should get incremented after each correct answer ;
data: null,
dataLength: null,
testPattern: /^[a-z0-9]+$/i,
currentScore: 0,
continueOn: 'continue',
reveal: 'reveal',
view: 'view',
killBillSetTimeout: null,
socialSharing: false,
analytics: false,
userID: null,
timer: 1500,
nextLetterTimer: 1,
//Jquery DOM Objects
$wordup: $container.find('.word'), //word up
$takeActionBro: $container.find('.takeAction') || null,
$rightOrWrongDiv: $container.find('.rightOrWrong') || null,
$currentScoreDiv: $container.find('.currentScore') || null,
$sharingIsCaring: $container.find('.shaingIsCaring') || null,
$img: $container.find('.row-item-image-url img') || null,
$span: $('<span class="editable" contenteditable="true"></span>'),
$spannoneditable: $('<span contenteditable="false"></span>'),
$differentSpan: $('<span class="what"> </span>'), // !!!!!!! that space is vewy vewy impowtant !!!!!!!!!
$secondDifferentspan: $('<span class="dash">-</span>'), //don't even think of making that dash an html entity sucka!
$periodSpan: $('<span class="period">.</span>') // not sure this name is appropriate reminds me of at least one week per month with wife JD
},
i = 0,
isInitializeGameRunning = null,
flag = null, //this is used for when users keep continusosly type in the last correct letter
// google analytics
userHasStartedGame = null,
//sniff sniff
ieNineOrBelow = $('html').hasClass('lt-ie10'),
ieNineAndAbove = window.clipboardData,
iOS = /(iPad|iPhone|iPod)/g.test(navigator.userAgent),
//overide defaults with any new data passed in
settings = $.extend({}, defaults, options),
//event callbacks
focusCallBack = function () {
preAnalyticsFiltering(settings.analytics, userHasStartedGame, 'initial');
var $this = $(this);
$this.data('before', $this.text());
$this.addClass('active');
return $this;
},
keyDownCallBack = function (event) {
if (event.keyCode === 13 || event.keyCode === 32) {
event.preventDefault();
//for those morons who don't know how to play the game and want to break stuff by pressing enter //also, spacebar -dan
} else if (event.keyCode === 8) {
var length = $.trim($(this).text()).length;
if (length > 0) {
return;
}
var $this = $(this);
skiptoNextOrPrevAvailablePosition($this, true, 'previous');
}
},
keyupCallBack = function (event) { // a lot of stuff happens here
var $this = $(this);
if ($this.data('before') !== $this.text()) {
$this.data('before', $this.text());
var text = $.trim($this.text());
var length = text.length;
(length > 1) ? showOnlyFirstLetter($this, text) : '';
if (flag) return false; // set only when yougotitrightson function is executing then set to null after it's finished
skiptoNextOrPrevAvailablePosition($this, length, 'next');
var areTheyFilled = areAllLettersFilledIn($(event.delegateTarget)); // returns array or false;
var onToTheNext = makeComparison(areTheyFilled);
(onToTheNext === 'got it right') ? youGotItRightSon() : (onToTheNext === 'got it wrong') ? youGotItWrongSon() : '';
}
return $this;
},
blurCallBack = function () {
var $this = $(this);
$this.removeClass('active');
},
showMeTheBaby = function (e) { //translated show me something bro !
if ($(e.target).hasClass(settings.view)) {
goToCharacterPage();
} else {
var $this = $(this);
// we do this for those click crazy people who want to reveal answer before word is spelled out what up with that yo!
if (isInitializeGameRunning) return false;
var reveal = settings.reveal;
if ($this.hasClass(reveal)) {
iGiveUpShowMeTheWord($this);
return false;
}
if ($this.hasClass(settings.continueOn)) {
clearTimeout(settings.killBillSetTimeout);
wouldntItBeGoodToShowNextCharacter($this, reveal);
}
}
},
goToCharacterPage = function () {
preAnalyticsFiltering(settings.analytics, null, 'goToCharacter');
var link = settings.data[settings.index].page;
window.location.href = link;
},
socialSharing = function (e) {
e.preventDefault();
var message;
var img;
var url = window.location.href;
if (settings.dataLength != settings.index) {
message = "I scored " + settings.currentScore + " points on the Who Am I game on marvel.com";
img = settings.data[settings.index].img;
} else {
message = "I scored " + settings.currentScore + " points and completed the Who Am I game on marvel.com";
img = settings.data[settings.dataLength - 1].img;
}
var shareType = this.getAttribute('data-game-sharebtn');
janrain.engage.share.setTitle('Marvel Character Guessing Game');
janrain.engage.share.setImage(img);
janrain.engage.share.setDescription($("meta[name='og:description']").attr('content') || '');
janrain.engage.share.setUrl(url);
janrain.engage.share.setMessage(message);
janrain.engage.share.reset();
janrain.engage.share.showProvider(shareType);
janrain.engage.share.show();
preAnalyticsFiltering(settings.analytics, shareType, 'sharing');
};
/* Help I really need some helper functions Help! */
function preAnalyticsFiltering(analytics, gameStarted, type) {
if (!analytics || gameStarted === 'initialized') return false;
var obj = {};
var index = parseInt(settings.index) + 1;
switch (type) {
case "initial":
//first focus of game only done once
obj.type = 'event';
obj.cat = 'wordgame initialized';
obj.action = 'focus';
obj.label = 'attempting to play';
obj.value = settings.userID;
runAnalytics('event', obj);
userHasStartedGame = 'initialized';
break;
case "reveal":
// when user reveals character with click
obj.type = "event";
obj.cat = "wordgame reveal character";
obj.action = "click";
obj.label = "character name " + settings.data[settings.index].name;
obj.value = index;
runAnalytics('event', obj);
break;
case "correct":
// when user gets correct answer
obj.type = "event";
obj.cat = "wordgame points scored";
obj.action = "character guessed correctly " + settings.data[settings.index].name;
obj.label = settings.currentScore + ' points';
obj.value = index;
runAnalytics('event', obj);
break;
case "sharing":
//when user socially shares his score
obj.type = "social";
obj.socialNetwork = gameStarted; //facebook twitter or email
obj.socialAction = "sharing score " + settings.currentScore + ' points';
obj.socialTarget = "character index " + index;
runAnalytics('social', obj);
break;
case "goToCharacter":
//when user clicks on view character page
obj.type = "event";
obj.cat = "going to external character page";
obj.action = "click";
obj.label = "character name " + settings.data[settings.index].name;
obj.value = index;
runAnalytics('event', obj);
break;
default:
return false;
}
function runAnalytics(event, obj) {
if (event === 'event') {
ga('send', obj.type, obj.cat, obj.action, obj.label, obj.value);
}
if (event === 'social') {
ga('send', obj.type, obj.socialNetwork, obj.socialAction, obj.socialTarget);
}
}
}
function showOnlyFirstLetter($span, text) {
$span.text(text[0]);
}
//It was annoying me so I threw this in quickly. Could probably be simplified with skip to next but I didn't want to break -dan
function skiptoNextOrPrevAvailablePosition($that, length, nextOrPrev) {
if (length === 0 || iOS) return; //IOS go Tab yourself!
var areNextorPrevLettersInWordNotEditable = function ($elements) {
var whatToReturn = true;
$elements.each(function (i, ele) {
if ($(ele).hasClass('editable')) {
whatToReturn = false;
return false;
}
});
return whatToReturn;
};
if (nextOrPrev === 'next') {
goNext();
} else { // it's previous
goPrev();
}
function goNext() {
if ($that.next().is("[contenteditable='true']")) {
setTimeout(function () {
$that.next().focus();
}, settings.nextLetterTimer);
} else if (areNextorPrevLettersInWordNotEditable($that.nextAll())) { //go to/focus on next word
setTimeout(function () {
$that.parent('div.new').next().children("[contenteditable='true']").first().focus();
}, settings.nextLetterTimer);
} else {
setTimeout(function () {
$that.nextAll("[contenteditable='true']").first().focus();
}, settings.nextLetterTimer);
}
}
function goPrev() {
if ($that.prev().is("[contenteditable='true']")) {
setTimeout(function () {
$that.prev().focus().text('');
}, settings.nextLetterTimer);
} else if (areNextorPrevLettersInWordNotEditable($that.prevAll())) { //go to/focus on prev word
setTimeout(function () {
$that.parent('div.new').prev().children("[contenteditable='true']").last().focus().text('');
}, settings.nextLetterTimer);
} else {
setTimeout(function () {
$that.prevAll("[contenteditable='true']").first().focus().text('');
}, settings.nextLetterTimer);
}
}
}
function areAllLettersFilledIn($word) {
var $childs = $word.find('span');
var allFilled = true;
var array = [];
//specifically for IE when QA tries type a million characters per second
var doublecheckforIE = function (arr) {
var moreThanOne = false;
for (var i = 0; i < arr.length; i++) {
if (arr[i].length > 1) {
arr[i] = arr[i][0];
moreThanOne = true;
}
}
if (moreThanOne) {
$childs.each(function (i, ele) {
$(ele).text(arr[i]);
});
}
return arr;
};
$childs.each(function (i, ele) {
if ($(ele).text().length === 0) {
allFilled = false;
return false;
}
array[i] = $(this).text().toLowerCase();
});
if (allFilled) {
if (ieNineAndAbove) {
return doublecheckforIE(array);
} else {
return array;
}
} else {
showOrHideWrongButton('hide');
return false;
}
}
function makeComparison(fillCheckArr) {
if (!fillCheckArr) return false;
var doesitMatch = compareArrays(fillCheckArr, settings.data[settings.index].name);
if ( !! doesitMatch) {
return 'got it right';
} else {
return 'got it wrong';
}
}
function compareArrays(arr, string) {
var j = 0;
for (j; j < arr.length; j++) {
if (arr[j] !== string[j]) {
return false;
}
}
return true;
}
function youGotItRightSon() {
flag = true; // this is set so users don't continuosly his last letter in correct answer
showOrHideWrongButton('hide');
settings.$rightOrWrongDiv.find('span.icon-checkmark').removeClass('hide');
settings.currentScore = settings.currentScore + 10;
var $currentScoreElement = settings.$currentScoreDiv;
$currentScoreElement.addClass('turnWhite').one('transitionend webkitTransitionEnd ie9holla', function () {
$(this).removeClass('turnWhite').find('b').text(settings.currentScore);
});
if (ieNineOrBelow) { //pure politics no browser left behind
setTimeout(function () {
$currentScoreElement.trigger('ie9holla');
}, 400);
}
shortLivedContinue(settings.$takeActionBro.find('span.reveal'));
createSpecialTimeout(settings.$takeActionBro.find('span.continue'));
preAnalyticsFiltering(settings.analytics, 'null', 'correct');
}
function youGotItWrongSon() {
showOrHideWrongButton('show');
}
function showOrHideWrongButton(showOrHide) {
(showOrHide === 'hide') ? settings.$rightOrWrongDiv.find('span.icon-close').addClass('hide') : '';
(showOrHide === 'show') ? settings.$rightOrWrongDiv.find('span.icon-close').removeClass('hide') : '';
}
function iGiveUpShowMeTheWord($this) {
preAnalyticsFiltering(settings.analytics, null, 'reveal');
var $lilBreezy = settings.$wordup.find('span'); // 3/5/14 named after Fabrizio's newborn
settings.$rightOrWrongDiv.find('span.icon-close').addClass('hide');
$lilBreezy.each(function (i, ele) {
$(ele).text(settings.data[settings.index].name[i]);
});
shortLivedContinue($this);
createSpecialTimeout($this);
}
function wouldntItBeGoodToShowNextCharacter($this, text) {
settings.index++;
var endOfGame = isItendOfGame(settings.dataLength, settings.index, false);
if (endOfGame) return true;
initializeGame(true);
if (text === settings.reveal) {
$this.addClass(settings.reveal).removeClass(settings.continueOn).text('reveal character');
}
settings.$rightOrWrongDiv.find('span.icon-checkmark').addClass('hide');
//move this somewhere else
// console.log(settings.imgArray[settings.index]);
replaceImage();
flag = null;
}
function isItendOfGame(dataLength, index, easterEgg) {
if (dataLength != index) return false;
var $social = $container.find('.social');
var $easterEggHtml;
var $aleksey;
$social.addClass('absolute');
if (easterEgg) {
$aleksey = $('<div id="aleksey"><img src="http://i.annihil.us/u/prod/marvel/i/mg/4/03/537a3584440c4.png"/></div>');
$easterEggHtml = $('<div id="easter_egg"><h1 class="fadeIn one">Congratulations!</h1><h1 class="fadeIn two">You Have Completed the who am I game, Your Reward is...</h1><h1 class="fadeIn three"> our QA Manager floating in space, feel free to share your accomplishment!</h1></div>');
} else {
$easterEggHtml = $('<div id="easter_egg"><h1 class="fadeIn one">Congratulations!</h1><h1 class="fadeIn two">You Have Completed the who am I game</h1><h1 class="fadeIn three"> Please Share your score</h1></div>');
$aleksey = $('<div></div>');
}
$container.css('min-height', '380px').html($easterEggHtml).find('h1.three').one("animationend webkitAnimationEnd", function () {
$social.prependTo($container);
setTimeout(function () {
$container.find($easterEggHtml).fadeOut('slow', function () {
$aleksey.appendTo($container);
$social.prependTo($container);
});
}, 3000);
});
if (ieNineOrBelow) {
$social.prependTo($container);
}
return true;
}
function shortLivedContinue($ele) {
$ele.addClass(settings.continueOn).removeClass(settings.reveal).text(settings.continueOn);
}
function createSpecialTimeout($ele) {
settings.killBillSetTimeout = setTimeout(function () {
wouldntItBeGoodToShowNextCharacter($ele, settings.reveal);
}, settings.timer);
}
function positionElementBasedOnTextLength(iterator, arrLength) {
if (iterator > 0) return false;
//length = arrLength;
if (arrLength > 14) { // we love magic numbers because they are magical!
settings.$wordup.addClass('removeMarginTop');
} else {
settings.$wordup.removeClass('removeMarginTop');
}
}
function initializeGame(remove) {
isInitializeGameRunning = true;
if (remove) {
settings.$wordup.html('');
i = 0;
}
positionElementBasedOnTextLength(i, settings.data[settings.index].name.length);
setTimeout(function () {
var letter = settings.data[settings.index].name[i];
var ele = settings.$wordup;
if (settings.testPattern.test(letter) && (i % 3 !== 0)) {
settings.$span.clone().appendTo(ele);
} else if (settings.testPattern.test(letter) && (i % 3 === 0)) {
settings.$spannoneditable.clone().text(letter).appendTo(ele); //.hide().fadeIn();
} else if (letter === '-') {
settings.$secondDifferentspan.clone().appendTo(ele);
} else if (letter === '.') {
settings.$periodSpan.clone().appendTo(ele);
} else {
settings.$differentSpan.clone().appendTo(ele);
settings.$wordup.children('span:last-child').prevAll('span').andSelf().wrapAll("<div class='new' />");
}
i++;
if (i < settings.data[settings.index].name.length) {
initializeGame(false);
} else {
settings.$wordup.children('span:last-child').prevAll('span').andSelf().wrapAll("<div class='new' />");
settings.index >= 1 ? setTimeout(function () {
settings.$wordup.find('div.new').children("[contenteditable='true']").first().focus();
}, 300) : '';
isInitializeGameRunning = false;
}
}, 100);
}
function createEvents(sharing) {
settings.$wordup.on('focus', 'span', focusCallBack).on('keydown', 'span', keyDownCallBack).on('keyup paste input', 'span', keyupCallBack).on('blur', 'span', blurCallBack);
//chainingsaw massacre!
settings.$takeActionBro.on('click', 'span', showMeTheBaby);
//click event for reveal character or goto character page
if (sharing) $container.on('click', '[data-game-sharebtn]', socialSharing);
//sharing is caring good ole facebook and twitter sharing ur scrore lovely!
}
function ie8Madness(arr) {
for (var j = 0; j < arr.length; j++) {
arr[j].name = arr[j].name.replace(/\s+/g, '?');
}
settings.$differentSpan = $('<span class="what">?</span>');
//this is done becasue IE 8 doesn't like spaces so I replaced each space with a ? mark to keep IE 8 happy
}
function replaceImage() {
settings.$img.attr('src', settings.data[settings.index].img);
}
function hideLoader() {
$container.find('.loader').addClass('hide').next().removeClass('hide');
}
function init() {
hideLoader();
if ($('html').hasClass('lt-ie9')) ie8Madness(settings.data);
createEvents(settings.socialSharing, settings.analytics);
initializeGame();
replaceImage();
}
init();
return settings;
};
}(jQuery));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment