diff --git a/WebContent/cah.css b/WebContent/cah.css index c796e82..138f0f8 100644 --- a/WebContent/cah.css +++ b/WebContent/cah.css @@ -1,3 +1,31 @@ +#browser { + background: rgba(0, 0, 0, .5); +} + +#browser_inner { + border: 10px solid red; + padding: 15px; + background: white; + margin: 150px; + min-height: 150px; +} + +#browser, #browser_inner { + position: absolute; + top: 0px; + right: 0px; + bottom: 0px; + left: 0px; + z-index: 9001; +} + +#browser_ok { + margin: 15px; + position: absolute; + right: 0px; + bottom: 0px; +} + #menubar { position: absolute; top: 0px; diff --git a/WebContent/index.jsp b/WebContent/index.jsp index c36c242..a4c7839 100644 --- a/WebContent/index.jsp +++ b/WebContent/index.jsp @@ -7,6 +7,8 @@ Cards Against Humanity + + <%-- cah must be first, ajax must be before app. app probably has to be last. --%> <%-- TODO make this be dynamic with looking at the filesystem and using jquery --%> @@ -31,6 +33,16 @@ < % = new net.socialgamer.cah.data.WhiteDeck().getNextCard().toString() % > --%> +
+
+

Cards Against Humanity is known to have graphical glitches in + $BROWSER_NAME. The game should work, + but it looks much better in Google Chrome.

+

We will not bug you about this again after you dismiss this dialog.

+ +
+
+
Nickname: diff --git a/WebContent/js/QTransform.js b/WebContent/js/QTransform.js new file mode 100644 index 0000000..5a9df30 --- /dev/null +++ b/WebContent/js/QTransform.js @@ -0,0 +1,438 @@ +/* + * based off of Louis-Rémi Babé rotate plugin (https://github.com/lrbabe/jquery.rotate.js) + * + * cssTransforms: jQuery cssHooks adding a cross browser, animatible transforms + * + * Author Bobby Schultz + */ +// +(function($) { + + var div = document.createElement('div'), divStyle = div.style; + + // give props to those who dont have them + $.cssProps.transform = divStyle.MozTransform === '' ? 'MozTransform' + : (divStyle.msTransform === '' ? 'msTransform' + : (divStyle.WebkitTransform === '' ? 'WebkitTransform' + : (divStyle.OTransform === '' ? 'OTransform' + : (divStyle.Transform === '' ? 'Transform' : false)))); + $.cssProps.transformOrigin = divStyle.MozTransformOrigin === '' ? 'MozTransformOrigin' + : (divStyle.msTransformOrigin === '' ? 'msTransformOrigin' + : (divStyle.WebkitTransformOrigin === '' ? 'WebkitTransformOrigin' + : (divStyle.OTransformOrigin === '' ? 'OTransformOrigin' + : (divStyle.TransformOrigin === '' ? 'TransformOrigin' : false)))); + + // define supported or not + $.support.transform = $.cssProps.transform !== false || divStyle.filter === '' ? true : false; + $.support.transformOrigin = $.cssProps.transformOrigin !== false ? true : false; + + // if ONLY IE matrixes are supported (IE9 beta6 will use css3) + $.support.matrixFilter = (divStyle.filter === '' && $.cssProps.transform === false) ? true + : false; + div = null; + + // stop if no form of transforms are supported + if ($.support.transform === false) { + return; + } + + // opt out of letting jquery handle the units for custom setters/getters + $.cssNumber.skew = $.cssNumber.skewX = $.cssNumber.skewY = $.cssNumber.scale = $.cssNumber.scaleX = $.cssNumber.scaleY = $.cssNumber.rotate = $.cssNumber.matrix = true; + + $.cssNumber.transformOrigin = $.cssNumber.transformOriginX = $.cssNumber.transformOriginY = true; + + if ($.support.matrixFilter) { + $.cssNumber.transformOrigin = $.cssNumber.transformOriginX = $.cssNumber.transformOriginY = true; + + $.cssProps.transformOrigin = 'matrixFilter'; + } + + $.cssHooks.transform = { + set : function(elem, val, unit) { + if ($.support.matrixFilter) { + elem.style.filter = [ val ].join(''); + } else { + elem.style[$.cssProps.transform] = val + '%'; + } + }, + get : function(elem, computed) { + if ($.support.matrixFilter) { + return elem.style.filter; + } else { + return elem.style[$.cssProps.transform]; + } + } + }; + + $.cssHooks.transformOrigin = { + set : function(elem, val, unit) { + if (!$.support.matrixFilter) { + val = (typeof val === 'string') ? val : val + (unit || '%'); + elem.style[$.cssProps.transformOrigin] = val; + } else { + val = val.split(","); + $.cssHooks.transformOriginX.set(elem, val[0]); + if (val.length > 1) { + $.cssHooks.transformOriginY.set(elem, val[1]); + } + } + }, + get : function(elem, computed) { + if (!$.support.matrixFilter) { + return elem.style[$.cssProps.transformOrigin]; + } else { + var originX = $.data(elem, 'transformOriginX'); + var originY = $.data(elem, 'transformOriginY'); + return originX && originY && originX === originY ? originX : '50%'; + } + } + }; + + $.fx.step.transformOrigin = function(fx) { + $.cssHooks.transformOrigin.set(fx.elem, fx.now, fx.unit); + }; + + $.cssHooks.transformOriginX = { + set : function(elem, val, unit) { + if (!$.support.matrixFilter) { + val = (typeof val === 'string') ? val : val + (unit || '%'); + elem.style[$.cssProps.transformOrigin + 'X'] = val; + } else { + $.data(elem, 'transformOriginX', unit ? val + unit : val); + setIEMatrix(elem); + } + }, + get : function(elem, computed) { + if (!$.support.matrixFilter) { + return elem.style[$.cssProps.transformOrigin + 'X']; + } else { + var originX = $.data(elem, 'transformOriginX'); + switch (originX) { + case 'left': + return '0%'; + case 'center': + return '50%'; + case 'right': + return '100%'; + } + return originX ? originX : '50%'; + } + } + }; + + $.fx.step.transformOriginX = function(fx) { + $.cssHooks.transformOriginX.set(fx.elem, fx.now, fx.unit); + }; + + $.cssHooks.transformOriginY = { + set : function(elem, val, unit) { + if (!$.support.matrixFilter) { + val = (typeof val === 'string') ? val : val + (unit || '%'); + elem.style[$.cssProps.transformOrigin + 'Y'] = val; + } else { + $.data(elem, 'transformOriginY', unit ? val + unit : val); + setIEMatrix(elem); + } + }, + get : function(elem, computed) { + if (!$.support.matrixFilter) { + return elem.style[$.cssProps.transformOrigin + 'Y']; + } else { + var originY = $.data(elem, 'transformOriginY'); + switch (originY) { + case 'top': + return '0%'; + case 'center': + return '50%'; + case 'bottom': + return '100%'; + } + return originY ? originY : '50%'; + } + } + }; + + $.fx.step.transformOriginY = function(fx) { + $.cssHooks.transformOriginY.set(fx.elem, fx.now, fx.unit); + }; + + // create hooks for css transforms + var rtn = function(v) { + return v; + }; + var xy = [ [ 'X', 'Y' ], 'X', 'Y' ]; + var abcdxy = [ [ 'A', 'B', 'C', 'D', 'X', 'Y' ], 'A', 'B', 'C', 'D', 'X', 'Y' ]; + var props = [ + { + prop : 'rotate', + matrix : [ function(v) { + return Math.cos(v); + }, function(v) { + return -Math.sin(v); + }, function(v) { + return Math.sin(v); + }, function(v) { + return Math.cos(v); + } ], + unit : 'rad', + subProps : [ '' ], + fnc : toRadian + }, + { + prop : 'scale', + matrix : [ [ rtn, 0, 0, rtn ], [ rtn, 0, 0, 1 ], [ 1, 0, 0, rtn ] ], + unit : '', + subProps : xy, + fnc : parseFloat, + _default : 1 + }, + { + prop : 'skew', + matrix : [ [ 1, rtn, rtn, 1 ], [ 1, rtn, 0, 1 ], [ 1, 0, rtn, 1 ] ], + unit : 'rad', + subProps : xy, + fnc : toRadian + }, + { + prop : 'translate', + matrix : [ [ 1, 0, 0, 1, rtn, rtn ], [ 1, 0, 0, 1, rtn, 0 ], [ 1, 0, 0, 1, 0, rtn ] ], + standardUnit : 'px', + subProps : xy, + fnc : parseFloat + }, + { + prop : 'matrix', + matrix : [ [ rtn, rtn, rtn, rtn, rtn, rtn ], [ rtn, 0, 0, 1, 0, 0 ], + [ 1, rtn, 0, 1, 0, 0 ], [ 1, 0, rtn, 1, 0, 0 ], [ 1, 0, 0, rtn, 0, 0 ], + [ 1, 0, 0, 1, 0, rtn ] ], + subProps : abcdxy, + fnc : parseFloat + } ]; + + jQuery.each(props, function(n, prop) { + jQuery.each(prop.subProps, function(num, sub) { + var _cssProp, _prop = prop; + + if ($.isArray(sub)) { + // composite transform + _cssProp = _prop.prop; + var _sub = sub; + $.cssHooks[_cssProp] = { + set : function(elem, val, unit) { + jQuery.each(_sub, function(num, x) { + $.cssHooks[_cssProp + x].set(elem, val, unit); + }); + }, + get : function(elem, computed) { + var val = []; + jQuery.each(_sub, function(num, x) { + val.push($.cssHooks[_cssProp + x].get(elem, val)); + }); + // hack until jQuery supports animating multiple properties + return val[0] || val[1]; + } + }; + } else { + // independent transfrom + _cssProp = _prop.prop + sub; + $.cssHooks[_cssProp] = { + set : function(elem, val, unit) { + $.data(elem, _cssProp, unit ? val + unit : val); + + setCSSTransform(elem, _prop.fnc(unit ? val + unit : val), _cssProp, _prop.unit || unit + || _prop.standardUnit); + }, + get : function(elem, computed) { + + var p = $.data(elem, _cssProp); + // console.log(_cssProp+'get:'+p); + return p && p !== undefined ? p : _prop._default || 0; + } + }; + } + + $.fx.step[_cssProp] = function(fx) { + fx.unit = fx.unit === 'px' && $.cssNumber[_cssProp] ? _prop.standardUnit : fx.unit; + var unit = ($.cssNumber[_cssProp] ? '' : fx.unit); + $.cssHooks[_cssProp].set(fx.elem, fx.now, fx.unit); + }; + }); + }); + + function setCSSTransform(elem, val, prop, unit) { + if ($.support.matrixFilter) { + return setIEMatrix(elem, val); + } + + // parse css string + var allProps = parseCSSTransform(elem); + + // check for value to be set + var a = /[X|Y]/.exec(prop); + a = (a === null ? '' : a[0] ? a[0] : a); + prop = /.*[^XY]/.exec(prop)[0]; + unit = unit === undefined ? '' : unit; + + // create return string + var result = ''; + var wasUpdated = false; + var arr; + if (allProps !== null) { + for ( var item in allProps) { + arr = allProps[item]; + if (prop === item) { + // update parsed data with new value + if (prop !== 'matrix') { + result += prop + '('; + result += a === 'X' || a === '' ? val + unit : (arr[0] !== '' ? arr[0] + : $.cssHooks[prop + 'X'].get(elem) + unit); + result += a === 'Y' ? ', ' + val + unit : (arr[1] !== '' ? ', ' + arr[1] + : (prop + 'Y' in $.cssHooks ? ', ' + $.cssHooks[prop + 'Y'].get(elem) + unit : '')); + result += ') '; + } else { + result += val + ' '; + } + wasUpdated = true; + } else { + // dump parsed data to string + result += item + '('; + for ( var i = 0; i < arr.length; i++) { + result += arr[i]; + if (i < arr.length - 1 && arr[i + 1] !== '') { + result += ', '; + } else { + break; + } + } + result += ') '; + } + } + } + + // if prop was not found to be updated, then dump data + if (!wasUpdated) { + result += prop + a + '(' + val + unit + ') '; + } + + // set all transform properties + elem.style[$.cssProps.transform] = result; + } + + function parseCSSTransform(elem) { + var props, prop, name, transform; + // break up into single transform calls + $(elem.style[$.cssProps.transform].replace(/(?:\,\s|\)|\()/g, "|").split(" ")) + // read each data point for the transform call + .each(function(i, item) { + if (item !== '') { + if (props === undefined) { + props = {}; + } + prop = item.split("|"); + name = prop.shift(); + transform = /.*[^XY]/.exec(name)[0]; + if (!props[transform]) { + props[transform] = [ '', '', '', '', '', '' ]; + } + if (!/Y/.test(name)) { + props[transform][0] = prop[0]; + } + if (!/X/.test(name)) { + props[transform][1] = prop[1]; + } + if (prop.length == 6) { + props[transform][2] = prop[2]; + props[transform][3] = prop[3]; + props[transform][4] = prop[4]; + props[transform][5] = prop[5]; + } + } + }); + + return props !== undefined ? props : null; + } + + function ieOrigin(o, n, percent) { + return percent * (o - n); + } + + function toRadian(value) { + if (typeof value === 'number') { + return parseFloat(value); + } + if (value.indexOf("deg") != -1) { + return parseInt(value, 10) * (Math.PI * 2 / 360); + } else if (value.indexOf("grad") != -1) { + return parseInt(value, 10) * (Math.PI / 200); + } + } + + $.rotate = { + radToDeg : function radToDeg(rad) { + return rad * 180 / Math.PI; + } + }; + + // special case for IE matrix + function setIEMatrix(elem, mat) { + var inverse, current, ang, org, originX, originY, runTransform = $.cssProps.transformOrigin === 'matrixFilter' ? true + : false; + + current = [ $.cssHooks.scaleX.get(elem), toRadian($.cssHooks.skewY.get(elem)), + toRadian($.cssHooks.skewX.get(elem)), $.cssHooks.scaleY.get(elem), + $.cssHooks.translateX.get(elem), $.cssHooks.translateY.get(elem) ]; + + // start by multiply inverse of transform origin by matrix + if (runTransform) { + elem.style.filter = [ "progid:DXImageTransform.Microsoft.Matrix" + + "(M11=1,M12=0,M21=0,M22=1,SizingMethod='auto expand')" ].join(''); + var Wp = $.cssHooks.transformOriginX.get(elem); + var Hp = $.cssHooks.transformOriginY.get(elem); + Wp = Wp.indexOf('%') > 0 ? (/[\d]*/.exec(Wp) / 100) : Wp; + Hp = Hp.indexOf('%') > 0 ? (/[\d]*/.exec(Hp) / 100) : Hp; + + var Wb = elem.offsetWidth; + var Hb = elem.offsetHeight; + } + + // multiply old matrix to new matrix + if (typeof mat !== 'array' || mat.length !== 6) { + mat = current; + } else { + mat = [ ((current[0] * mat[0]) + (current[1] * mat[2])), + ((current[0] * mat[1]) + (current[1] * mat[3])), + ((current[2] * mat[0]) + (current[3] * mat[2])), + ((current[2] * mat[1]) + (current[3] * mat[3])), mat[4], mat[5] ]; + } + + // multiply the transform and rotation matrixes + ang = $.data(elem, 'rotate'); + if (ang) { + ang = toRadian(ang); + var cos = Math.cos(ang); + var sin = Math.sin(ang); + + ang = [ cos, -sin, sin, cos ]; + mat = [ ((mat[0] * ang[0]) + (mat[1] * ang[2])), ((mat[0] * ang[1]) + (mat[1] * ang[3])), + ((mat[2] * ang[0]) + (mat[3] * ang[2])), ((mat[2] * ang[1]) + (mat[3] * ang[3])), mat[4], + mat[5] ]; + } + + // apply the matrix as a IE filter + elem.style.filter = [ "progid:DXImageTransform.Microsoft.Matrix(", "M11=" + mat[0] + ", ", + "M12=" + mat[1] + ", ", "M21=" + mat[2] + ", ", "M22=" + mat[3] + ", ", + "SizingMethod='auto expand'", ")" ].join(''); + + if (runTransform) { + var Wo = elem.offsetWidth; + var Ho = elem.offsetHeight; + elem.style.position = 'relative'; + elem.style.left = Wp * (Wb - Wo) + (parseInt(mat[4]) || 0); + elem.style.top = Hp * (Hb - Ho) + (parseInt(mat[5]) || 0); + } + // $('#console').append('
+ // trans:'+Wp+":"+Wb+":"+Wo+":"+mat[4]+":"+elem.style.left+'
'); + + } + +})(jQuery); diff --git a/WebContent/js/cah.app.js b/WebContent/js/cah.app.js index 95b1732..0e947d0 100644 --- a/WebContent/js/cah.app.js +++ b/WebContent/js/cah.app.js @@ -20,6 +20,18 @@ $(document).ready(function() { // have not expressed an interest in being cleared out yet. // $(window).bind("beforeunload", window_beforeunload); $("#logout").click(logout_click); + + if (($.browser.mozilla || $.browser.opera) && !$.cookie("browser_dismiss")) { + var name = $.browser.mozilla ? "Firefox" : "Opera"; + $("#browser").show(); + $("#browser_name").text(name); + $("#browser_ok").click(function() { + $("#browser").hide(); + $.cookie("browser_dismiss", true, { + expires : 3650, + }); + }); + } }); function nickbox_keyup(e) { diff --git a/WebContent/js/cah.game.js b/WebContent/js/cah.game.js index 6ad0aba..e083869 100644 --- a/WebContent/js/cah.game.js +++ b/WebContent/js/cah.game.js @@ -57,6 +57,14 @@ cah.Game = function(id) { */ this.hand_ = Array(); + /** + * Firefox is horrible, and Opera is pretty bad too. + * + * @type {number} + * @private + */ + this.badBrowserZOrderHack_ = 10000; + $("#leave_game").click(cah.bind(this, this.leaveGameClick_)); $("#start_game").click(cah.bind(this, this.startGameClick_)); }; @@ -100,6 +108,8 @@ cah.Game.prototype.dealtCards = function(cards) { /** * Add a card to the player's hand. * + * TODO: in IE, for some reason, the logo is only on the leftmost card. + * * @param {cah.card.WhiteCard} * card Card to add to hand. */ @@ -107,6 +117,8 @@ cah.Game.prototype.dealtCard = function(card) { this.hand_.push(card); var element = card.getElement(); jQuery(".game_hand_cards", this.element_).append(element); + + $(element).css("zoom", ".35"); var data = { card : element, }; @@ -114,16 +126,40 @@ cah.Game.prototype.dealtCard = function(card) { duration : 200, queue : false, }; - $(element).mouseenter(data, function(e) { - $(e.data.card).animate({ - zoom : .7 - }, options); - }).mouseleave(data, function(e) { - $(e.data.card).animate({ - zoom : .35 - }, options); - }); - $(element).css("zoom", ".35"); + + if ($.browser.mozilla || $.browser.opera) { + var origSize = parseInt($(element).css("width")); + if ($.browser.mozilla) { + $(element).css("-moz-transform", "scale(0.35, 0.35)").css("-moz-transform-origin", "0 0"); + } else { + $(element).css("-o-transform", "scale(0.35, 0.35)").css("-o-transform-origin", "0 0"); + } + $(element).css("width", origSize * .35).css("height", origSize * .35).css("z-index", + this.badBrowserZOrderHack_--); + $(".cah", element).css("bottom", "-150px"); + + $(element).mouseenter(data, function(e) { + $(e.data.card).animate({ + scale : .7, + }, options); + }).mouseleave(data, function(e) { + $(e.data.card).animate({ + scale : .35, + }, options); + }); + + } else { + + $(element).mouseenter(data, function(e) { + $(e.data.card).animate({ + zoom : .7 + }, options); + }).mouseleave(data, function(e) { + $(e.data.card).animate({ + zoom : .35 + }, options); + }); + } }; cah.Game.prototype.insertIntoDocument = function() { @@ -311,13 +347,13 @@ cah.GameScorePanel.prototype.update = function(score, status) { jQuery(".scorecard_status", this.element_).text(cah.$.GamePlayerStatus_msg[status]); }; -$(document).ready(function() { - var game = new cah.Game(0); - $("#main_holder").append(game.getElement()); - - for ( var i = 0; i < 10; i++) { - var card = new cah.card.WhiteCard(true); - card.setText("This is card " + i); - game.dealtCard(card); - } -}); +// $(document).ready(function() { +// var game = new cah.Game(0); +// $("#main_holder").append(game.getElement()); +// +// for ( var i = 0; i < 10; i++) { +// var card = new cah.card.WhiteCard(true); +// card.setText("This is card " + i); +// game.dealtCard(card); +// } +// }); diff --git a/WebContent/js/jquery.cookie.js b/WebContent/js/jquery.cookie.js new file mode 100644 index 0000000..dc03161 --- /dev/null +++ b/WebContent/js/jquery.cookie.js @@ -0,0 +1,47 @@ +/** + * jQuery Cookie plugin + * + * Copyright (c) 2010 Klaus Hartl (stilbuero.de) + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ +(function($) { + $.cookie = function(key, value, options) { + + // key and at least value given, set cookie... + if (arguments.length > 1 && (!/Object/.test(Object.prototype.toString.call(value)) || value === null || value === undefined)) { + options = $.extend({}, options); + + if (value === null || value === undefined) { + options.expires = -1; + } + + if (typeof options.expires === 'number') { + var days = options.expires, t = options.expires = new Date(); + t.setDate(t.getDate() + days); + } + + value = String(value); + + return (document.cookie = [ + encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value), + options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE + options.path ? '; path=' + options.path : '', + options.domain ? '; domain=' + options.domain : '', + options.secure ? '; secure' : '' + ].join('')); + } + + // key and possibly options given, get cookie... + options = value || {}; + var decode = options.raw ? function(s) { return s; } : decodeURIComponent; + + var pairs = document.cookie.split('; '); + for (var i = 0, pair; pair = pairs[i] && pairs[i].split('='); i++) { + if (decode(pair[0]) === key) return decode(pair[1] || ''); // IE saves cookies with empty string as "c; ", e.g. without "=" as opposed to EOMB, thus pair[1] may be undefined + } + return null; + }; +})(jQuery);