"use strict"; /** @namespace The namespace for all FreeLotto JavaScript functions */ var FL = FL || {}; (function ($) { /** @namespace Language-related functions (map, forEach, etc) */ FL.lang = {}; /* http://dean.edwards.name/base/forEach.js forEach, version 1.0 Copyright 2006, Dean Edwards License: http://www.opensource.org/licenses/mit-license.php */ // array-like enumeration if (!Array.forEach) { // mozilla already supports this Array.forEach = function (array, block, context) { for (var i = 0; i < array.length; i++) { block.call(context, array[i], i, array); } }; } // generic enumeration Function.prototype.forEach = function (object, block, context) { for (var key in object) { if (typeof this.prototype[key] === "undefined") { block.call(context, object[key], key, object); } } }; // globally resolve forEach enumeration /** * Iterate through a list, performing block on each iteration * @param {Object, Array} object List over which to iterate * @param {Function} block Function to execute on each iteration * @param {Object} [context] Scope to use when calling block. * @default {Object} this */ FL.lang.forEach = function (object, block, context) { if (object) { var resolve = Object; // default if (object instanceof Function) { // functions have a "length" property resolve = Function; } else if (object.forEach instanceof Function) { // the object implements a custom forEach method so use that object.forEach(block, context); return; } else if (typeof object === "string") { // the object is a string resolve = String; } else if (typeof object.length === "number") { // the object is array-like resolve = Array; } resolve.forEach(object, block, context); } }; /** * Iterate through list, processing with func and, optionally, including scope * @requires FL.lang * @param {Object} list * @param {Function} func * @param {Object} scope * @return {Array} */ FL.lang.map = function (list, func, scope) { var arr = [], result; FL.lang.forEach(list, function (/* val, ndx, list */) { result = func.apply(this, arguments); if (result) { arr.push(result); } }, scope || this); return arr; }; /** * Takes list of 2 or more objects. Later key/values overwrite earlier key/values. * @static * @requires FL.lang.forEach * @param {Object} * @return {Object} */ FL.lang.merge = function (/* objA, objB, ... objN */) { var merged = {}; FL.lang.forEach(arguments, function (obj) { merged = (function (first, second) { FL.lang.forEach(second, function (val, key) { first[key] = second[key]; }); return first; }(merged, obj)); }); return merged; }; /* eo FL.lang */ /** * @class Returns an instance which can be used to for CRUD operations on a cookie. * @param {String} sName The name (or key) to use for the cookie * @param {String, Object} value What to store in the cookie * @param {Object} opts * @config {Object, String, Date} expires When does the cookie expire. * @config {String} domain (sub)domain to restrict cookie to * @config {String} path Path to restrict cookie to. No value defaults to '/'; * @config {String} secure Is the cookie limited to https? * @config {Function} serialize Custom function to use to convert #value into a cookie-ready string * @config {Function} deserialize Custom function to use to convert the cookie string into an object * @return {FL.Cookie} instance * @type {Object} * @example new FL.Cookie('settings', {language: 'en'}).setCookie(); * @example new FL.Cookie('settings', {language: 'en', timezone: 'US-Eastern'}).setCookie(); * @example new FL.Cookie('played', 'false').setCookie(); * @example new FL.Cookie('played', 'true', {expires: new Date('01/01/2020')}).setCookie(); * @example var settings = new FL.Cookie('settings', {language: 'en'}); * settings.set('timezone', 'US-Eastern'); * setting.setCookie(); * @example var settings = new FL.Cookie('settings', {language: 'en'}); */ FL.Cookie = function (sName, value, opts) { var instance = this, oEmpty = {}, sv_key = '__single-value__', oValues = ("string" === typeof value) ? oEmpty[sv_key] = value : value, defaults = { expires: undefined, domain: undefined, path: '/', secure: false, serialize: serialize, deserialize: deserialize }, config = FL.lang.merge(defaults, (opts || {})), curr_vals = getValuesFromCookieString() || {}; oValues = FL.lang.merge(curr_vals, oValues); /**#@+ @public */ /** @property {String, Number, Date} expires */ this.expires = config.expires; /** @property {String} domain */ this.domain = config.domain; /** @property {String} path */ this.path = config.path; /** @property {Boolean} secure */ this.secure = config.secure; /** * Sets key to value internally * @param {Object} key * @param {Object} value * @return {FL.Cookie} instance * @type {Object} */ this.set = function (key, value) { if (sv_key in oValues) { oValues[sv_key] = key; } else { oValues[key] = value; } return instance; // allows chaining }; /** * Returns the value stored for key in the internal structure {oValues} * @param {String} key * @return {String} value */ this.get = function (key) { if (sv_key in oValues) { return oValues[sv_key]; } else if (key) { return oValues[key]; } }; /** * Deletes the given key from the cookie * @param {String} key * @return {FL.Cookie} instance * @type {Object} */ this.del = function (key) { delete oValues[key]; return instance; }; /** * Serializes values object and sets the cookie in the browser * @return {FL.Cookie} instance * @type {Object} */ this.setCookie = function () { var parts = [ [sName, getValueString()] ], expires = getDateString(); if (expires) { parts.push(['expires', expires]); } if (config.domain) { parts.push(['domain', config.domain]); } if (instance.path) { parts.push(['path', instance.path]); } var cookie_string = FL.lang.map(parts, function (arr) { return arr.join('='); }).join('; '); if (config.secure) { cookie_string += '; secure'; } document.cookie = cookie_string; return instance; // allows chaining }; /** * Return the internal object which stores the values to be serialized * @return {Object} oValues */ this.getValues = function () { return (sv_key in oValues) ? oValues[sv_key] : oValues; }; /**#@- */ /**#@+ @private */ /** * @return {Object} of key/value pairs for *currently set* cookie */ function getValuesFromCookieString() { var aCookies = document.cookie.split('; '), oCookie; for (var i = 0, l = aCookies.length; i < l; i++) { var sCookie = aCookies[i], matches = sCookie.match(/^(.+?)=(.+)$/); if(matches) { var cookieID = matches[1], cookieVal = matches[2]; if (cookieID === sName) { oCookie = config.deserialize(cookieVal); break; } } } return oCookie; } /** * @return {String} serialized string of cookie values */ function getValueString() { if (sv_key in oValues) { return oValues[sv_key]; } else { return config.serialize(oValues); } } /** * @return {String} UTC Date string appropriate for cookie */ function getDateString() { if ((/GMT|UTC/i).test(instance.expires) || (/\//).test(instance.expires) ){ return new Date(instance.expires).toUTCString(); } else if ("number" === typeof instance.expires) { return new Date(instance.expires).toUTCString(); } else if (instance.expires instanceof Date) { return instance.expires.toUTCString(); } return; } /** * @param {Object} obj * @requires FL.lang.map */ function serialize(obj) { var pairs = FL.lang.map(obj, function (val, key) { if (obj[key]) { return encodeURIComponent(key) +'='+ encodeURIComponent(val); } else { return false; } }); return pairs.join('&'); } /** * @param {String} str * @requires FL.lang.forEach */ function deserialize(str) { var pairs = str.split('&'), obj = {}; if (! (/\=/).test(pairs)) { obj[sv_key] = pairs[0]; } else { FL.lang.forEach(pairs, function (pair) { var parts = pair.split('='), key = decodeURIComponent(parts[0]), val = decodeURIComponent(parts[1]); obj[key] = val; }); } return obj; } /**#@- */ return this; }; // eo FL.Cookie constructor /** * Turn a string of key=value pairs into an object like {key: 'value'} * @param {String} str key=value pairs * @return {Object} */ FL.deserialize = function (str) { var ndx = str.indexOf('?') + 1, pairs = str.slice(ndx).split('&'), obj = {}, key, val, kv; FL.lang.forEach(pairs, function (pair) { kv = pair.split('='); if (kv.length !== 1) { key = unescape(kv[0]); val = unescape(kv[1]); if ( (/^[0-9]+$/).test(val) ){ val = parseInt(val); } if ( (/[%5B%5D|\[\]]/).test(key) // array-like key || (key in obj) // already seen/stored key ){ if (obj[key]) { if ( !(obj[key] instanceof Array) ) { obj[key] = [obj[key]]; } obj[key].push(val); } else { obj[key] = [val]; } } else { obj[key] = val; } } }); return obj; }; /** * Access the values in the query string. * When called without arguments, return the entire object * @param {Object} [opts] * @config {String, Array} key The key (or array of keys) whose value should be returned * @config {String} url The URL to use when extracting key/values * @returns {String, Object, Array} * @example var obj = FL.queryParams(); // returns object based on query string params * @example var str = FL.queryParams({key: 'user'}); // returns query string value of 'user' * @example var obj = FL.queryParams({url: 'foo=bar&baz=bam'}); // returns {foo: 'bar', baz: 'bam'} * @example var str = FL.queryParams({key: 'baz', url: 'foo=bar&baz=bam'}); // returns 'bam' * @example var obj = FL.queryParams({key: ['user', 'baz'], url: 'user=name&foo=bar&baz=bam'}); // returns {user: 'name', baz: 'bam'} */ FL.queryParams = function (opts) { opts = opts || {}; var url = opts.url || window.location.href, cached = ('qso' in window.location) || false, obj = cached ? window.location.qso : FL.deserialize(url), out; if (!cached) { try { window.location.qso = obj; } catch (e) {} } if (opts.key) { if (opts.key instanceof Array) { out = {}; FL.lang.forEach(opts.key, function (k) { out[k] = obj[k]; }); } else { out = obj[opts.key]; } } else { out = obj; } return out; }; /** * Turn an object like {key: 'value', another: 'pair'} into 'key=value&another=pair' * @param {Object} obj An object like {key: 'value', another: 'pair'} * @return {String} */ FL.serialize = function (obj) { var parts = [], push = function (key, val) { parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(val)); }; for (var key in obj) { if (obj.hasOwnProperty(key)) { var val = obj[key]; if (val instanceof Array) { for (var i=0, l=val.length; iencode(\%countries) %gt;; // which can be accessed by another function if passing the variable is not practical/possible */ FL.page = {}; /** * @namespace FreeLotto functions added to the jQuery namespace */ $.fn.extend( { /**#@+ * @memberOf jQuery * @function */ /** * Generate (and assign) an ID for a DOM element * @name generateID * @param {Object} options * @config {String} prefix Prefix for the id, an integer will be appended. @default 'fl_gen_' * @config {Boolean} force Overwrite with new ID even if the DOM element already has one? @default false * @example jQuery('.menu_left').generateID({prefix: 'your_prefix_here_'}); // [span#your_prefix_here_6.menu_left, span#your_prefix_here_7.menu_left, span#your_prefix_here_8.menu_left] * @example jQuery('#logo').generateID({prefix: 'your_prefix_here_'}); // [img#logo.howtoplaypopup LogoTopLef...er_new.gif] * @example jQuery('#logo').generateID({prefix: 'your_prefix_here_', force: true}); // [img#your_prefix_here_2.howtoplaypopup LogoTopLef...er_new.gif] */ generateID: function (options) { options = options || {}; var defaults = { prefix: 'fl_gen_', force: false }, settings = $.extend(defaults, options); return this.each(function () { if (settings.force || (!this.id) ) { this.id = settings.prefix + $.data(this); } }); }, /** * Simple show/hide of menus * @name simpleMenu * @param {Object} menu The CSS selector for the item to be shown * @param {Object} options * @config {String} speed * @example $("#show_language").simpleMenu("#show_language_links"); * @example $("#logo").simpleMenu("#howtoplaypopup", {speed: "slow"}); */ simpleMenu: function (menu, options) { if (! menu) { throw "You must include a selector for menu"; } options = options || {}; var $menu = $(menu), defaults = {}, settings = $.extend(defaults, options); return this.each(function () { var $trigger = $(this); $trigger.click(function (e) { $menu.toggle(settings.speed); }); }); }, /** * Force a handler to be triggered *before* any others. * @param {String} types One or more event types separated by a space * @param {Object} data Additional data passed to the event handler as event.data * @param {Function} fn A function to bind to the event on each of the set of matched elements, passed an event object. */ bindFirst: function (types, data, fn) { return this.each(function (index, elem) { $.each(types.split(/\s+/), function (index, type) { var eventType = type.split(".").shift(), events = $.data(elem, "events"), originalEvents = events && events[eventType] || null; if (!originalEvents) { return $(elem).bind(type, data, fn); } events[eventType] = {}; $(elem).bind(type, data, fn); $.extend(events[eventType], originalEvents); }); }); } /**#@-*/ }); }(jQuery)); // This will run on every page $("document").ready(function () { // set up the language dropdown. $("a.language_links").click(function (e) { e.preventDefault(); var lang = this.href.replace(/^.*\#/, ""); FL.changeLanguage(lang, FL.page.changelanguage_options || {}); }); // set up logo how to play $("#logo").simpleMenu("#howtoplaypopup", {speed: "slow"}); $("#btn-howtoplay-close").simpleMenu("#howtoplaypopup", {speed: "slow"}); // set up select language mouseover $("#show_language").simpleMenu("#show_language_links"); $("#btn-language-select-close").simpleMenu("#show_language_links"); });