/*
* Copyright (c) 2012, Andy Janata
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Card objects. There is a base class, and individual classes for White and Black cards. This could
* probably stand to be split up into 3 files.
*
* @author Andy Janata (ajanata@socialgamer.net)
*/
cah.card = {};
/**
* Serial number to use in card div IDs. This possibly isn't needed.
*
* @type {Number}
*/
cah.card.serial = 0;
/**
* Base class for cards.
*
* @param {boolean}
* opt_faceUp True if this card is initially face-up.
* @param {number}
* opt_id The id of this card, for server communication purposes.
* @constructor
*/
cah.card.BaseCard = function(opt_faceUp, opt_id) {
/**
* The id to use for html elements for this card.
*
* @type {number}
* @protected
*/
this.id_ = cah.card.serial++;
/**
* The id of this card, for server communication purposes.
*
* @type {?number}
* @protected
*/
this.serverId_ = opt_id;
/**
* Whether this card is currently face-up.
*
* @type {boolean}
* @protected
*/
this.faceUp_ = !!opt_faceUp;
/**
* Element for face-down version of this card. Lazily loaded.
*
* @type {HTMLDivElement}
* @protected
*/
this.faceDownElem_ = undefined;
/**
* Element for face-up version of this card. Lazily loaded.
*
* @type {HTMLDivElement}
* @protected
*/
this.faceUpElem_ = undefined;
this.element_ = $('
')[0];
if (this.faceUp_) {
this.turnFaceUp();
} else {
this.turnFaceDown();
}
};
/**
* Replaces this card with its face-up version. If no text has been set on this card, it will need
* to be set!
*/
cah.card.BaseCard.prototype.turnFaceUp = function() {
this.ensureFaceUpElement_();
$(this.element_).empty().append(this.faceUpElem_);
this.faceUp_ = true;
};
/**
* Replaces this card with its face-down version. If text has been set on this card, it will still
* be resident in the object, but the user would have seen the card face-up already anyway.
*/
cah.card.BaseCard.prototype.turnFaceDown = function() {
this.ensureFaceDownElement_();
$(this.element_).empty().append(this.faceDownElem_);
this.faceUp_ = false;
};
/**
* Get the face-down version of this card.
*
* @protected
* @abstract
* @returns {HTMLDivElement} Face-down card element.
*/
cah.card.BaseCard.prototype.getFaceDown_ = function() {
throw "Abstract method invoked.";
};
/**
* Get the face-up version of this card.
*
* @protected
* @abstract
* @returns {HTMLDivElement} Face-up card element.
*/
cah.card.BaseCard.prototype.getFaceUp_ = function() {
throw "Abstract method invoked.";
};
/**
* Set the visible text on a card. It matters not if the card is face-up or face-down. HTML is
* allowed and entities are required.
*
* @param {string}
* text HTML to display on the card.
*/
cah.card.BaseCard.prototype.setText = function(text) {
this.ensureFaceUpElement_();
$(".card_text", this.faceUpElem_).html(text);
// TODO do this better
$(".card_text", this.faceUpElem_).attr(
"aria-label",
text.replace("____", "blank").replace("™", "").replace("®", "").replace("&",
"and"));
};
/**
* Gets the screen reader text from this card.
*/
cah.card.BaseCard.prototype.getAriaText = function() {
return $(".card_text", this.faceUpElem_).attr("aria-label");
};
/**
* Set the "watermark" on the logo on the card. It matters not if the card is face-up or face-down.
*
* @param {String}
* watermark Watermark to display on the card.
*/
cah.card.BaseCard.prototype.setWatermark = function(watermark) {
this.ensureFaceUpElement_();
$(".watermark", this.faceUpElem_).text(watermark);
};
/**
* Ensure this card has a face-up element, creating one if needed.
*
* @private
*/
cah.card.BaseCard.prototype.ensureFaceUpElement_ = function() {
if (!this.faceUpElem_) {
this.faceUpElem_ = this.getFaceUp_();
// TODO move the logo stuff out to static css instead of doing it for every card...
$(".logo_1", this.faceUpElem_).animate({
rotate : "-13deg",
}, {
duration : 0,
queue : false,
});
$(".logo_3", this.faceUpElem_).animate({
rotate : "13deg",
}, {
duration : 0,
queue : false,
});
}
};
/**
* Ensure this card has a face-down element, creating one if needed.
*
* @private
*/
cah.card.BaseCard.prototype.ensureFaceDownElement_ = function() {
if (!this.faceDownElem_) {
this.faceDownElem_ = this.getFaceDown_();
}
};
/**
* @return {?number} The server ID of this card, if one was specified at creation.
*/
cah.card.BaseCard.prototype.getServerId = function() {
return this.serverId_;
};
/**
* @return {HTMLElement} The element for this card.
*/
cah.card.BaseCard.prototype.getElement = function() {
return this.element_;
};
// ///////////////////////////////////////////////
/**
* Black card definition.
*
* @param {boolean}
* opt_faceUp True if this card is initially face-up.
* @param {number}
* opt_id The id of this card, for server communication purposes.
* @extends cah.card.BaseCard
* @constructor
*/
cah.card.BlackCard = function(opt_faceUp, opt_id) {
cah.card.BaseCard.call(this, opt_faceUp, opt_id);
/**
* The number of white cards to draw when this is the active black card.
*
* @type {number}
* @private
*/
this.draw_ = 0;
/**
* The number of white cards to play for this black card.
*
* @type {number}
* @private
*/
this.pick_ = 1;
};
cah.inherits(cah.card.BlackCard, cah.card.BaseCard);
/**
* @override
*/
cah.card.BlackCard.prototype.getFaceDown_ = function() {
var temp = $("#black_down_template").clone()[0];
temp.id = "black_down_" + this.id_;
$(temp).removeClass("hide");
return temp;
};
/**
* @override
*/
cah.card.BlackCard.prototype.getFaceUp_ = function() {
var temp = $("#black_up_template").clone()[0];
temp.id = "black_up_" + this.id_;
$(temp).removeClass("hide");
return temp;
};
/**
* @param {number}
* draw The number of white cards to draw when this black card is played.
*/
cah.card.BlackCard.prototype.setDraw = function(draw) {
this.draw_ = draw;
this.updateCardInfo_();
};
/**
* @param {number}
* pick The number of white cards to play for this black card.
*/
cah.card.BlackCard.prototype.setPick = function(pick) {
this.pick_ = pick;
this.updateCardInfo_();
};
/**
* Update the pick and draw displays on this card, and potentially change the game name to or from
* "CAH".
*
* @private
*/
cah.card.BlackCard.prototype.updateCardInfo_ = function() {
if (this.draw_ != 0 || this.pick_ != 1) {
$(".logo_text", this.faceUpElem_).text("PYX");
if (this.draw_ != 0) {
$(".draw .card_number", this.faceUpElem_).text(this.draw_);
$(".draw", this.faceUpElem_).removeClass("hide");
} else {
$(".draw", this.faceUpElem_).addClass("hide");
}
if (this.pick_ != 1) {
$(".pick .card_number", this.faceUpElem_).text(this.pick_);
$(".pick", this.faceUpElem_).removeClass("hide");
} else {
$(".pick", this.faceUpElem_).addClass("hide");
}
} else {
$(".logo_text", this.faceUpElem_).text("Pretend You're Xyzzy");
}
};
// ///////////////////////////////////////////////
/**
* White card definition.
*
* @param {boolean}
* opt_faceUp True if this card is initially face-up.
* @param {number}
* opt_id The id of this card, for server communication purposes.
* @extends cah.card.BaseCard
* @constructor
*/
cah.card.WhiteCard = function(opt_faceUp, opt_id) {
cah.card.BaseCard.call(this, opt_faceUp, opt_id);
/**
* Whether this is a fill-in blank card or not.
*
* @type {boolean}
*/
this.isBlankCard_ = false;
};
cah.inherits(cah.card.WhiteCard, cah.card.BaseCard);
/**
* Set this card's flag indicating if it is a fill-in blank card.
*
* @param {boolean}
* blank Whether this is a fill-in blank card or not.
*/
cah.card.WhiteCard.prototype.setIsBlankCard = function(blank) {
this.isBlankCard_ = blank;
};
/**
* Checks if this is a blank card.
*
* @returns True if this is a blank card.
*/
cah.card.WhiteCard.prototype.isBlankCard = function() {
return this.isBlankCard_;
};
/**
* @override
*/
cah.card.WhiteCard.prototype.getFaceDown_ = function() {
var temp = $("#white_down_template").clone()[0];
temp.id = "white_down_" + this.id_;
$(temp).removeClass("hide");
return temp;
};
/**
* @override
*/
cah.card.WhiteCard.prototype.getFaceUp_ = function() {
var temp = $("#white_up_template").clone()[0];
temp.id = "white_up_" + this.id_;
$(temp).removeClass("hide");
return temp;
};