/** * Outdoor Hub Javascript Core * * Serves as light weight wrapper for basic building blocks that we use all the * time; waiting for the dom to be ready, loading jquery, loading js/css files, * statistics, and clickthrough tracking. * * Note object property function assignment method used instead of JSON to * prevent clobbering the OHUB namespace. * * To use this file (bootstrap): * * (function() { * d = document; * s = d.createElement('script'); * s.type = 'text/javascript'; * if (s.readyState) { * s.onreadystatechange = function() { * if (s.readyState == 'loaded' || s.readyState == 'complete') { * s.onreadystatechange = null; * OHUB.DEBUG = true; //set to false to disable debug msgs * OHUB.ready(function() { * //YOUR BOOTSTRAP/INIT FUNCTION HERE * }); * } * } * } else { * s.onload = function() { * OHUB.DEBUG = true; //set to false to disable debug msgs * OHUB.ready(function() { * //YOUR BOOTSTRAP/INIT FUNCTION HERE * }); * } * } * s.src = 'http://app.outdoorhub.com/lib/ohub_core.min.js'; * d.getElementsByTagName('head')[0].appendChild(s); * })(); * * @package OHUB * @author Rick Christy (rchristy@outdoorhub.com) * @version 0.1 */ if (typeof(OHUB) == 'undefined') { OHUB = {}; } OHUB.tracker_url = 'http://st.ohub.us'; OHUB.clickthru_url = 'http://ct.ohub.us'; // Set to true to enable debug messages OHUB.DEBUG = false; if (typeof(OHUB.loaded) == 'undefined') { OHUB.loaded = []; } /** * Gets the next highest zIndex * @return int */ OHUB.get_nhz = function() { OHUB.debug('get_nhz()'); var nhz = 0; $_('*').each(function(i) { var z = $_(this).css('zIndex'); if (typeof(z) != 'undefined' && z != 'auto') { nhz = (parseInt(z, 10) > nhz) ? z : nhz; } }); return parseInt(nhz, 10) + 99999 + 1; }; /** * Cachebust a [timestamp] string * @param string str string to cachebust for * @param string find string to replace with cachebuster * @return string Cachebusted string */ OHUB.cachebust = function(str) { if (typeof(str) != 'undefined') { var ret = str.toString().replace( /\[timestamp\]/gi, String(new Date().getTime()) + Math.round(Math.random(1) * 1000000)); ret = ret.replace( /\[random\]/gi, String(new Date().getTime()) + Math.round(Math.random(1) * 1000000)); ret = ret.replace( /ord\=\%n/gi, 'ord=' + String(new Date().getTime()) + Math.round(Math.random(1) * 1000000)); return ret; } else { return; } }; /** * Stat tracker * @param object data (see below) * * Request Arg. Mnemonic Description Lookup (table/file) * ---------------- ------------------ --------------- ----------------------- * a (a)pplication Application ID MySQL: applications * b (b)y_author_id Author ID MySQL: feed_item_authors * c (c)omponent Component ID MySQL: components * p (p)ublisher Publisher ID MySQL: publishers * s (s)ponsor (ad) Ad ID MySQL: ads * x a(x)ion Action ID PHP: oh/_ACTIONS.php * f (f)eed Feed ID MySQL: feeds * r (r)ticle Article ID MySQL: feed_items * v (v)ideo Video ID MySQL: ohdev_ohv.Videos * w (w)idget Widget ID MySQL: ohdev_connect.widgets * * wp = wordpress namespace (namespaces = abbreviation followed by dot) * wp.p wordpress post_id Post ID MySQL: article_stats.article_id (wp_posts.ID) * wp.s wordpress slug Slug MySQL: aritcle_stats.slug (wp_terms.slug) * wp.t wordpress taxonomy Taxonomy MySQL: article_stats.taxonomy (wp_term_taxonomy.taxonomy) * * t (t)ype Type (ad | app | pub | feed | article | video | widget | wp) * o (o)utput Output (json | [gif]) * debug n/a Debug data in results (only if o=json) * * @return void */ OHUB.stat = function(data) { OHUB.debug('stat: ' + typeof(data)); if (typeof(data) != 'object') { return; } else { var args = {}; if (typeof(data.o) != 'undefined') { args.o = data.o; } if (typeof(data.a) != 'undefined') { args.a = data.a; } if (typeof(data.b) != 'undefined') { args.b = data.b; } if (typeof(data.c) != 'undefined') { args.c = data.c; } if (typeof(data.s) != 'undefined') { args.s = data.s; } if (typeof(data.p) != 'undefined') { args.p = data.p; } if (typeof(data.x) != 'undefined') { args.x = data.x; } if (typeof(data.t) != 'undefined') { args.t = data.t; } if (typeof(data.r) != 'undefined') { args.r = data.r; } if (typeof(data.f) != 'undefined') { args.f = data.f; } if (typeof(data.v) != 'undefined') { args.v = data.v; } if (typeof(data.w) != 'undefined') { args.w = data.w; } if (typeof(data.wp) != 'undefined') { if (typeof(data.wp.p) != 'undefined') { args.wp.p = data.wp.p; } if (typeof(data.wp.t) != 'undefined') { args.wp.s = data.wp.s; } if (typeof(data.wp.t) != 'undefined') { args.wp.t = data.wp.t; } } if (typeof(data.ref) != 'undefined') { args.ref = data.ref; } $_.getJSON( OHUB.tracker_url + '?cb=?', args, function(data) { OHUB.debug('stat cb'); } ); } }; /** * Returns clickthru tracker URL with support for stat call * @param object data in format: * url: url to click through to, * stat: { (all optional) * c: component_id, * p: publisher_id, * x: action_id, * t: type ('app', 'ad', 'feed', 'video', etc.), * r: feed_item_id, * f: feed_id, * v: video_id, * w: widget_id, * wp.p: post_id, * wp.s: slug, * wp.t: taxonomy * } */ OHUB.clickthru = function(data) { OHUB.debug('clickthru()'); if (typeof(data.stat) != 'object') { OHUB.debug('clickthru passed without stat', 'warn'); } if (typeof(data.url) != 'string') { OHUB.debug('clickthru passed without a URL!', 'warn'); } var url = OHUB.clickthru_url + '?u=' + encodeURIComponent(data.url) + ';'; data.stat.t = (typeof(data.stat.t) != 'undefined') ? data.stat.t : 'app'; data.stat.b = (typeof(data.stat.b) != 'undefined') ? data.stat.b : null; data.stat.c = (typeof(data.stat.c) != 'undefined') ? data.stat.c : null; data.stat.r = (typeof(data.stat.r) != 'undefined') ? data.stat.r : null; data.stat.f = (typeof(data.stat.f) != 'undefined') ? data.stat.f : null; data.stat.s = (typeof(data.stat.s) != 'undefined') ? data.stat.s : null; data.stat.p = (typeof(data.stat.p) != 'undefined') ? data.stat.p : null; data.stat.v = (typeof(data.stat.v) != 'undefined') ? data.stat.v : null; data.stat.w = (typeof(data.stat.w) != 'undefined') ? data.stat.w : null; if (typeof(data.stat.wp) != 'undefined') { data.stat.wp.p = (typeof(data.stat.wp.p) != 'undefined') ? data.stat.wp.p : null; data.stat.wp.s = (typeof(data.stat.wp.s) != 'undefined') ? data.stat.wp.s : null; data.stat.wp.t = (typeof(data.stat.wp.t) != 'undefined') ? data.stat.wp.t : null; } else { data.stat.wp = null; } data.stat.a = (typeof(data.stat.a) != 'undefined') ? data.stat.a : null; url += '&a=' + data.stat.a; url += '&x=1'; url += '&t=' + data.stat.t; if (data.stat.b !== null) { url += '&b=' + data.stat.b; } if (data.stat.c !== null) { url += '&c=' + data.stat.c; } if (data.stat.r !== null) { url += '&r=' + data.stat.r; } if (data.stat.f !== null) { url += '&f=' + data.stat.f; } if (data.stat.s !== null) { url += '&s=' + data.stat.s; } if (data.stat.v !== null) { url += '&v=' + data.stat.v; } if (data.stat.w !== null) { url += '&w=' + data.stat.w; } if (data.stat.wp !== null) { if (data.stat.wp.p !== null) { url += '&wp.p=' + data.stat.wp.p; } if (data.stat.wp.s !== null) { url += '&wp.s=' + data.stat.wp.s; } if (data.stat.wp.t !== null) { url += '&wp.t=' + data.stat.wp.t; } } if (data.stat.p !== null) { url += '&p=' + data.stat.p; } return url; }; /** * Loads latest version of jQuery if it's not already loaded * Assigns window.$_ reference * @param function cb callback * @return void */ OHUB.jquery = function(cb) { OHUB.debug('jquery()'); if (!OHUB.has_jquery()) { OHUB.load('http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js', 'js', function() { window.$_ = jQuery; if (typeof(cb) == 'function') { return cb(); } }); } else { window.$_ = jQuery; if (typeof(cb) == 'function') { return cb(); } } }; /** * Setup CORS * @return void */ OHUB.setup_cors = function() { OHUB.debug('setup_cors()'); if (!OHUB.has_jquery()) { return; } jQuery.support.cors = $_.support.cors = true; $_.ajaxTransport('+*', function(options, originalOptions, jqXHR) { if((jQuery.browser.msie || jQuery.browser.opera || jQuery.browser.safari) && window.XDomainRequest) { var xdr; return { send: function(headers, completeCallback) { // Use Microsoft XDR xdr = new XDomainRequest(); xdr.open('get', options.url); xdr.onload = function() { if(this.contentType.match(/\/xml/)) { var dom = new ActiveXObject('Microsoft.XMLDOM'); dom.async = false; dom.loadXML(this.responseText); completeCallback(200, 'success', [dom]); } else { completeCallback(200, 'success', [this.responseText]); } }; xdr.ontimeout = function() { completeCallback(408, 'error', ['The request timed out.']); }; xdr.onerror = function() { completeCallback(404, 'error', ['The requested resource could not be found.']); }; xdr.send(); }, abort: function() { if (xdr) { xdr.abort(); } } }; } }); }; /** * Loads a JS/CSS file on demand * @param string URL of file * @param string type of file (js|css) * @param function cb callback to fire when loaded * @param string insert_before element * @param boolean duplicates_ok * @return void */ OHUB.load = function(url, type, cb, insert_before, duplicates_ok) { insert_before = (typeof(insert_before) != 'undefined') ? insert_before : null; duplicates_ok = (typeof(duplicates_ok) != 'undefined') ? duplicates_ok : false; OHUB.debug('load(' + url + ' (' + type + '), insert_before=' + insert_before + ', duplicates_ok=' + duplicates_ok + ')', 'log', '', false, 'color: white; background-color: royalblue;'); var cb_called = false; var t = (typeof(type) == 'undefined') ? 'js' : type; var tag = ''; var attrs = {}; switch(t) { case 'js': tag = 'script'; attrs = { type: 'text/javascript', src: url }; break; case 'css': tag = 'link'; attrs = { rel: 'stylesheet', type: 'text/css', href: url }; break; default: return; } var e = document.createElement(tag); if (e.readyState) { e.onreadystatechange = function() { if (e.readyState == 'loaded' || e.readyState == 'complete') { e.onreadystatechange = null; OHUB.debug('loaded : readyState : (' + url + ' [' + type + '])'); if (!OHUB.has_loaded(url, duplicates_ok)) { OHUB.now_loaded(url); } if (typeof(cb) == 'function' && !cb_called) { cb_called = true; return cb(); } } }; } else { e.onload = function() { OHUB.debug('loaded : onload : (' + url + ' [' + type + '])'); if (!OHUB.has_loaded(url, duplicates_ok)) { OHUB.now_loaded(url); } if (typeof(cb) == 'function' && !cb_called) { cb_called = true; return cb(); } }; } for (var attr in attrs) { e[attr] = attrs[attr]; } if (insert_before === null) { document.getElementsByTagName('head')[0].appendChild(e); } else { insert_before.parentNode.insertBefore(e, insert_before); } if (t == 'css' && typeof(cb) == 'function' && !cb_called) { if (!OHUB.has_loaded(url, duplicates_ok)) { OHUB.now_loaded(url); } cb_called = true; return cb(); } }; /** * Pushes a URL into the loaded stack * @param string url to push * @return void */ OHUB.now_loaded = function(url) { OHUB.debug('now_loaded(url=' + url + ')'); var file = ''; if (typeof(url) == 'undefined') { OHUB.debug('now_loaded() - no url passed!', 'warn'); return; } else { var query = url.indexOf('?'); if (query !== -1) { file = url.substring(0, query); } else { file = url; } OHUB.loaded.push(file); } }; /** * Determines if a url is in the loaded stack * @param string url to check for * @param boolean duplicates_ok if TRUE has_loaded returns false (optional, default=false) * @return boolean TRUE If object has been loaded already || FALSE if not */ OHUB.has_loaded = function(url, duplicates_ok) { duplicates_ok = (typeof(duplicates_ok) != 'undefined') ? duplicates_ok : false; OHUB.debug('has_loaded(url=' + url + ', duplicates_ok=' + duplicates_ok + ')'); if (duplicates_ok) { return false; } return (OHUB.in_array(url, OHUB.loaded)); }; /** * DOM ready wrapper - runs when the DOM is ready * (synonymous with jQuery $(document).ready(function() {})) * @param function f callback * @return void */ OHUB.ready = function(f) { OHUB.debug('ready()'); if (OHUB.ready.done) { return f(); } if (OHUB.ready.timer) { OHUB.ready.push(f); } else { OHUB.listen(window, 'load', OHUB.is_ready); if (f) { OHUB.ready.ready = [f]; } OHUB.ready.timer = setInterval(OHUB.is_ready, 10); } }; /** * Timer helper function for OHUB.ready * @return void */ OHUB.is_ready = function() { if (OHUB.ready.done) { return false; } if (document && document.getElementsByTagName && document.getElementById && document.body) { clearInterval(OHUB.ready.timer); OHUB.ready.timer = null; if (typeof(OHUB.ready.ready) != 'undefined') { for (var i=0; i < OHUB.ready.ready.length; i++) { OHUB.ready.ready[i](); } OHUB.ready.ready = null; } OHUB.ready.done = true; OHUB.debug('is_ready()'); } }; /** * Event listener helper function for OHUB.ready * @param HTMLElement element to attach event to * @param string type of event * @param function cb callback * @return void */ OHUB.listen = function(el, type, cb) { OHUB.debug('listen(el=' + el + ', type=' + type + ')'); if (!cb.$$guid) { cb.$$guid = OHUB.listen.guid++; } if (!el.events) { el.events = {}; } var handlers = el.events[type]; if (!handlers) { handlers = el.events[type] = {}; if (el['on' + type]) { handlers[0] = el['on' + type]; } } handlers[cb.$$guid] = cb; el['on' + type] = OHUB.handle_listen; }; OHUB.listen.guid = 1; /** * Event listener handler helper function for OHUB.listen * @param object event * @return void */ OHUB.handle_listen = function(event) { OHUB.debug('handle_listen()'); event = event || window.event; if (typeof(event) == 'undefined') { return; } var handlers = this.events[event.type]; for (var i in handlers) { this.$$handle_listen = handlers[i]; this.$$handle_listen(event); } }; /** * Parses a URL query string and returns object of key=value pairs * @param string url to parse * @returns object of parsed key=value pairs */ OHUB.parse_querystring = function(url) { OHUB.debug('parse_querystring(url=' + url + ')'); var parsed = {}; var e, a = /\+/g; var r = /([^&=]+)=?([^&]*)/g; var d = function (s) { return decodeURIComponent(s.replace(a, ' ')); }; var q = url.substring(url.indexOf('?')+1); while (e = r.exec(q)) { parsed[d(e[1])] = d(e[2]); } return parsed; }; /** * Returns top level domain name (TLD) for a URL * @param string TLD */ OHUB.tld = function(url) { if (url !== '' && typeof(url) != 'undefined') { var domain = (url.match(/:\/\/(.[^\/]+)/)[1]).replace('www.',''); var pieces = domain.split('.'); if (pieces.length == 2) { return domain; } var is_all_numeric = false; for (var piece in pieces) { if (piece == '.') { continue; } is_all_numeric = !isNaN(pieces[piece]); } if (!is_all_numeric) { var tld = pieces[pieces.length - 1]; var name = pieces[pieces.length - 2]; domain = name + '.' + tld; } return domain; } else { return url; } }; /** * Dim / fade-in black transparency * @param float speed to fade-in * @param float opacity to fade to * @param function callback after dim * @return void */ OHUB.dim = function(speed, opacity, callback) { OHUB.debug('dim()'); if ($_('#OHUB_DIMMER').length === 0) { OHUB.add_dimmer(); } var dimmer = $_('#OHUB_DIMMER'); dimmer.fadeTo(speed, opacity, function() { dimmer.data('is_dimmed', true); if (typeof(callback) == 'function') { callback(); } }); }; /** * Undim the UI / fade-out black transparency * @param float speed to fade-out * @param function callback after undim * @return void */ OHUB.undim = function(speed, callback) { OHUB.debug('undim()'); var dimmer = $_('#OHUB_DIMMER'); $_(window).unbind('resize.OHUB_dimmer'); dimmer.fadeOut(speed, function() { dimmer.data('is_dimmed', false); if (typeof(callback) == 'function') { callback(); } }); }; /** * Add the dimmer * @return void */ OHUB.add_dimmer = function() { OHUB.debug('add_dimmer()'); var dimmer = $_('#OHUB_DIMMER'); if (dimmer.length === 0) { $_('body').prepend('
'); dimmer = $_('#OHUB_DIMMER'); var nhz = OHUB.get_nhz(); dimmer.css({ position: 'fixed', backgroundColor: '#000', zIndex: nhz, margin: 0, left: 0, top: 0, height: $_(window).height(), width: '100%' }); $_(window).unbind('resize.OHUB_dimmer').bind('resize.OHUB_dimmer', function() { var dimmer = $_('#OHUB_DIMMER'); if (dimmer.data('is_dimmed')) { dimmer.css({ height: $_(window).height() }); } }); } }; /** * Include external files (js/css) * @param array includes files to include * @param boolean duplicates_ok if already loaded ok to load duplicate? * @param function cb callback after all included * @param HTMLElement insert_before element * @return void */ /*OHUB.includes = function(files, cb, duplicates_ok, insert_before) { OHUB.debug('includes(files=' + files.join(', ') + '), duplicates_ok=' + duplicates_ok + ', insert_before=' + insert_before +')'); OHUB.loaded = (typeof(OHUB.loaded) != 'undefined') ? OHUB.loaded : []; duplicates_ok = (typeof(duplicates_ok) != 'undefined') ? duplicates_ok : false; insert_before = (typeof(insert_before) != 'undefined') ? insert_before : null; cb = (typeof(cb) == 'undefined') ? function() {} : cb; var loads = [], cb_called = false, file = '', ext = '', poll_interval = null; poll_interval = setInterval(function() { done_yet(); }, 100); if (!OHUB.is_array(files)) { OHUB.debug('include() files is not an array! aborting!', 'warn'); } else if (!OHUB.has_jquery()) { OHUB.debug('jQuery required - call OHUB.jquery(function(){}) before files! aborting!', 'warn'); } else { for (var i=0; i < files.length; i++) { var include = files[i]; var query = include.indexOf('?'); if (query !== -1) { file = include.substring(0, query); ext = include.substring(include.lastIndexOf('.') + 1, query); } else { file = include; ext = include.substring(include.lastIndexOf('.') + 1); } if ($_.inArray(file, OHUB.loaded) != -1 && !duplicates_ok) { OHUB.debug('includes() file: "' + file + '" already loaded and no duplicates allowed! aborting!', 'warn'); loads.unshift(include); } else { OHUB.loaded.push(file); $_('body').queue('OHUB_includes', (function(include, ext, insert_before, cb, loads) { return OHUB.load(include, ext, function() { loads.unshift(include); $_('body').dequeue('OHUB_includes'); }, insert_before); })(include, ext, insert_before, cb, loads) ); } } } function done_yet() { if (loads.length == files.length) { clearInterval(poll_interval); poll_interval = null; if (!cb_called) { cb_called = true; if (typeof(cb) == 'function') { return cb(); } } } } }; */ /** * Determine if needle is in array haystack * @param string needle * @param array arr Array haystack * @return boolean TRUE if found || FALSE if not found */ OHUB.in_array = function(needle, haystack) { OHUB.debug('in_array(needle=' + needle + ')'); if (!OHUB.is_array(haystack)) { OHUB.debug('in_array() - haystack is not an array! aborting!', 'warn'); } if (typeof(needle) != 'string') { OHUB.debug('in_array() - needle is not a string! aborting!', 'warn'); } return (String('|' + haystack.join('|') + '|').indexOf('|' + needle + '|') !== -1); }; /** * Determines if arg is array * @return boolean TRUE if array || FALSE otherwise */ OHUB.is_array = function(arr) { return (typeof(arr) == 'object' && typeof(arr.length) == 'number'); }; /** * Returns the file name minus extension for a URL * @return string context for URL */ OHUB.url_context = function(url) { this.debug('url_context(url=' + url + ')'); if (typeof(url) !== 'undefined') { return url.split('/')[url.split('/').length-1].split('.')[0]; } }; /** * Determines if jQuery is already loaded * @return boolean TRUE if jQuery loaded || FALSE if not * @type Object */ OHUB.has_jquery = function() { OHUB.debug('has_jquery()'); return (typeof(jQuery) == 'function'); }; /** * Debug message handler * @param mixed out string, func, or object * @param string type of message { warn | info | error | [log]} * @param string ident identity of debug message * @param boolean force debugging (even if debugging is off?) * @param object style (optional) console.log style formatting * @return void */ OHUB.debug = function(out, type, ident, force, style) { ident = (typeof(ident) != 'undefined' && ident !== '') ? ident : 'OHUB.core'; force = (typeof(force) != 'undefined') ? force : false; style = (typeof(style) != 'undefined') ? style : null; hasfb = (typeof(window.console) == 'object' && typeof(window.console.warn) == 'function'); if (!OHUB.DEBUG && !force) { return; } if (ident == 'OHUB.core' && style === null) { style = 'color: blue;'; } try { if (typeof(console) == 'object') { if (typeof(console[type]) != 'function') { type = 'log'; } switch(typeof(out)) { case 'string': case 'function': ident += ': '; switch(type) { case 'warn': console.warn(ident + out); break; case 'info': console.info(ident + out); break; case 'error': console.error(ident + out); break; default: if (style === null) { console.log(ident + out); } else { if (hasfb) { console.log('%c' + ident + out, style); } else { console.log(ident + out); } } break; } break; case 'object': eval("console.dir({ '" + ident + "': out } );"); break; } } } catch(e) { } }; OHUB.CORE = true;