//************************************************/ /* IPB3 Javascript */ /* -------------------------------------------- */ /* ipb.js - Global code */ /* (c) IPS, Inc 2008 */ /* -------------------------------------------- */ /* Author: Rikki Tissier */ /************************************************/ /* ===================================================================================================== */ /* IPB3 JS Debugging */ var USE_RTE = 0; var Debug = { write: function( text ){ if( jsDebug && !Object.isUndefined(window.console) ){ console.log( text ); } /*else if( jsDebug ) { if( !$('_inline_debugging') ){ var _inline_debug = new Element('div', { id: '_inline_debugging' }).setStyle('background: rgba(0,0,0,0.7); color: #fff; padding: 10px; width: 97%; height: 150px; position: absolute; bottom: 0; overflow: auto; z-index: 50000').show(); if( !Object.isUndefined( $$('body')[0] ) ){ $$('body')[0].insert( _inline_debug ); } } try { $('_inline_debugging').innerHTML += "
" + text; } catch(err){} }*/ }, dir: function( values ){ if( jsDebug && !Object.isUndefined(window.console) && ! Prototype.Browser.IE && ! Prototype.Browser.Opera ){ console.dir( values ); } }, error: function( text ){ if( jsDebug && !Object.isUndefined(window.console) ){ console.error( text ); } }, warn: function( text ){ if( jsDebug && !Object.isUndefined(window.console) ){ console.warn( text ); } }, info: function( text ){ if( jsDebug && !Object.isUndefined(window.console) ){ console.info( text ); } } }; /* Set up version specifics */ Prototype.Browser.IE6 = Prototype.Browser.IE && parseInt(navigator.userAgent.substring(navigator.userAgent.indexOf("MSIE")+5)) == 6; Prototype.Browser.IE7 = Prototype.Browser.IE && parseInt(navigator.userAgent.substring(navigator.userAgent.indexOf("MSIE")+5)) == 7; Prototype.Browser.IE8 = Prototype.Browser.IE && parseInt(navigator.userAgent.substring(navigator.userAgent.indexOf("MSIE")+5)) == 8; Prototype.Browser.IE9 = Prototype.Browser.IE && parseInt(navigator.userAgent.substring(navigator.userAgent.indexOf("MSIE")+5)) == 9; /* Add in stuff prototype does not include */ Prototype.Browser.Chrome = Prototype.Browser.WebKit && ( navigator.userAgent.indexOf('Chrome/') > -1 ); /* Older browsers do not have String.trim() */ if ( !String.prototype.trim ) { String.prototype.trim = function(){ return this.replace(/^\s+|\s+$/g, ''); }; } /* ===================================================================================================== */ /* OVERWRITE getOffsetParent TO FIX TD ISSUE */ function isBody(element) { return element.nodeName.toUpperCase() === 'BODY'; } function isHtml(element) { return element.nodeName.toUpperCase() === 'HTML'; } function isDocument(element) { return element.nodeType === Node.DOCUMENT_NODE; } function isDetached(element) { return element !== document.body && !Element.descendantOf(element, document.body); } Element.Methods.getOffsetParent = function(element) { element = $(element); if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element)) return $(document.body); if( Prototype.Browser.IE ){ if (element.offsetParent && element.offsetParent != document.body && Element.getStyle( element.offsetParent, 'position' ) != 'static') return $(element.offsetParent); if (element == document.body) return $(element); } else { var isInline = (Element.getStyle(element, 'display') === 'inline'); if (!isInline && element.offsetParent && Element.getStyle(element.offsetParent,'position') != 'static') return $(element.offsetParent); } while ((element = element.parentNode) && element !== document.body) { if (Element.getStyle(element, 'position') !== 'static') { return isHtml(element) ? $(document.body) : $(element); } } return $(document.body); } /*Event.observe( window, 'load', function(e){ Element.Methods.getOffsetParent = function( element ){ //alert( "Using overloaded getOffsetParent" ); if (element.offsetParent && element.offsetParent != document.body) return $(element.offsetParent); if (element == document.body) return $(element); while ((element = element.parentNode) && element != document.body) if (Element.getStyle(element, 'position') != 'static') return $(element); return $(document.body); }; }); function _getOffsetParent( element ) { //alert( "Using overloaded getOffsetParent" ); if (element.offsetParent && element.offsetParent != document.body) return $(element.offsetParent); if (element == document.body) return $(element); while ((element = element.parentNode) && element != document.body ) if (Element.getStyle(element, 'position') != 'static') return $(element); return $(document.body); }*/ /* ===================================================================================================== */ /* MAIN ROUTINE */ window.IPBoard = Class.create({ namePops: [], topicPops: [], vars: [], lang: [], templates: [], editors: $A(), initDone: false, initialize: function() { Debug.write("IPB js is loading..."); document.observe("dom:loaded", function(){ this.Cookie.init(); // Show a little loading graphic Ajax.Responders.register({ onLoading: function( handler ) { if( !Object.isUndefined( handler['options']['hideLoader'] ) && handler['options']['hideLoader'] != false ){ return; } if( !$('ajax_loading') ){ if( !ipb.templates['ajax_loading'] ){ return; } $('ipboard_body').insert( ipb.templates['ajax_loading'] ); } var effect = new Effect.Appear( $('ajax_loading'), { duration: 0.2 } ); }, onComplete: function() { if( !$('ajax_loading') || !$('ajax_loading').visible() ){ return; } var effect = new Effect.Fade( $('ajax_loading'), { duration: 0.2 } ); if ( ! Object.isUndefined( ipb.hoverCard ) ){ ipb.hoverCardRegister.postAjaxInit(); } /* General links to functions */ $$("[data-clicklaunch]").invoke('clickLaunch'); /* Quote functions */ ipb.global.parseQuoteBoxes(); ipb.global.removeLinkedLightbox(); }, onSuccess: function() { if ( ! Object.isUndefined( ipb.hoverCard ) ){ ipb.hoverCardRegister.postAjaxInit(); } }, onFailure: function( t ) { if( !$('ajax_loading') || !$('ajax_loading').visible() ){ return; } var effect = new Effect.Fade( $('ajax_loading'), { duration: 0.2 } ); if ( ! Object.isUndefined( ipb.global ) ) { ipb.global.showInlineNotification( ipb.lang['ajax_failure'] ); } }, onException: function( t, exception ) { if( !$('ajax_loading') || !$('ajax_loading').visible() ){ return; } var effect = new Effect.Fade( $('ajax_loading'), { duration: 0.2 } ); Debug.error( exception ); if ( ! Object.isUndefined( ipb.global ) ) { //ipb.global.showInlineNotification( ipb.lang['ajax_failure'] ); } } }); // Initialize our delegation manager ipb.delegate.initialize(); ipb.initDone = true; }.bind(this)); }, positionCenter: function( elem, dir ) { if( !$(elem) ){ return; } elem_s = $(elem).getDimensions(); window_s = document.viewport.getDimensions(); window_offsets = document.viewport.getScrollOffsets(); center = { left: ((window_s['width'] - elem_s['width']) / 2), top: ((window_s['height'] - elem_s['height']) / 2) }; if( typeof(dir) == 'undefined' || ( dir != 'h' && dir != 'v' ) ) { $(elem).setStyle('top: ' + center['top'] + 'px; left: ' + center['left'] + 'px'); } else if( dir == 'h' ) { $(elem).setStyle('left: ' + center['left'] + 'px'); } else if( dir == 'v' ) { $(elem).setStyle('top: ' + center['top'] + 'px'); } $(elem).setStyle('position: fixed'); }, showModal: function() { if( !$('ipb_modal') ) { this.createModal(); } this.modal.show(); }, hideModal: function() { if( !$('ipb_modal') ){ return; } this.modal.hide(); }, createModal: function() { this.modal = new Element('div', { id: 'ipb_modal' } ).hide().addClassName('modal'); this.modal.setStyle("width: 100%; height: 100%; position: fixed; top: 0px; left: 0px; overflow: hidden; z-index: 1000; opacity: 0.2"); $('ipboard_body').insert({bottom: this.modal}); }, editorInsert: function( content, editorid ) { // If no editor id supplied, lets use the first one if( !editorid ) { var editor = ipb.textEditor.getEditor(); } else { var editor = ipb.textEditor.getEditor(editorid); } if( Object.isUndefined( editor ) ) { /* Get current */ var editor = ipb.textEditor.getEditor(); } editor.insert( content ); } }); /* ===================================================================================================== */ /* IPB3 Delegation manager */ /* Simple class that allows us to specify css selectors and an associated function to run */ /* when an appropriate element is clicked */ IPBoard.prototype.delegate = { store: $A(), initialize: function() { document.observe('click', function(e){ if( Event.isLeftClick(e) || Prototype.Browser.IE || ipb.vars['is_touch'] ) // IE doesnt provide isLeftClick info for click event, touch devices either { var elem = null; var handler = null; var target = ipb.delegate.store.find( function(item){ elem = e.findElement( item['selector'] ); if( elem ){ handler = item; return true; } else { return false; } }); if( !Object.isUndefined( target ) ) { if( handler ) { Debug.write("Firing callback for selector " + handler['selector'] ); handler['callback']( e, elem, handler['params'] ); } } } }); }, register: function( selector, callback, params ) { ipb.delegate.store.push( { selector: selector, callback: callback, params: params } ); } }; /* ===================================================================================================== */ /* IPB3 Cookies */ /* Meow */ IPBoard.prototype.Cookie = { store: [], initDone: false, set: function( name, value, sticky ) { var expires = ''; var path = '/'; var domain = ''; if( !name ) { return; } if( sticky ) { if( sticky == 1 ) { expires = "; expires=Wed, 1 Jan 2020 00:00:00 GMT"; } else if( sticky == -1 ) // Delete { expires = "; expires=Thu, 01-Jan-1970 00:00:01 GMT"; } else if( sticky.length > 10 ) { expires = "; expires=" + sticky; } } if( ipb.vars['cookie_domain'] ) { domain = "; domain=" + ipb.vars['cookie_domain']; } if( ipb.vars['cookie_path'] ) { path = ipb.vars['cookie_path']; } document.cookie = ipb.vars['cookie_id'] + name + "=" + escape( value ) + "; path=" + path + expires + domain + ';'; ipb.Cookie.store[ name ] = value; Debug.write( "Set cookie: " + ipb.vars['cookie_id'] + name + "=" + value + "; path=" + path + expires + domain + ';' ); }, get: function( name ) { /* Init done yet? */ if ( ipb.Cookie.initDone !== true ) { ipb.Cookie.init(); } if( ipb.Cookie.store[ name ] ) { return ipb.Cookie.store[ name ]; } return ''; }, doDelete: function( name ) { Debug.write("Deleting cookie " + name); ipb.Cookie.set( name, '', -1 ); }, init: function() { // Already init? if ( ipb.Cookie.initDone ) { return true; } // Init cookies by pulling in document.cookie skip = ['session_id', 'ipb_admin_session_id', 'member_id', 'pass_hash']; cookies = $H( document.cookie.replace(" ", '').toQueryParams(";") ); if( cookies ) { cookies.each( function(cookie){ cookie[0] = cookie[0].strip(); if( ipb.vars['cookie_id'] != '' ) { if( !cookie[0].startsWith( ipb.vars['cookie_id'] ) ) { return; } else { cookie[0] = cookie[0].replace( ipb.vars['cookie_id'], '' ); } } if( skip[ cookie[0] ] ) { return; } else { ipb.Cookie.store[ cookie[0] ] = unescape( cookie[1] || '' ); Debug.write( "Loaded cookie: " + cookie[0] + " = " + cookie[1] ); } }); } ipb.Cookie.initDone = true; } }; /* ===================================================================================================== */ /* Form validation */ IPBoard.prototype.validate = { // Checks theres actually a value isFilled: function( elem ) { if( !$( elem ) ){ return null; } return !$F(elem).blank(); }, isNumeric: function( elem ) { if( !$( elem ) ){ return null; } return $F(elem).match( /^[\d]+?$/ ); }, isMatching: function( elem1, elem2 ) { if( !$( elem1 ) || !$( elem2 ) ){ return null; } return $F(elem1) == $F(elem2); }, email: function( elem ) { if( !$( elem ) ){ return null; } if( $F( elem ).match( /^.+@.+\..{2,4}$/ ) ){ return true; } else { return false; } } }; /* ===================================================================================================== */ /* AUTOCOMPLETE */ IPBoard.prototype.Autocomplete = Class.create( { initialize: function(id, options) { this.id = $( id ).id; this.timer = null; this.last_string = ''; this.internal_cache = $H(); this.pointer = 0; this.items = $A(); this.observing = true; this.objHasFocus = null; this.options = Object.extend({ min_chars: 3, multibox: false, global_cache: false, goToUrl: false, classname: 'ipb_autocomplete', templates: { wrap: new Template(""), item: new Template("
  • #{itemvalue}
  • ") } }, arguments[1] || {}); //----------------------------------------- if( !$( this.id ) ){ Debug.error("Invalid textbox ID"); return false; } this.obj = $( this.id ); if( !this.options.url ) { Debug.error("No URL specified for autocomplete"); return false; } $( this.obj ).writeAttribute('autocomplete', 'off'); this.buildList(); // Observe keypress $( this.obj ).observe('focus', this.timerEventFocus.bindAsEventListener( this ) ); $( this.obj ).observe('blur', this.timerEventBlur.bindAsEventListener( this ) ); $( this.obj ).observe('keydown', this.eventKeypress.bindAsEventListener( this ) ); }, eventKeypress: function(e) { if( ![ Event.KEY_TAB, Event.KEY_UP, Event.KEY_DOWN, Event.KEY_LEFT, Event.KEY_RIGHT, Event.KEY_RETURN ].include( e.keyCode ) ){ return; // Not interested in anything else } // & and up key are both keycode 38. So if we're holding shift, ignore this console.log( e.shiftKey ); if ( e.shiftKey === true ) { return; } if( $( this.list ).visible() ) { switch( e.keyCode ) { case Event.KEY_TAB: case Event.KEY_RETURN: this.selectCurrentItem(e); break; case Event.KEY_UP: case Event.KEY_LEFT: this.selectPreviousItem(e); break; case Event.KEY_DOWN: case Event.KEY_RIGHT: this.selectNextItem(e); break; } Event.stop(e); } }, // MOUSE & KEYBOARD EVENT selectCurrentItem: function(e) { var current = $( this.list ).down('.active'); this.unselectAll(); if( !Object.isUndefined( current ) ) { var itemid = $( current ).id.replace( this.id + '_ac_item_', ''); if( !itemid ){ return; } // Go to URL? if( this.options.goToUrl && $( current ).readAttribute('data-url') ) { window.location = $( current ).readAttribute('data-url'); return false; } // Get value var value = this.items[ itemid ] .replace('&', '&') .replace( /'/g, "'" ) .replace( />/g, '>' ) .replace( /</g, '<' ) .replace( /!/g, '!' ); if( this.options.multibox ) { // some logic to get current name if( $F( this.obj ).indexOf(',') !== -1 ) { var pieces = $F( this.obj ).split(','); pieces[ pieces.length - 1 ] = ''; $( this.obj ).value = pieces.join(',') + ' '; } else { $( this.obj ).value = ''; $( this.obj ).focus(); } $( this.obj ).value = $F( this.obj ) + value + ', '; } else { $( this.obj ).value = value; var effect = new Effect.Fade( $(this.list), { duration: 0.3 } ); //this.observing = false; } } $( this.obj ).focus(); /* Stop cursor jumping back when adding input */ if ( Prototype.Browser.IE ) { if ( $( this.obj ).createTextRange ) { var r = $( this.obj ).createTextRange(); r.moveStart("character", $( this.obj ).value.length); r.select(); } } }, // MOUSE EVENT selectThisItem: function(e) { this.unselectAll(); var items = $( this.list ).immediateDescendants(); var elem = Event.element(e); // Find the element while( !items.include( elem ) ) { elem = elem.up(); } $( elem ).addClassName('active'); }, // KEYBOARD EVENT selectPreviousItem: function(e) { var current = $( this.list ).down('.active'); this.unselectAll(); if( Object.isUndefined( current ) ) { this.selectFirstItem(); } else { var prev = $( current ).previous(); if( prev ){ $( prev ).addClassName('active'); } else { this.selectLastItem(); } } }, // KEYBOARD EVENT selectNextItem: function(e) { // Get the current item var current = $( this.list ).down('.active'); this.unselectAll(); if( Object.isUndefined( current ) ){ this.selectFirstItem(); } else { var next = $( current ).next(); if( next ){ $( next ).addClassName('active'); } else { this.selectFirstItem(); } } }, // INTERNAL CALL selectFirstItem: function() { if( !$( this.list ).visible() ){ return; } this.unselectAll(); $( this.list ).firstDescendant().addClassName('active'); }, // INTERNAL CALL selectLastItem: function() { if( !$( this.list ).visible() ){ return; } this.unselectAll(); var d = $( this.list ).immediateDescendants(); var l = d[ d.length -1 ]; if( l ) { $( l ).addClassName('active'); } }, unselectAll: function() { $( this.list ).childElements().invoke('removeClassName', 'active'); }, // Ze goggles are blurry! timerEventBlur: function(e) { window.clearTimeout( this.timer ); this.eventBlur.bind(this).delay( 0.6, e ); }, // Phew, ze goggles are focussed again timerEventFocus: function(e) { this.timer = this.eventFocus.bind(this).delay(0.4, e); }, eventBlur: function(e) { this.objHasFocus = false; if( $( this.list ).visible() ) { var effect = new Effect.Fade( $(this.list), { duration: 0.3 } ); } }, eventFocus: function(e) { if( !this.observing ){ Debug.write("Not observing keypress"); return; } this.objHasFocus = true; // Keep loop going this.timer = this.eventFocus.bind(this).delay(0.6, e); var curValue = this.getCurrentName(); if( curValue == this.last_string ){ return; } if( curValue.length < this.options.min_chars ){ // Hide list if necessary if( $( this.list ).visible() ) { var effect = new Effect.Fade( $( this.list ), { duration: 0.3, afterFinish: function(){ $( this.list ).update(); }.bind(this) } ); } return; } this.last_string = curValue; // Cached? json = this.cacheRead( curValue ); if( json == false ){ // No results yet, get them var request = new Ajax.Request( this.options.url + escape( curValue ), { method: 'get', evalJSON: 'force', onSuccess: function(t) { if( Object.isUndefined( t.responseJSON ) ) { // Well, this is bad. Debug.error("Invalid response returned from the server"); return; } if( t.responseJSON['error'] ) { switch( t.responseJSON['error'] ) { case 'requestTooShort': Debug.warn("Server said request was too short, skipping..."); break; default: Debug.error("Server returned an error: " + t.responseJSON['error']); break; } return false; } if( t.responseText != "[]" ) { // Seems to be OK! this.cacheWrite( curValue, t.responseJSON ); this.updateAndShow( t.responseJSON ); } }.bind( this ) } ); } else { this.updateAndShow( json ); } //Debug.write( curValue ); }, updateAndShow: function( json ) { if( !json ){ return; } this.updateList( json ); if( !$( this.list ).visible() && this.objHasFocus ) { Debug.write("Showing"); var effect = new Effect.Appear( $( this.list ), { duration: 0.3, afterFinish: function(){ this.selectFirstItem(); }.bind(this) } ); } }, cacheRead: function( value ) { if( this.options.global_cache != false ) { if( !Object.isUndefined( this.options.global_cache.get( value ) ) ){ Debug.write("Read from global cache"); return this.options.global_cache.get( value ); } } else { if( !Object.isUndefined( this.internal_cache.get( value ) ) ){ Debug.write("Read from internal cache"); return this.internal_cache.get( value ); } } return false; }, cacheWrite: function( key, value ) { if( this.options.global_cache !== false ){ this.options.global_cache.set( key, value ); } else { this.internal_cache.set( key, value ); } return true; }, getCurrentName: function() { if( this.options.multibox ) { // some logic to get current name if( $F( this.obj ).indexOf(',') === -1 ){ return $F( this.obj ).strip(); } else { var pieces = $F( this.obj ).split(','); var lastPiece = pieces[ pieces.length - 1 ]; return lastPiece.strip(); } } else { return $F( this.obj ).strip(); } }, buildList: function() { if( $( this.id + '_ac' ) ) { return; } var finalPos = {}; // Position menu to keep it on screen var sourcePos = $( this.id ).viewportOffset(); var sourceDim = $( this.id ).getDimensions(); var delta = [0,0]; var parent = null; var screenScroll = document.viewport.getScrollOffsets(); var ul = this.options.templates.wrap.evaluate({ id: this.id + '_ac' }); /* In a modal pop up? */ var test = $( this.id ).up('.popupWrapper'); if ( ! Object.isUndefined( test ) && test.getStyle('position') == 'fixed' ) { $(this.id).up().insert( {bottom: ul} ); parent = $( this.id ).getOffsetParent(); delta = [ parseInt( parent.getStyle('left') / 2 ), parseInt( parent.getStyle('top') / 2 ) ]; finalPos['left'] = delta[0]; finalPos['top'] = delta[1] + screenScroll.top; /* Make it appear over */ $( this.id + '_ac' ).setStyle( { 'zIndex': 10002 } ); } else { $$('body')[0].insert( {bottom: ul} ); if ( Element.getStyle( $( this.id ), 'position') == 'absolute') { parent = $( this.id ).getOffsetParent(); delta = [ parseInt( parent.getStyle('left') ), parseInt( parent.getStyle('top') ) ]; } finalPos['left'] = sourcePos[0] - delta[0]; finalPos['top'] = sourcePos[1] - delta[1] + screenScroll.top; } // Now try and keep it on screen finalPos['top'] = finalPos['top'] + sourceDim.height; $( this.id + '_ac' ).setStyle('position: absolute; top: ' + finalPos['top'] + 'px; left: ' + finalPos['left'] + 'px;').hide(); this.list = $( this.id + '_ac' ); }, updateList: function( json ) { if( !json || !$( this.list ) ){ return; } var newitems =''; this.items = $A(); json = $H( json ); json.each( function( item ) { var li = this.options.templates.item.evaluate({ id: this.id + '_ac_item_' + item.key, itemid: item.key, itemvalue: item.value['showas'] || item.value['name'], img: item.value['img'] || '', img_w: item.value['img_w'] || '', img_h: item.value['img_h'] || '', url: item.value['url'] || '' }); this.items[ item.key ] = item.value['name']; newitems = newitems + li; }.bind(this) ); $( this.list ).update( newitems ); $( this.list ).immediateDescendants().each( function(elem){ $( elem ).observe('mouseover', this.selectThisItem.bindAsEventListener(this)); $( elem ).observe('click', this.selectCurrentItem.bindAsEventListener(this)); $( elem ).setStyle('cursor: pointer'); }.bind(this)); if( $( this.list ).visible() ) { this.selectFirstItem(); } } }); /** * Get query string param */ getQueryStringParamByName = function(name) { name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); var regexS = "[\\?&]" + name + "=([^&#]*)"; var regex = new RegExp(regexS); var results = regex.exec(window.location.search); if ( results == null ) { return ""; } else { return decodeURIComponent( results[1].replace(/\+/g, " ") ); } }; /* ===================================================================================================== */ /* Extended objects */ // Extend RegExp with escape Object.extend( RegExp, { escape: function(text) { if (!arguments.callee.sRE) { var specials = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$' ]; //arguments.callee.sRE = new RegExp( '(\\' + specials.join('|\\') + ')' ); // IMPORTANT: dont use g flag arguments.callee.sRE = new RegExp( '(\\' + specials.join('|\\') + ')', 'g' ); } return text.replace(arguments.callee.sRE, '\\$1'); } }); // Escape regex String.prototype.regExpEscape = function() { var text = this; return text.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); }; // Extend String with HTMLspecial chars String.prototype.escapeHtml = function() { return this .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); }; //Extend String with HTMLspecial chars String.prototype.unEscapeHtml = function() { var _t = this.replace( /&/g, "&" ); return _t .replace(/</g, "<") .replace(/>/g, ">") .replace(/"/g, '"') .replace(/'/g, "'") .replace(/'/g, "'"); }; // Extend String with URL UTF-8 escape String.prototype.encodeUrl = function() { var text = this; var regcheck = text.match(/[\x90-\xFF]/g); if ( regcheck ) { for (var i = 0; i < regcheck.length; i++) { text = text.replace(regcheck[i], '%u00' + (regcheck[i].charCodeAt(0) & 0xFF).toString(16).toUpperCase()); } } return escape(text).replace(/\+/g, "%2B").replace(/%20/g, '+').replace(/\*/g, '%2A').replace(/\//g, '%2F').replace(/@/g, '%40'); }; // Extend String with URL UTF-8 escape - duplicated so it can be changed from above String.prototype.encodeParam = function() { var text = this; var regcheck = text.match(/[\x90-\xFF]/g); if ( regcheck ) { for (var i = 0; i < regcheck.length; i++) { text = text.replace(regcheck[i], '%u00' + (regcheck[i].charCodeAt(0) & 0xFF).toString(16).toUpperCase()); } } /* Return just text as it is then encoded by prototype lib */ return escape(text).replace(/\+/g, "%2B"); }; // Extend date object to return date and time as object Date.prototype.getDateAndTime = function( unix ) { var a = new Date( parseInt( unix ) * 1000 ); var months = ipb.lang['gbl_months'].split(','); var year = a.getFullYear(); var month = months[a.getMonth()]; var date = a.getDate(); var hour = a.getHours(); var min = a.getMinutes(); var sec = a.getSeconds(); return { year : year, monthName: month, month : ( '0' + a.getMonth() + 1 ).slice( -2 ), date : ( '0' + date ).slice( -2 ), hour : ( '0' + hour ).slice( -2 ), min : ( '0' + min ).slice( -2 ), sec : ( '0' + sec ).slice( -2 ), dst : a.getTimezoneOffset() }; }; // Extend Date object with a function to check for DST Date.prototype.getDST = function() { var beginning = new Date( "January 1, 2008" ); var middle = new Date( "July 1, 2008" ); var difference = middle.getTimezoneOffset() - beginning.getTimezoneOffset(); var offset = this.getTimezoneOffset() - beginning.getTimezoneOffset(); if( difference != 0 ) { /* Hemisphere check */ if ( difference < 0 ) { /* Northern */ return (difference == offset) ? 1 : 0; } else { /* Southern */ return (difference != offset) ? 1 : 0; } } else { return 0; } }; /* ==================================================================================================== */ /* IPB3 JS Loader */ var Loader = { require: function( name ) { document.write(""); }, boot: function() { $A( document.getElementsByTagName("script") ).findAll( function(s) { return (s.src && s.src.match(/ipb\.js(\?.*)?$/)); } ).each( function(s) { var path = s.src.replace(/ipb\.js(\?.*)?$/,''); var includes = s.src.match(/\?.*load=([a-zA-Z0-9_,\.]*)/); if( ! Object.isUndefined(includes) && includes != null && includes[1] ) { includes[1].split(',').each( function(include) { if( include ) { Loader.require( path + "ips." + include ); } } ); } } ); } }; var callback = { afterOpen: function( popup ){ try { $( 'pj_' + $(elem).identify() + '_input').activate(); } catch(err){ } } }; /* ==================================================================================================== */ /* ELEMENT EXTENSIONS (tooltips, authorpane etc.) */ Element.addMethods( { getInnerText: function(element) { element = $(element); return element.innerText && ! window.opera ? element.innerText : element.innerHTML.stripScripts().unescapeHTML().replace(/[\n\r\s]+/g, ' '); }, defaultize: function( element, lang ) { if( ipb.global._supportsPlaceholder == null ){ ipb.global._supportsPlaceholder = (function(){ var i = document.createElement('input'); return 'placeholder' in i; })(); } if( ipb.global._supportsPlaceholder ){ if( $F( element ) == lang || $F( element ).empty() ){ $(element).removeClassName('inactive').writeAttribute('placeholder', lang).value = ''; } } else { if( $F( element ) == lang || $F( element ).empty() ){ $(element).addClassName('inactive').value = lang; } $(element).observe('focus', function(e){ if( $(element).hasClassName('inactive') && ( $F(element) == '' || $F(element) == lang ) ){ $(element).removeClassName('inactive').value = ''; } else { $(element).removeClassName('inactive'); } }). observe('blur', function(e){ if( $F(element).empty() ){ $(element).addClassName('inactive').value = lang; } }); // Try and find a form around the element var form = $( element ).up('form'); if( !Object.isUndefined( form ) ){ $( form ).observe('submit', function(e){ if( $(element).hasClassName('inactive') ){ $(element).value = ''; } }); } } }, clickLaunch: function( element ) { var _callback = $( element ).readAttribute("data-clicklaunch"); var _scope = 'global'; try { var _try = $( element ).readAttribute("data-scope"); _scope = ( _try ) ? _try.replace("ipb.", '') : _scope; } catch(e) { }; if( $(element).retrieve('clickevent') ){ try { $(element).retrieve('clickevent').stop(); } catch(err){ }; } var click = $(element).on( 'click', function(e) { Event.stop(e); ipb[_scope][_callback]( element, e); } ); $(element).store('clickevent', click); }, confirmAction: function( element, callback ) { var _text = $( element ).readAttribute("data-confirmaction"); var _ok = ''; if( callback ) { _ok = callback; } else if ( element.tagName == 'FORM' ) { _ok = "$('" + element.id +"').submit()"; } else { _ok = 'window.location=\'' + element.readAttribute( 'href' ) + '\''; } if ( ! _text || _text == 'true' ) { _text = ipb.lang['gbl_confirm_desc']; } var _options = { type: 'pane', modal: true, /* Inline JS makes it easier even if it is uglier */ initial: '

    ' + ipb.lang['gbl_confirm_text'] + '

    ' + _text + '


    ' + ipb.lang['gbl_confirm_cancel'] + '   ' + ipb.lang['gbl_confirm_ok'] + '
    ', hideAtStart: false, w: '300px', h: 150 }; if ( element.tagName == 'FORM' || callback ) { /* Fire immediately */ if ( ! Object.isUndefined( ipb.global.popups['conact'] ) ) { ipb.global.popups['conact'].kill(); } ipb.global.popups['conact'] = new ipb.Popup( 'confirm', _options ); } else { $(element).on( 'click', function(e) { Event.stop(e); if ( ! Object.isUndefined( ipb.global.popups['conact'] ) ) { ipb.global.popups['conact'].kill(); } ipb.global.popups['conact'] = new ipb.Popup( 'confirm', _options ); } ); } }, tooltip: function( element, options ){ options = Object.extend( { template: new Template(""), position: 'auto', content: $( element ).readAttribute("data-tooltip").stripTags().escapeHTML(), animate: true, overrideBrowser: true, delay: 0.4 }, options); var show = function(e){ if( options.delay && !options._still_going ){ return; // Action has been cancelled } // Don't show if empty. Bug #36247 Tooltips if( ! options.content ){ return; } var id = $(element).identify(); if( !$( id + '_tooltip' ) ){ $( document.body ).insert({ 'bottom': options.template.evaluate({ 'id': id + '_tooltip', 'content': options.content }) } ); } if( options.overrideBrowser && $(element).hasAttribute('title') ){ $(element).writeAttribute("data-title", $(element).readAttribute('title').stripTags().escapeHTML()).writeAttribute("title", false); } var tooltip = $(id + '_tooltip').setStyle({position: 'absolute'}); // Add word wrap for calculations //$(tooltip).setStyle('white-space: nowrap'); var layout = $(element).getLayout(); var position = $(element).cumulativeOffset(); var dims = $( id + '_tooltip' ).getDimensions(); var docDim = $( document.body ).getLayout(); // Detect best position for tooltip if( options.position == 'auto' ){ if( position.left + (layout.get('padding-box-width')/2) - (dims.width/2) < 0 ){ options.position = 'right'; } else if( position.left + (dims.width/2) > docDim.get('width') ){ options.position = 'left'; } else { options.position = 'top'; } } Debug.write( dims ); // And now position switch( options.position ){ case 'top': $(tooltip).setStyle( { top: (position.top - dims.height - 1) + 'px', left: (position.left + (layout.get('padding-box-width')/2) - (dims.width/2)) + 'px' } ).addClassName('top'); break; case 'bottom': $(tooltip).setStyle( { top: (position.top + layout.get('padding-box-height') + 1) + 'px', left: (position.left + (layout.get('padding-box-width')/2) - (dims.width/2)) + 'px' } ).addClassName('bottom'); break; case 'left': $(tooltip).setStyle( { top: (position.top - (layout.get('padding-box-height') / 2)) + 'px', left: (position.left - dims.width - 3) + 'px' }).addClassName('left'); break; case 'right': $(tooltip).setStyle( { top: (position.top - (layout.get('padding-box-height') / 2)) + 'px', left: (position.left + layout.get('padding-box-width') - 3) + 'px' }).addClassName('right'); break; } // Remove word wrap //$(tooltip).setStyle('white-space: normal'); if( options.animate ){ new Effect.Appear( $(tooltip), { duration: 0.3, queue: 'end' } ); } else { $(tooltip).show(); } }, hide = function(e){ var id = $(element).identify(); if( !$(id + '_tooltip') ){ return; } if( options.animate ){ new Effect.Fade( $(id + '_tooltip'), { duration: 0.2, queue: 'end' }); } else { $(id + '_tooltip').hide(); } }; $( element ).observe("mouseenter", function(e){ if( options.delay ){ options._still_going = true; show.delay( options.delay, e ); } else { show(e); } }). observe("click", function(e){ options._still_going = false; hide(); }). observe("mouseleave", function(e) { options._still_going = false; hide(); }); } }); /************************************************/ /* IPB3 Javascript */ /* -------------------------------------------- */ /* ips.global.js - Global functionality */ /* (c) IPS, Inc 2008 */ /* -------------------------------------------- */ /* Author: Rikki Tissier */ /************************************************/ var _global = window.IPBoard; _global.prototype.global = { searchTimer: [], searchLastQuery: '', rssItems: [], reputation: {}, popups: {}, ac_cache: $H(), pageJumps: $H(), pageJumpMenus: $H(), boardMarkers: $H(), searchResults: $H(), tidPopOpen: 0, activeTab: 'forums', userCards: null, inlineNotification: { timers: [] }, _supportsPlaceholder: null, /*------------------------------*/ /* Constructor */ init: function() { Debug.write("Initializing ips.global.js"); document.observe("dom:loaded", function(){ ipb.global.initEvents(); }); }, initEvents: function() { // Delegate our user popup links/warn logs ipb.delegate.register(".warn_link", ipb.global.displayWarnLogs); ipb.delegate.register(".mini_friend_toggle", ipb.global.toggleFriend); ipb.delegate.register(".__topic_preview", ipb.global.topicPreview); ipb.delegate.register('.bbc_spoiler_show', ipb.global.toggleSpoiler); ipb.delegate.register('a[rel~="external"]', ipb.global.openNewWindow ); ipb.delegate.register('._repLikeMore', ipb.global.repLikeMore); ipb.delegate.register('a[rel~="quickNavigation"]', ipb.global.openQuickNavigation ); if( $('sign_in') && !$('sign_in').hasClassName('no_ajax') ){ $('sign_in').on('click', ipb.global.inlineSignin); } if( $('rss_feed') ){ ipb.global.buildRSSmenu(); } if ( ! Object.isUndefined( ipb.vars['notificationData'] ) ) { new ipb.Popup( 'navigation_popup', { type: 'modal', initial: ipb.templates['notificationTemplate'].evaluate( ipb.vars['notificationData'] ), hideAtStart: false, w: '600px', h: 250} ); } /* This is needed for RTL - the generic anchoring isn't working on RTL for some reason */ if( $('backtotop') ){ $('backtotop').observe( "click", function(e){ Event.stop(e); window.scroll( 0, 0 ); } ); } ipb.global.buildPageJumps(); ipb.global.initUserCards(); /* Got an inline notification? */ if ( ! Object.isUndefined( ipb.templates['inlineMsg'] ) && ipb.templates['inlineMsg'] != '' ){ ipb.global.showInlineNotification( ipb.templates['inlineMsg'] ); } // Contextual search if( $('search-box') ){ ipb.global.contextualSearch(); } // Global menus if( $('user_link') ){ new ipb.Menu( $('user_link'), $('user_link_menucontent') ); } if( $('new_skin') ){ new ipb.Menu( $('new_skin'), $('new_skin_menucontent') ); } if( $('new_language') ){ new ipb.Menu( $('new_language'), $('new_language_menucontent') ); } if( $('mark_all_read') ){ new ipb.Menu( $('mark_all_read'), $('mark_all_read_menucontent') ); } // Tooltips $$("[data-tooltip]").invoke('tooltip'); // General click handlers $$("[data-clicklaunch]").invoke('clickLaunch'); // Confirm action used in delete, etc $$("[data-confirmaction]").invoke('confirmAction'); // Status updates if( $('statusUpdateGlobal') ){ $('statusUpdateGlobal').defaultize( ipb.lang['global_status_update'] ); $('statusSubmitGlobal').observe( 'click', ipb.global.statusUpdated ); } ipb.global.parseQuoteBoxes(); ipb.global.removeLinkedLightbox(); /* Attachments wrapped in URL @link http://community.invisionpower.com/tracker/issue-37113-linking-image-attachments-does-not-work/ */ $$('a.resized_img').each( function( elem ) { if ( $(elem).previous('a.bbc_url') ) { var test = $(elem).previous('a.bbc_url'); if ( ! test.innerHTML.length ) { $(elem).writeAttribute( 'href', test.href ); $(elem).writeAttribute( 'rel', test.rel ); /* Remove empty href */ test.remove(); } } } ); /* Tag show more */ if ( ! Object.isUndefined( ipb.hoverCard ) && ipb.vars['is_touch'] === false ) { var ajaxUrl = ipb.vars['base_url'] + "app=core&module=ajax§ion=tags&do=getTagsAsPopUp&md5check="+ipb.vars['secure_hash']; ipb.hoverCardRegister.initialize( 'tagsPopUp', { 'w': '500px', 'delay': 750, 'position': 'auto', 'ajaxUrl': ajaxUrl, 'getId': true, 'setIdParam': 'key' } ); } }, /* Make quote boxes all nice */ parseQuoteBoxes: function() { $$('blockquote.ipsBlockquote').each( function( el ) { if ( ! $(el).hasClassName('built') ) { var author = ''; var cid = ''; var time = 0; var date = ''; var collapsed = 0; var _extra = ''; var _a = new Element('span'); try { author = $(el).getAttribute( 'data-author' ) ? $(el).getAttribute( 'data-author' ).escapeHtml() : ''; cid = $(el).getAttribute( 'data-cid' ) ? $(el).getAttribute( 'data-cid' ).escapeHtml() : ''; time = $(el).getAttribute( 'data-time' ) ? $(el).getAttribute( 'data-time' ).escapeHtml() : 0; date = $(el).getAttribute( 'data-date' ) ? $(el).getAttribute( 'data-date' ).escapeHtml() : ''; collapsed = $(el).getAttribute( 'data-collapsed' ) ? $(el).getAttribute( 'data-collapsed' ).escapeHtml() : 0; } catch( aCold ) { } if ( time ) { if ( time == parseInt( time ) && time.length == 10 ) { /* First, determine if we are in DST now */ var _tz = new Date().getTimezoneOffset() * 60; /* Find out if timestamp was in DST */ var _date = new Date().getDateAndTime( parseInt( time ) ); /* If there isn't a match, figure out the DST offset and then add it back in */ if( _date['dst'] * 60 != _tz ) { _tz = _tz - _date['dst'] * 60; _date = new Date().getDateAndTime( parseInt( time ) - parseInt( _tz ) ); } var _ampm = ''; if( ipb.vars['hour_format'] == "12" ) { if( _date['hour'] > 12 ) { _date['hour'] -= 12; _ampm = ' ' + ipb.lang['date_pm']; } else if( _date['hour'] == 12 ) { _ampm = ' ' + ipb.lang['date_pm']; } else if( _date['hour'] == 0 ) { _date['hour'] = 12; _ampm = ' ' + ipb.lang['date_am']; } else { _ampm = ' ' + ipb.lang['date_am']; } } date = _date['date'] + ' ' + _date['monthName'] + ' ' + _date['year'] + ' - ' + _date['hour'] + ':' + _date['min'] + _ampm; } } if ( author && date ) { _extra = ipb.lang['quote__date_author'].replace( /#name#/, author ).replace( /#date#/, date ); } else if ( author ) { _extra = ipb.lang['quote__author'].replace( /#name#/, author ); } /* finally.. */ if ( _extra.length == 0 ) { _extra = ipb.lang['quote_title']; } if ( cid && parseInt( cid ) == cid ) { _a = new Element( 'a', { 'class': 'snapback right', rel: 'citation', href: ipb.vars['board_url'] + '/index.php?app=forums&module=forums§ion=findpost&pid=' + cid } ); _a.update( new Element( 'img', { src: ipb.vars['img_url'] + '/snapback.png' } ) ); } el.insert( { before: new Element( 'p', { 'class': 'citation' } ).update( _extra ).insert( _a ) } ); try { el.down('cite').hide(); } catch(err){} el.addClassName( 'built' ); if ( collapsed ) { var wrapper = new Element( 'div', {'class': '_quote-wrapper' } ).update( el.innerHTML ); el.update( wrapper ); el.down('div._quote-wrapper').hide(); el.insert( new Element( 'p', { 'class': '___x clickable' } ).update( ipb.lang['quote_expand'] ) ); el.down('p.___x').on( 'click', function( e, elem ) { elem.up('blockquote').down('div._quote-wrapper').show(); elem.hide(); } ); } } } ); }, /* Remove lightbox if wrapped in a link */ removeLinkedLightbox: function() { $$('a.bbc_url').each( function( el ) { if ( _thislightbox = $(el).down('span[rel~=lightbox]') ) { var contents = $(el).innerHTML.replace('', ''); contents = contents.replace('', ''); $(el).innerHTML = contents; } } ); }, /* Lightbox has been disabled */ lightBoxIsOff: function() { $$('span[rel*="lightbox"]').each( function( elem ) { if ( ! $(elem).down('a') ) { $(elem).down('img').on( 'click', function(e, el) { window.open(el.src); } ); } } ); }, /* Stores default values of status share checkboxes */ saveSocialShareDefaults: function( elem, e ) { var services = {}; /* Gather elements */ $$('._share_x_').each( function(elem){ services[ elem.id.replace(/share_x_/, '' ) ] = ( elem.checked ) ? 1 : 0; } ); new Ajax.Request( ipb.vars['base_url'] + "app=core§ion=sharelinks&module=ajax&do=savePostPrefs&md5check=" + ipb.vars['secure_hash'], { method: 'post', evalJSON: 'force', parameters: services, onSuccess: function(t) { if ( Object.isUndefined( t.responseJSON ) ) { alert( ipb.lang['action_failed'] ); return; } if ( ! Object.isUndefined( t.responseJSON['error'] ) ) { alert( t.responseJSON['error'] ); } else { /* Nothing to do */ } } }); }, /*!! statusUpdated */ /* Updates a status where ever you are on the page. Differs from the ipb.status version slightly */ statusUpdated: function(e) { Event.stop(e); if ( $('statusUpdateGlobal' ).value.length < 2 || $('statusUpdateGlobal').value == ipb.lang['prof_update_default'] ) { return false; } // Bug #34650: Commented this out so that board index updates // use the ajax function defined below instead of the main status function /* Main status library loaded? */ /*if ( ! Object.isUndefined( ipb.status ) ) { return ipb.status.updateSubmit( e, 'statusUpdateGlobal' ); }*/ var su_Twitter = $('su_TwitterGlobal') && $('su_TwitterGlobal').checked ? 1 : 0; var su_Facebook = $('su_FacebookGlobal') && $('su_FacebookGlobal').checked ? 1 : 0; var skin_group = ( $('statusHook') ) ? 'boards' : 'profile'; new Ajax.Request( ipb.vars['base_url'] + "app=members§ion=status&module=ajax&do=new&md5check=" + ipb.vars['secure_hash'] + "&skin_group=" + skin_group + "&return=json&smallSpace=1", { method: 'post', evalJSON: 'force', parameters: { content: $('statusUpdateGlobal' ).value.encodeParam(), su_Twitter: su_Twitter, su_Facebook: su_Facebook }, onSuccess: function(t) { if( Object.isUndefined( t.responseJSON ) ) { alert( ipb.lang['action_failed'] ); return; } if ( t.responseJSON['error'] ) { alert( t.responseJSON['error'] ); } else { try { if ( $('status_wrapper') ) { var memberId = 0; try { memberId = $('status_wrapper').readAttribute('data-member'); } catch(err){ } if ( ! memberId || ( memberId == ipb.vars['member_id'] ) ) { $('status_wrapper').innerHTML = t.responseJSON['html'] + $('status_wrapper').innerHTML; /* Showing latest only? */ if ( ipb.status.myLatest ) { if ( $('statusWrap-' + ipb.status.myLatest ) ) { $('statusWrap-' + ipb.status.myLatest ).hide(); } } } } ipb.menus.closeAll(e,true); ipb.global.showInlineNotification( ipb.lang['status_updated'] ); $('statusUpdateGlobal').value = ''; $('statusUpdateGlobal').defaultize( ipb.lang['global_status_update'] ); } catch(err) { Debug.error( 'Logging error: ' + err ); } } } }); }, /** * Changes the user's skin */ changeSkin: function(element, e) { Debug.dir( element ); var skinId = $(element).readAttribute('data-skinid'); var url = ipb.vars['base_url'] + 'app=core&module=ajax§ion=skin&do=change&skinId=' + skinId + '&secure_key=' + ipb.vars['secure_hash']; Debug.write( url ); new Ajax.Request( url, { method: 'get', onSuccess: function(t) { /* * Get an error? */ if( t.responseJSON['status'] == 'ok' ) { window.location = window.location; window.location.reload(true); } else { ipb.global.errorDialogue( ipb.lang['ajax_failure'] ); } } } ); Event.stop(e); return false; }, /** * Displays the inbox drop down in header */ getInboxList: function(element, e) { /* * Only run AJAX call once. Cache and use the cache for subsequent requests. */ if ( Object.isUndefined( ipb.global.popups['inbox'] ) ) { ipb.global.popups['inbox'] = true; ipb.menus.closeAll(e); $(element).identify(); /* Create pop-up wrapper */ $(element).addClassName('ipbmenu'); $('ipboard_body').insert( ipb.templates['header_menu'].evaluate( { id: 'user_inbox_link_menucontent' } ) ); $('user_inbox_link_menucontent').setStyle('width: 300px').update( "
    " ); var _newMenu = new ipb.Menu( $(element), $( "user_inbox_link_menucontent" ) ); _newMenu.doOpen(); var url = ipb.vars['base_url'] + 'app=members&module=ajax§ion=messenger&do=getInboxDropDown'; Debug.write( url ); new Ajax.Request( url, { method: 'post', evalJSON: 'force', hideLoader: true, parameters: { secure_key: ipb.vars['secure_hash'] }, onSuccess: function(t) { /* * Get an error? */ if( t.responseJSON['error'] ) { if ( t.responseJSON['__board_offline__'] ) { ipb.global.errorDialogue( ipb.lang['board_offline'] ); ipb.menus.closeAll(e); } } else { $('user_inbox_link_menucontent').update( t.responseJSON['html'] ); /* Clear counter */ try { $(element).down('.ipsHasNotifications').fade( { afterFinish: function() { $(element).down('.ipsHasNotifications').show().addClassName('ipsHasNotifications_blank'); } } ); } catch( acold ) { } } } } ); } Event.stop(e); return false; }, /** * Displays the notifications drop down in header */ getNotificationsList: function(element, e) { Event.stop(e); /* * Only run AJAX call once. Cache and use the cache for subsequent requests. */ if ( Object.isUndefined( ipb.global.popups['notification'] ) ) { ipb.global.popups['notification'] = true; ipb.menus.closeAll(e); $(element).identify(); /* Create pop-up wrapper */ $(element).addClassName('ipbmenu'); $('ipboard_body').insert( ipb.templates['header_menu'].evaluate( { id: 'user_notifications_link_menucontent' } ) ); $('user_notifications_link_menucontent').setStyle('width: 300px').update( "
    " ); var _newMenu = new ipb.Menu( $(element), $( "user_notifications_link_menucontent" ) ); _newMenu.doOpen(); var url = ipb.vars['base_url'] + 'app=core&module=ajax§ion=notifications&do=getlatest'; Debug.write( url ); new Ajax.Request( url, { method: 'post', evalJSON: 'force', hideLoader: true, parameters: { secure_key: ipb.vars['secure_hash'] }, onSuccess: function(t) { /* * Get an error? */ if( t.responseJSON['error'] ) { if ( t.responseJSON['__board_offline__'] ) { ipb.global.errorDialogue( ipb.lang['board_offline'] ); ipb.menus.closeAll(e); } } else { $('user_notifications_link_menucontent').update( t.responseJSON['html'] ); /* Clear counter */ try { $(element).down('.ipsHasNotifications').fade( { afterFinish: function() { $(element).down('.ipsHasNotifications').show().addClassName('ipsHasNotifications_blank'); } } ); } catch( acold ) { } } } } ); } return false; }, openQuickNavigation: function( e ) { Event.stop(e); if( ipb.global.popups['quickNav'] ){ ipb.global.popups['quickNav'].show(); } else { var url = ipb.vars['base_url'] + "app=core&module=ajax§ion=navigation&secure_key=" + ipb.vars['secure_hash'] + "&inapp=" + ipb.vars['active_app']; ipb.global.popups['quickNav'] = new ipb.Popup( 'navigation_popup', { type: 'modal', ajaxURL: url, hideAtStart: false, w: '600px', h: 460 } ); /* delegate */ ipb.delegate.register('a[rel~="ipsQuickNav"]', ipb.global.quickNavTabClick ); } return false; }, launchPhotoEditor: function( elem, e ) { Event.stop(e); if ( ! Object.isUndefined( ipb.global.popups['photoEditor'] ) ) { ipb.global.popups['photoEditor'].kill(); } var url = ipb.vars['base_url'] + "&app=members&module=ajax§ion=photo&do=show&secure_key=" + ipb.vars['secure_hash']; ipb.global.popups['photoEditor'] = new ipb.Popup( 'photo_popup', { type: 'pane', modal: true, ajaxURL: url, hideAtStart: false, evalJs: 'force', w: '750px', h: 500 } ); return false; }, quickNavTabClick: function( e, elem ) { Event.stop(e); app = elem.readAttribute( 'data-app' ); var url = ipb.vars['base_url'] + "app=core&module=ajax§ion=navigation&secure_key=" + ipb.vars['secure_hash'] + "&do=panel&inapp=" + app; new Ajax.Request( url.replace(/&/g, '&'), { method: 'get', evalJSON: 'force', hideLoader: true, onSuccess: function(t) { $('ipsNav_content').update( t.responseText ); $$('a[rel~="ipsQuickNav"]').each( function(link) { link.up('li').removeClassName('active'); var _app = link.readAttribute( 'data-app' ); if ( _app == app ) { link.up('li').addClassName('active'); } } ); } }); return false; }, ajaxPagination: function( element, url ) { new Ajax.Request( url.replace(/&/g, '&'), { method: 'get', evalJSON: 'force', hideLoader: true, onSuccess: function(t) { $(element).update( t.responseText ); } }); return false; }, inlineSignin: function( e ) { if( ipb.vars['is_touch'] ){ // Just go to normal form for touch devices return; } /* If we don't have the template bit.. */ if ( ! $('inline_login_form') ) { return; } Event.stop(e); if( ipb.global.loginRedirect ) { window.location = ipb.global.loginRedirect; return; } new ipb.Popup( 'sign_in_popup', { type: 'pane', initial: $('inline_login_form').show(), hideAtStart: false, hideClose: false, defer: false, modal: true, w: '600px' }, { afterShow: function(pop){ try { $('ips_username').focus(); } catch(err){} } }); }, forumMarkRead: function(elem, e) { Event.stop(e); var id = $(elem).readAttribute("data-fid"); if( !id ){ return; } var url = ipb.vars['base_url'] + '&app=forums&module=ajax&secure_key=' + ipb.vars['secure_hash'] + '§ion=markasread&forumid=' + id; // Send AJAX request new Ajax.Request( url, { method: 'get', evalJSON: 'force', onSuccess: function(t) { if( t.responseText == 'no_forum' || t.responseText == 'no_permission' ){ alert( ipb.lang['mark_read_forum'] ); return; } /* Remove elements */ $$('.__topic').each( function( topic ) { if ( $(topic).hasClassName('unread') ) { var tid = $(topic).readAttribute("data-tid"); if ( tid ) { ipb.global.topicRemoveUnreadElements( tid ); } } } ); } }); }, topicMarkRead: function(elem, e) { Event.stop(e); var id = $(elem).readAttribute("data-tid"); if( !id ){ return; } var row = $('trow_'+id); var url = ipb.vars['base_url'] + '&app=forums&module=ajax&secure_key=' + ipb.vars['secure_hash'] + '§ion=topics&do=markRead&tid=' + id; // Send AJAX request new Ajax.Request( url, { method: 'get', evalJSON: 'force', onSuccess: function(t) { if( t.responseText == 'no_topic' || t.responseText == 'no_permission' ){ alert( ipb.lang['mark_read_topic'] ); return; } /* Remove mark as read link */ $(elem).remove(); /* Close preview */ ipb.global.topicPreview(e, row.down('.__topic_preview') ); /* Remove elements */ ipb.global.topicRemoveUnreadElements( id ); } }); }, topicRemoveUnreadElements: function( tid ) { $('trow_' + tid).removeClassName('unread').down('.col_f_icon').select('a img').invoke('remove'); }, topicPreview: function(e, elem) { Event.stop(e); var toggle = $(elem).down(".expander"); var row = $(elem).up(".__topic"); var id = $(row).readAttribute("data-tid"); if( !id ){ return; } // Stop multiple loads if( $(row).readAttribute('loadingPreview') == 'yes' ){ return; // Just be patient! } $( row ).writeAttribute('loadingPreview', 'yes'); if( $("topic_preview_" + id) ) { if( $("topic_preview_wrap_" + id).visible() ) { new Effect.BlindUp( $("topic_preview_wrap_" + id), { duration: 0.3, afterFinish: function(){ $('topic_preview_' + id).hide(); } } ); row.removeClassName('highlighted'); $( toggle ).addClassName('closed').removeClassName('loading').removeClassName('open').writeAttribute('title', ipb.lang['open_tpreview']); } else { $('topic_preview_' + id).show(); new Effect.BlindDown( $("topic_preview_wrap_" + id), { duration: 0.3 } ); row.addClassName('highlighted'); $( toggle ).addClassName('open').removeClassName('loading').removeClassName('closed').writeAttribute('title', ipb.lang['close_tpreview']); } $(row).writeAttribute('loadingPreview', 'no'); } else { var url = ipb.vars['base_url'] + '&app=forums&module=ajax&secure_key=' + ipb.vars['secure_hash'] + '§ion=topics&do=preview&tid=' + id; if ( ipb.global.searchResults[ id ] ){ url += '&pid=' + ipb.global.searchResults[ id ]['pid'] + '&searchTerm=' + ipb.global.searchResults[ id ]['searchterm']; } $( toggle ).addClassName('loading').removeClassName('closed').removeClassName('open'); // Send AJAX request new Ajax.Request( url, { method: 'get', evalJSON: 'force', onSuccess: function(t) { if( t.responseText == 'no_topic' || t.responseText == 'no_permission' ){ alert( ipb.lang['no_permission_preview'] ); $( toggle ).addClassName('open').removeClassName('loading').removeClassName('closed').writeAttribute('title', ipb.lang['close_tpreview']); $(row).writeAttribute('loadingPreview', 'no'); return; } if( row.tagName == "TR" ) { var count = row.childElements().size(); var newrow = new Element('tr', { 'class': 'preview', 'id': 'topic_preview_' + id }); var newcell = new Element('td', { 'colspan': count } ); var wrap = new Element('div', { 'id': 'topic_preview_wrap_' + id }).hide().update( new Element('div' ) ); // Put all the bits inside each other row.insert( { after: newrow.insert( newcell.insert( wrap ) ) } ); } else { var wrap = new Element('div', { 'id': 'topic_preview_wrap_' + id }).hide().update( new Element('div') ); row.insert( { after: wrap } ); } // Insert content wrap.update( t.responseText ).relativize(); // display it new Effect.BlindDown( wrap, { duration: 0.3 } ); // Update row & elem row.addClassName('highlighted'); $( toggle ).addClassName('open').removeClassName('loading').removeClassName('closed').writeAttribute('title', ipb.lang['close_tpreview']); $(row).writeAttribute('loadingPreview', 'no'); } }); } }, // Set up the main menu activateMainMenu: function() { if( $("nav_other_apps") && $("community_app_menu") ){ /* Image is 0 width inside hidden div, so we have to compensate manually...hardcoded for our useropts image 17px + 3px margin */ /* Note that we are grabbing width of more menu tab, instead of 'margin-box-width' which accounts for margin. Cannot grab this value while the tab is hidden and we don't want to loop a second time unnecessarily to readjust after showing the menu */ var start = totalW = $("nav_other_apps").getWidth() + 20; var menuWidth = $("community_app_menu").getWidth(); /* Add up the widths of any menu items we won't be moving to the more menu */ $("community_app_menu").select("li.skip_moremenu").each( function(elem){ totalW += $(elem).measure('margin-box-width'); }); $("community_app_menu").select("li:not(#nav_other_apps,.submenu_li)").each( function(elem){ /* These tabs should not be moved to the more menu */ if( $(elem).hasClassName('skip_moremenu') ) { return; } totalW += $(elem).measure('margin-box-width'); if( totalW >= menuWidth ) { if( !$("more_apps_menucontent") ){ $$("body")[0].insert(""); } $(elem).addClassName('submenu_li').removeClassName('left'); $("more_apps_menucontentul").insert( elem ); // Move item to menu } }); // Do we have an app menu? if( $("more_apps_menucontent" ) ) { $("nav_other_apps").show(); new ipb.Menu( $('more_apps'), $('more_apps_menucontent') ); } Debug.write( menuWidth ); } }, /** * Init user cards */ initUserCards: function() { /* User cards */ if ( ! Object.isUndefined( ipb.hoverCard ) && ipb.vars['is_touch'] === false && ipb.vars['member_group']['g_mem_info'] == 1 ) { var ajaxUrl = ipb.vars['base_url'] + '&app=members&module=ajax&secure_key=' + ipb.vars['secure_hash'] + '§ion=card'; if ( ipb.topic !== undefined && ipb.topic.forum_id !== undefined ) { ajaxUrl += "&f=" + ipb.topic.forum_id; } ipb.hoverCardRegister.initialize( 'member', { 'w': '500px', 'delay': 750, 'position': 'auto', 'ajaxUrl': ajaxUrl, 'getId': true, 'setIdParam': 'mid' } ); } }, /** * Display an inline notification * */ showInlineNotification: function( content, options ) { /* Fix options */ options = ( Object.isUndefined( options ) ) ? {} : options; options.showClose = ( Object.isUndefined( options.manualClose ) ) ? false : options.showClose; options.neverClose = ( Object.isUndefined( options.neverClose ) ) ? false : options.neverClose; options.displayForSeconds = ( Object.isUndefined( options.displayForSeconds ) ) ? 5 : options.displayForSeconds; // If there's already one open, close it, // and add a callback to try again in when its done. if ( $('ipsGlobalNotification' ) ) { ipb.global.closeInlineNotification( function(){ ipb.global.showInlineNotification( content, options ); }); return; } else { if( $('ipbwrapper') ) { /* Front end */ $('ipbwrapper').insert( new Element('div', { id: 'ipsGlobalNotification' } ).update( ipb.templates['global_notify'].evaluate( { 'message': content } ) ) ); } else { /* ACP */ $('ipboard_body').insert( new Element('div', { id: 'ipsGlobalNotification' } ).update( ipb.templates['global_notify'].evaluate( { 'message': content, 'close': ipb.templates['global_notify_close'] } ) ) ); } /* Add in content */ new Effect.Appear( 'ipsGlobalNotification', { duration: 1.5 } ); if ( options.showClose ) { $('ipsGlobalNotification').insert( new Element( 'div', { id: 'ipsGlobalNotification_close' } ) ); $('ipsGlobalNotification_close').observe('click', ipb.global.closeInlineNotification ); } else if( $('ipsGlobalNotification_close') ) { $('ipsGlobalNotification_close').observe('click', ipb.global.closeInlineNotification ); } } /* Listen on any a hrefs */ $('ipsGlobalNotification').on('click', 'span a', ipb.global.closeInlineNotification); /* Close */ if ( options.neverClose !== true ) { try { clearTimeout( ipb.global.inlineNotification['timers']['close'] ); } catch(e) {} ipb.global.inlineNotification['timers']['close'] = setTimeout( ipb.global.closeInlineNotification, options.displayForSeconds * 1000 ); } }, /** * Closes a notification */ closeInlineNotification: function( callback ) { callback = callback || Prototype.emptyFunction; if ( $('ipsGlobalNotification_close') ){ $('ipsGlobalNotification_close').stopObserving('click'); } try { clearTimeout( ipb.global.inlineNotification['timers']['close'] ); } catch(e) {} new Effect.Fade( 'ipsGlobalNotification', { duration: 1.0, afterFinish: function(){ $('ipsGlobalNotification').remove(); callback(); } } ); }, /** * Show an error dialogue * @param string * @returns Nothing */ errorDialogue: function( text ) { errContent = "

    " + ipb.lang['error_occured'] + "

    " + text + "

    "; new ipb.Popup( 'generic__errorDialogue', { type: 'pane', initial: errContent, stem: true, hideAtStart: false, hideClose: false, defer: false, warning: false, w: 400 } ); }, /** * Show an OK dialogue * @param string * @returns Nothing */ okDialogue: function( text ) { okContent = "

    " + ipb.lang['success'] + "

    " + text + "

    "; new ipb.Popup( 'generic__okDialogue', { type: 'pane', initial: okContent, stem: true, hideAtStart: false, hideClose: false, defer: false, w: 400 } ); }, contextualSearch: function() { if( !$('search_options') && !$('search_options_menucontent') ){ return; } if ( ! $('main_search') ) { return; } $('main_search').defaultize( ipb.lang['search_default_value'] ); // This removes the text for IE7 $('search').select('.submit_input').find( function(elem){ $(elem).value = ''; } ); var update = function( noSelect ) { var checked = $('search_options_menucontent').select('input').find( function(elem){ return $(elem).checked; } ); if( Object.isUndefined( checked ) ){ checked = $('search_options_menucontent').select('input:first')[0]; if( !checked ){ return; } checked.checked = true; } $('search_options').show().update( $( checked ).up('label').readAttribute('title') || '' ); // Put cursor in search box if( noSelect != true ){ $('main_search').focus(); } return true; }; update(true); $('search_options_menucontent').select('input').invoke('observe', 'click', update); }, fetchTid: function( e ) { var elem = Event.element(e); elem.identify(); if( !elem.hasClassName('__topic') ) { elem = elem.up('.__topic'); } var id = elem.id; if ( !id || ! $(id) ) { return 0; } var m = $(id).className.match('__tid([0-9]+)'); var tid = m[1]; return tid; }, displayWarnLogs: function( e, elem ) { mid = elem.id.match('warn_link_([0-9a-z]+)_([0-9]+)')[2]; if( Object.isUndefined(mid) ){ return; } if( parseInt(mid) == 0 ){ return false; } Event.stop(e); var _url = ipb.vars['base_url'] + '&app=core&module=ajax&secure_key=' + ipb.vars['secure_hash'] + '§ion=warn&do=view&mid=' + mid; warnLogs = new ipb.Popup( 'warnLogs', {type: 'pane', modal: false, w: '500px', h: 500, ajaxURL: _url, hideAtStart: false, close: '.cancel' } ); }, /* ------------------------------ */ /** * Toggle mini friend button * * @param {event} e The event * @param {int} id Member id */ toggleFriend: function(e, elem) { Event.stop(e); // Get ID of friend var id = $( elem ).id.match('friend_(.*)_([0-9]+)'); if( Object.isUndefined( id[2] ) ){ return; } var isFriend = ( $(elem).hasClassName('is_friend') ) ? 1 : 0; var urlBit = ( isFriend ) ? 'remove' : 'add'; var url = ipb.vars['base_url'] + "app=members§ion=friends&module=ajax&do=" + urlBit + "&member_id=" + id[2] + "&md5check=" + ipb.vars['secure_hash']; // Send new Ajax.Request( url, { method: 'get', onSuccess: function(t) { switch( t.responseText ) { case 'pp_friend_timeflood': alert( ipb.lang['cannot_readd_friend'] ); Event.stop(e); break; case "pp_friend_already": alert( ipb.lang['friend_already'] ); Event.stop(e); break; case "error": return true; break; default: var newIcon = ( isFriend ) ? ipb.templates['m_add_friend'].evaluate({ id: id[2]}) : ipb.templates['m_rem_friend'].evaluate({ id: id[2] }); // Find all friend links for this user var friends = $$('.mini_friend_toggle').each( function( fr ){ if( $(fr).id.endsWith('_' + id[2] ) ) { if ( isFriend ) { $(fr).removeClassName('is_friend').addClassName('is_not_friend').update( newIcon ); } else { $(fr).removeClassName('is_not_friend').addClassName('is_friend').update( newIcon ); } } }); new Effect.Highlight( $( elem ), { startcolor: ipb.vars['highlight_color'] } ); // Fire an event so we can update if necessary document.fire('ipb:friendRemoved', { friendID: id[2] } ); Event.stop(e); break; } } } ); }, /** * MATT * Toggle spammer */ toggleFlagSpammer: function( memberId, flagStatus ) { if ( flagStatus == true ) { if( confirm( ipb.lang['set_as_spammer'] ) ) { var tid = 0; var fid = 0; var sid = 0; if( typeof(ipb.topic) != 'undefined' ) { tid = ipb.topic.topic_id; fid = ipb.topic.forum_id; sid = ipb.topic.start_id; } window.location = ipb.vars['base_url'] + 'app=core&module=modcp&do=setAsSpammer&member_id=' + memberId + '&t=' + tid + '&f=' + fid + '&st=' + sid + '&auth_key=' + ipb.vars['secure_hash']; return false; } else { return false; } } else { alert( ipb.lang['is_spammer'] ); return false; } }, /* ------------------------------ */ /** * Toggle spoiler * * @param {event} e The event */ toggleSpoiler: function(e, button) { Event.stop(e); var returnvalue = $(button).up('.bbc_spoiler').down('.bbc_spoiler_wrapper').down('.bbc_spoiler_content').toggle(); if( returnvalue.visible() ){ $(button).value = ipb.lang['spoiler_hide']; } else { $(button).value = ipb.lang['spoiler_show']; } }, /* ------------------------------ */ /** * Builds the popup menu for RSS feeds */ buildRSSmenu: function() { // Get all link tags $$('link').each( function(link) { if( link.readAttribute('type') == "application/rss+xml" ) { ipb.global.rssItems.push( ipb.templates['rss_item'].evaluate( { url: link.readAttribute('href'), title: link.readAttribute('title').escapeHtml() } ) ); } }); if( ipb.global.rssItems.length > 0 ) { rssmenu = ipb.templates['rss_shell'].evaluate( { items: ipb.global.rssItems.join("\n") } ); $( 'rss_feed' ).insert( { after: rssmenu } ); new ipb.Menu( $( 'rss_feed' ), $( 'rss_menu' ) ); } else { $('rss_feed').hide(); } }, /* ------------------------------ */ /** * Reputation Popup Balloon */ repPopUp: function( e, repId, repApp, repType ) { if( ipb.global.popups['rep_' + repId] ){ ipb.global.popups['rep_' + repId].kill(); } var _url = ipb.vars['base_url'] + '&app=core&module=ajax&secure_key=' + ipb.vars['secure_hash'] + '§ion=reputation&do=view&repApp=' + repApp + '&repType=' + repType + '&repId=' + repId; ipb.global.popups['rep_' + repId] = new ipb.Popup('rep_' + repId, { type: 'balloon', stem: true, attach: { target: e, position: 'auto' }, hideAtStart: false, ajaxURL: _url, w: '300px', h: 400 }); }, /* ------------------------------ */ /** * Hides the PM notification box * * @param {event} e The event */ closePMpopup: function(e) { if( $('pm_notification') ) { new Effect.Parallel([ new Effect.Fade( $('pm_notification') ), new Effect.BlindUp( $('pm_notification') ) ], { duration: 0.5 } ); } Event.stop(e); }, /* ------------------------------ */ /** * Mark a PM read from popup * * @param {event} e The event */ markReadPMpopup: function(e) { if( $('pm_notification') ) { var elem = Event.findElement(e, 'a'); var href = elem.href.replace( /&/g, '&' ) + '&ajax=1'; //Debug.write( 'Mark as read: ' + href ); new Ajax.Request( href + "&md5check=" + ipb.vars['secure_hash'], { method: 'get', evalJSON: 'force', onSuccess: function(t){} }); new Effect.Parallel([ new Effect.Fade( $('pm_notification') ), new Effect.BlindUp( $('pm_notification') ) ], { duration: 0.5 } ); } Event.stop(e); return false; }, /* ------------------------------ */ /** * Initializes GD image * */ initGD: function() { $('gd-antispam').observe('click', ipb.global.generateNewImage); if( $('gd-image-link') ) { $('gd-image-link').observe('click', ipb.global.generateNewImage ); } }, /* ------------------------------ */ /** * Simulate clicking the image * * @param {element} elem The GD image element */ generateImageExternally: function( elem ) { if( !$(elem) ){ return; } $(elem).observe('click', ipb.global.generateNewImage); }, /* ------------------------------ */ /** * Click event for generating new GD image * * @param {event} e The event */ generateNewImage: function(e) { img = $('gd-antispam'); Event.stop(e); oldSrc = img.src.toQueryParams(); oldSrc = $H( oldSrc ).toObject(); if( !oldSrc['captcha_unique_id'] ){ Debug.error("No captcha ID found"); } // Get new image new Ajax.Request( ipb.vars['base_url'] + "app=core&module=global§ion=captcha&do=refresh&captcha_unique_id=" + oldSrc['captcha_unique_id'] + '&secure_key=' + ipb.vars['secure_hash'], { method: 'get', onSuccess: function(t) { //Change src oldSrc['captcha_unique_id'] = t.responseText; img.writeAttribute( { src: ipb.vars['base_url'] + $H( oldSrc ).toQueryString() } ); $('regid').value = t.responseText; } } ); }, /* ------------------------------ */ /** * Registers a reputation toggle on the page * * @param {int} id The element that wraps rep * @param {string} url The URL to ping * @param {int} rating The current rep rating */ registerReputation: function( id, url, rating ) { if( !$( id ) ){ return; } // Find rep up var rep_up = $( id ).down('.rep_up'); var rep_down = $( id ).down('.rep_down'); var domLikeStripId = ( $(url.domLikeStripId) ) ? $(url.domLikeStripId) : false; var sendUrl = ipb.vars['base_url'] + '&app=core&module=ajax§ion=reputation&do=add_rating&app_rate=' + url.app + '&type=' + url.type + '&type_id=' + url.typeid + '&secure_key=' + ipb.vars['secure_hash']; if( $( rep_up ) ){ $( rep_up ).observe( 'click', ipb.global.repRate.bindAsEventListener(this, 1, id) ); } if( $( rep_down ) ){ $( rep_down ).observe( 'click', ipb.global.repRate.bindAsEventListener(this, -1, id) ); } ipb.global.reputation[ id ] = { obj: $( id ), domLikeStripId: domLikeStripId, url: url, sendUrl: sendUrl, currentRating: rating || 0 }; Debug.write( "Registered reputation" ); }, /* ------------------------------ */ /** * Does a reputation rating action * * @param {event} e The event */ repRate: function( e ) { Event.stop(e); var type = $A(arguments)[1]; var id = $A(arguments)[2]; var value = ( type == 1 ) ? 1 : -1; if( !ipb.global.reputation[ id ] ){ return; } else { var rep = ipb.global.reputation[ id ]; } Debug.write( rep.sendUrl + '&rating=' + value ); // Send ping new Ajax.Request( rep.sendUrl + '&rating=' + value, { method: 'get', onSuccess: function( t ) { if( t.responseJSON['status'] == 'ok' ) { try { // It worked! Hide the rep buttons rep.obj.down('.rep_up').up('li').hide(); rep.obj.down('.rep_down').up('li').hide(); /* Can we see some, though? */ if ( t.responseJSON['canRepUp'] === true ) { rep.obj.down('.rep_up').up('li').show(); } if ( t.responseJSON['canRepDown'] === true ) { rep.obj.down('.rep_down').up('li').show(); } } catch(err) { Debug.error( err ); } // Update the figure var rep_display = rep.obj.down('.rep_show'); if( rep_display ) { ['positive', 'negative', 'zero'].each(function(c){ rep_display.removeClassName(c); }); var newValue = parseInt( t.responseJSON['rating'] ); if( newValue > 0 ) { rep_display.addClassName('positive'); } else if( newValue < 0 ) { rep_display.addClassName('negative'); } else { rep_display.addClassName('zero'); } rep_display.update( newValue ); } /* Got a like strip */ if ( $(rep.domLikeStripId.id) ) { if ( t.responseJSON['likeData'].formatted !== false ) { $(rep.domLikeStripId.id).update( t.responseJSON['likeData'].formatted ).show(); } else { $(rep.domLikeStripId.id).update( '' ).hide(); } } } else { if( t.responseJSON['error'] == 'nopermission' || t.responseJSON['error'] == 'no_permission' ) { ipb.global.errorDialogue( ipb.lang['no_permission'] ); } else { ipb.global.errorDialogue( t.responseJSON['error'] ); } } } }); }, /** * Fetch 'more'pop-up */ repLikeMore: function(e, elem) { Event.stop(e); try { var id = elem.readAttribute('data-id'); var app = elem.readAttribute('data-app'); var type = elem.readAttribute('data-type'); } catch( e ) { Debug.error(e); } if ( ! Object.isUndefined( ipb.global.popups['likeMore'] ) ) { ipb.global.popups['likeMore'].kill(); } var popid = 'setfave_' + id; var _url = ipb.vars['base_url'] + '&app=core&module=ajax§ion=reputation&do=more&secure_key=' + ipb.vars['secure_hash'] + '&f_app=' + app + '&f_type=' + type + '&f_id=' + id; Debug.write( _url ); /* easy one this... */ ipb.global.popups['likeMore'] = new ipb.Popup( popid, { type: 'pane', ajaxURL: _url, stem: false, hideAtStart: false, h: 500, w: '450px' }); }, /* ------------------------------ */ /** * Utility function for converting bytes * * @param {int} size The value in bytes to convert * @return {string} The converted string, with unit */ convertSize: function(size) { var kb = 1024; var mb = 1024 * 1024; var gb = 1024 * 1024 * 1024; if( size < kb ){ return size + " B"; } if( size < mb ){ return ( size / kb ).toFixed( 2 ) + " KB"; } if( size < gb ){ return ( size / mb ).toFixed( 2 ) + " MB"; } return ( size / gb ).toFixed( 2 ) + " GB"; }, /* ------------------------------ */ /** * Registers a page jump toggle * * @param {int} source ID of this jump * @param {hash} options Options for this jump */ registerPageJump: function( source, options ) { if( !source || !options ){ return; } ipb.global.pageJumps[ source ] = options; }, /* ------------------------------ */ /** * Builds a page jump control */ buildPageJumps: function() { $$('.pagejump').each( function(elem){ // Find the pj ID var classes = $( elem ).className.match(/pj([0-9]+)/); if( Object.isUndefined( classes ) || !classes || !classes[1] ){ return; } $( elem ).identify(); // Doth a popup exist? //Debug.write( "This wrapper has been created! " + classes[1] ); var temp = ipb.templates['page_jump'].evaluate( { id: 'pj_' + $(elem).identify() } ); $$('body')[0].insert( temp ); $('pj_' + $(elem).identify() + '_submit').observe('click', ipb.global.pageJump.bindAsEventListener( this, $(elem).identify() ) ); // So it submits on enter $('pj_' + $(elem).identify() + '_input').observe('keypress', function(e){ if( e.which == Event.KEY_RETURN ) { ipb.global.pageJump( e, $(elem).identify() ); } }); var wrap = $( 'pj_' + $(elem).identify() + '_wrap' ).addClassName('pj' + classes[1]).writeAttribute('jumpid', classes[1] ); var callback = { afterOpen: function( popup ){ try { $( 'pj_' + $(elem).identify() + '_input').activate(); } catch(err){ } } }; ipb.global.pageJumpMenus[ classes[1] ] = new ipb.Menu( $( elem ), $( wrap ), { stopClose: true }, callback ); }); }, /* ------------------------------ */ /** * Executes a page jump * * @param {event} e The event * @param {element} elem The page jump element */ pageJump: function( e, elem ) { if( !$( elem ) || !$( 'pj_' + $(elem).id + '_input' ) ){ return; } var value = $F( 'pj_' + $(elem).id + '_input' ); var jumpid = $( 'pj_' + $(elem).id + '_wrap' ).readAttribute( 'jumpid' ); if( value.blank() ){ try { ipb.global.pageJumpMenus[ source ].doClose(); } catch(err) { } } else { value = parseInt( value ); } // Work out page number var options = ipb.global.pageJumps[ jumpid ]; if( !options ){ Debug.dir( ipb.global.pageJumps ); Debug.write( jumpid ); return; } var pageNum = ( ( value - 1 ) * options.perPage ); Debug.write( pageNum ); if( pageNum < 1 ){ pageNum = 0; } /*else if( pageNum > options.totalPages ){ pageNum = options.totalPages; }*/ /* Probably much easier to let the PHP redirect figure it out * now we have the new page-2 options. Not an SEO issue as crawlers won't input * data and not a resouces issue as drop down is hardly a hot spot for traffic */ var separator = options.url.indexOf( '&' ) !== -1 ? '&' : '?' ; var url = options.url + separator + options.stKey + '=' + pageNum; if( options.anchor ) { url = url + options.anchor; } url = url.replace(/&/g, '&'); // Without a negative lookbehind, http:// gets replaced with http:/ when we replace // with / // @see http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript url = url.replace(/(http:|https:)?\/\//g, function($0, $1) { return $1 ? $0 : '/'; } ); document.location = url; return; }, /* ------------------------------ */ /** * Open the link in a new window * * @param {event} e The event * @param {boolean} force Force new window regardless of host? */ openNewWindow: function(e, link, force) { var ourHost = document.location.host; var newHost = link.host; if( Prototype.Browser.IE ) { newHost = newHost.replace( /^(.+?):(\d+)$/, '$1' ); } /** * Open a new window, if link is to a different host */ if( ourHost != newHost || force ) { window.open(link.href); Event.stop(e); return false; } else { return true; } }, /* ------------------------------ */ /** * Registers an ajax marker * * @param {string} id ID of the wrapper element * @param {string} key Key of the current marker status (e.g. f_unread) * @param {string} url URL to ping */ registerMarker: function( id, key, url ) { if( !$(id) || key.blank() || url.blank() ){ return; } Debug.write( "Marker INIT: " + id ); $( id ).observe('click', ipb.global.sendMarker.bindAsEventListener( this, id, key, url ) ); }, /* ------------------------------ */ /** * Sends a marker read request * * @param {event} e The event * @param {string} id ID of containing element * @param {string} key Key of current marker * @param {string} url URL to ping */ sendMarker: function( e, id, key, url ) { Event.stop(e); new Ajax.Request( url + "&secure_key=" + ipb.vars['secure_hash'], { method: 'get', evalJSON: 'force', onSuccess: function(t) { if( Object.isUndefined( t.responseJSON ) ) { Debug.error("Invalid server response"); return false; } if( t.responseJSON['error'] ) { Debug.error( t.responseJSON['error'] ); return false; } if ( $(id + '_tooltip') ){ $(id + '_tooltip').hide(); } $( id ).up('tr').removeClassName('unread'); // Update icon $( id ).replace( unreadIcon ); // Update subforum icons var _intId = id.replace( /forum_img_/, '' ); if( $("subforums_" + _intId ) ) { $$("#subforums_" + _intId + " li" ).each( function(elem) { $(elem).removeClassName('unread'); }); } } }); }, registerCheckAll: function( id, classname ) { if( !$( id ) ){ return; } $( id ).observe('click', ipb.global.checkAll.bindAsEventListener( this, classname ) ); $$('.' + classname ).each( function(elem){ $( elem ).observe('click', ipb.global.checkOne.bindAsEventListener( this, id ) ); }); }, checkAll: function( e, classname ) { Debug.write('checkAll'); var elem = Event.element(e); // Get all checkboxes var checkboxes = $$('.' + classname); if( elem.checked ){ checkboxes.each( function(check){ check.checked = true; }); } else { checkboxes.each( function(check){ check.checked = false; }); } }, checkOne: function(e, id) { var elem = Event.element(e); if( $( id ).checked && elem.checked == false ) { $( id ).checked = false; } }, updateReportStatus: function(e, reportID, noauto, noimg ) { Event.stop(e); var url = ipb.vars['base_url'] + "app=core&module=ajax&section=reports&do=change_status&secure_key=" + ipb.vars['secure_hash'] + "&status=3&id=" + parseInt( reportID ) + "&noimg=" + parseInt( noimg ) + "&noauto=" + parseInt( noauto ); // Do request, see what we get new Ajax.Request( url.replace(/&/g, '&'), { method: 'post', evalJSON: 'force', onSuccess: function( t ) { if( Object.isUndefined( t.responseJSON ) ) { alert( ipb.lang['action_failed'] ); return; } try { $('rstat-' + reportID).update( t.responseJSON['img'] ); ipb.menus.closeAll( e ); } catch(err) { Debug.error( err ); } } }); }, getTotalOffset: function(elem, top, left) { if( $( elem ).getOffsetParent() != document.body ) { Debug.write( "Checking " + $(elem).id ); var extra = $(elem).positionedOffset(); top += extra['top']; left += extra['left']; return ipb.global.getTotalOffset( $( elem ).getOffsetParent(), top, left ); } else { Debug.write("OK Finished!"); return { top: top, left: left }; } }, // Checks a server response from an ajax request for 'nopermission' checkPermission: function( text ) { if( text == "nopermission" || text == 'no_permission' ) { alert( ipb.lang['no_permission'] ); return false; } return true; }, /** * Check for entry keypress */ checkForEnter: function(e, callback) { if( ![ Event.KEY_RETURN ].include( e.keyCode ) ){ return; // Not interested in anything else } if ( callback ) { switch( e.keyCode ) { case Event.KEY_RETURN: callback(e); break; } Event.stop(e); } }, /** * Check for DST */ checkDST: function() { var memberHasDst = ipb.vars['dst_in_use']; var dstInEffect = new Date().getDST(); if( memberHasDst - dstInEffect != 0 ) { var url = ipb.vars['base_url'] + 'app=members&module=ajax§ion=dst&md5check='+ipb.vars['secure_hash']; new Ajax.Request( url, { method: 'get', onSuccess: function(t) { // We don't need to do anything about this.. return true; } } ); } } }; /************************************************/ /* IPB3 Javascript */ /* -------------------------------------------- */ /* ips.menu.js - Me n you class <3 */ /* (c) IPS, Inc 2008 */ /* -------------------------------------------- */ /* Author: Rikki Tissier */ /************************************************/ /* ipb.menus is a menu manager; ipb.Menu is a menu object */ var _menu = window.IPBoard; _menu.prototype.menus = { registered: $H(), closeCallBack: false, init: function() { Debug.write("Initializing ips.menu.js"); document.observe("dom:loaded", function(){ ipb.menus.initEvents(); }); }, initEvents: function() { // Set document event Event.observe( document, 'click', ipb.menus.docCloseAll ); // Auto-find menus $$('.ipbmenu').each( function(menu){ id = menu.identify(); if( $( id + "_menucontent" ) ) { new ipb.Menu( menu, $( id + "_menucontent" ) ); } }); }, register: function( source, obj ) { ipb.menus.registered.set( source, obj ); }, registerCloseCallBack: function( callBack ) { ipb.menus.closeCallBack = callBack; }, docCloseAll: function( e ) { ipb.menus.closeAll( e ); }, /*!! Close all menus (forceClose ignores clicked in menu area check) */ closeAll: function( except, forceClose ) { ipb.menus.registered.each( function(menu, force){ if( typeof( except ) == 'undefined' || ( except && menu.key != except ) ) { try{ if( forceClose || ( !(except.target && $(except.target).descendantOf( menu.value.target )) && except != menu.key ) ){ menu.value.doClose(); } } catch(err) { // Assume this menu gone byebye } } }); /* Could make this an array and chain events */ if ( Object.isFunction( ipb.menus.closeCallBack ) ) { ipb.menus.closeCallBack(); } } }; _menu.prototype.Menu = Class.create({ initialize: function( source, target, options, callbacks ){ if( !$( source ) || !$( target ) ){ return; } if( !$( source ).id ){ $( source ).identify(); } this.id = $( source ).id + '_menu'; this.source = $( source ); this.target = $( target ); this.callbacks = callbacks || {}; this.options = Object.extend( { eventType: 'click', closeOnMouseout: false, stopClose: true, offsetX: 0, offsetY: 0 }, arguments[2] || {}); // Set up events $( source ).observe( 'click', this.eventClick.bindAsEventListener( this ) ); $( source ).observe( 'mouseover', this.eventOver.bindAsEventListener( this ) ); $( target ).observe( 'click', this.targetClick.bindAsEventListener( this ) ); /* Close on mouse out too? */ if( this.options['closeOnMouseout'] !== false ) { $( this.options['closeOnMouseout'] ).observe( 'mouseleave', this.mouseOutClose.bindAsEventListener( this ) ); } /* Have an alt? */ if ( $( $( source ).id + '_alt' ) ) { $( $( source ).id + '_alt' ).observe( 'click', this.eventClick.bindAsEventListener( this, $( $( source ).id + '_alt' ) ) ); $( $( source ).id + '_alt' ).observe( 'mouseover', this.eventOver.bindAsEventListener( this ) ); } // Set up target $( this.target ).setStyle( 'position: absolute;' ).hide().setStyle( { zIndex: 9999 } ); $( this.target ).descendants().each( function( elem ){ $( elem ).setStyle( { zIndex: 10000 } ); }); ipb.menus.register( $( source ).id, this ); if( Object.isFunction( this.callbacks['afterInit'] ) ) { this.callbacks['afterInit']( this ); } }, doOpen: function(elem) { Debug.write("Menu open"); var pos = {}; var _source = ( this.options.positionSource ) ? this.options.positionSource : this.source; if ( ! Object.isUndefined( elem ) ) { var _source = elem; } // This is the positioned offset of the source element var sourcePos = $( _source ).positionedOffset(); // Cumulative offset (actual position on the page, e.g. if you scrolled down it could be higher than max resolution height) var _sourcePos = $( _source ).cumulativeOffset(); // Cumulative offset of your scrolling (how much you have scrolled) var _offset = $( _source ).cumulativeScrollOffset(); // Real source position: Actual position on page, minus scroll offset (provides position on page within viewport) var realSourcePos = { top: _sourcePos.top - _offset.top, left: _sourcePos.left - _offset.left }; // Dimensions of source object var sourceDim = $( _source ).getDimensions(); // Viewport dimensions (e.g. 1280x1024) var screenDim = document.viewport.getDimensions(); // Target dimensions var menuDim = { width: $( this.target ).measure('border-box-width'), height: $(this.target).measure('border-box-height') }; var isFixed = $( _source ).ancestors().find( function(el){ return el.getStyle('position') == 'fixed'; } ); /* RTL bug fixes */ if( isRTL ) { if( sourcePos.top < 0 ) { sourcePos.top = realSourcePos.top; } // Really really hacky RTL bug fix... :( if( $(_source).id == 'user_link' ) { //alert(sourcePos.left); sourcePos.left = sourcePos.left - ( parseInt($(_source).getStyle('padding-left').replace( /px/, '' )) + parseInt($(_source).getStyle('margin-left').replace( /px/, '' )) ); //alert(sourcePos.left); } } // Some logging Debug.write( "realSourcePos: " + realSourcePos.top + " x " + realSourcePos.left ); Debug.write( "sourcePos: " + sourcePos.top + " x " + sourcePos.left ); Debug.write( "scrollOffset: " + _offset.top + " x " + _offset.left ); Debug.write( "_sourcePos: " + _sourcePos.top + " x " + _sourcePos.left ); Debug.write( "sourceDim: " + sourceDim.width + " x " + sourceDim.height); Debug.write( "menuDim: " + menuDim.height ); Debug.write( "screenDim: " + screenDim.height ); Debug.write( "manual ofset: " + this.options.offsetX + " x " + this.options.offsetY ); // Ok, if it's a relative parent, do one thing, else be normal // Getting fed up of this feature and IE bugs _a = _source.getOffsetParent(); _b = this.target.getOffsetParent(); Debug.write("_a is " + _a ); Debug.write("_b is " + _b ); if( isFixed ) { $( this.target ).setStyle('position: fixed'); if( ( _sourcePos.left + menuDim.width ) > screenDim.width ){ diff = menuDim.width - sourceDim.width; pos.left = _sourcePos.left - diff + this.options.offsetX; } else { pos.left = (_sourcePos.left) + this.options.offsetX; } if( ( _sourcePos.top + menuDim.height ) > screenDim.height ){ pos.top = _sourcePos.top - menuDim.height + this.options.offsetY; } else { pos.top = _sourcePos.top + sourceDim.height + this.options.offsetY; } $( this.target ).setStyle( 'top: ' + (pos.top-1) + 'px; left: ' + pos.left + 'px;' ); } else { if( _a != _b ) { // Left if( ( realSourcePos.left + menuDim.width ) > screenDim.width ){ diff = menuDim.width - sourceDim.width; pos.left = _sourcePos.left - diff + this.options.offsetX; } else { if( Prototype.Browser.IE7 ){ pos.left = (_sourcePos.left) + this.options.offsetX; } else { pos.left = (_sourcePos.left) + this.options.offsetX; } } // Top /* If there's no space to open downwards, open upwards *unless* /* it would go off the top of the screen (i.e. < 0px ) Bug #18270 */ if( ( ( ( realSourcePos.top + sourceDim.height ) + menuDim.height ) > screenDim.height ) && ( _sourcePos.top - menuDim.height + this.options.offsetY ) > 0 ) { pos.top = _sourcePos.top - menuDim.height + this.options.offsetY; } else { pos.top = _sourcePos.top + sourceDim.height + this.options.offsetY; } } else { Debug.write("MENU: source offset EQUALS target offset"); // Left if( ( realSourcePos.left + menuDim.width ) > screenDim.width ){ diff = menuDim.width - sourceDim.width; pos.left = sourcePos.left - diff + this.options.offsetX; } else { pos.left = sourcePos.left + this.options.offsetX; } // Top /* If there's no space to open downwards, open upwards *unless* /* it would go off the top of the screen (i.e. < 0px ) Bug #18270 */ if( ( ( ( realSourcePos.top + sourceDim.height ) + menuDim.height ) > screenDim.height ) && ( _sourcePos.top - menuDim.height + this.options.offsetY ) > 0 ) { pos.top = sourcePos.top - menuDim.height + this.options.offsetY; } else { pos.top = sourcePos.top + sourceDim.height + this.options.offsetY; } } $( this.target ).setStyle( 'top: ' + (pos.top-1) + 'px; left: ' + pos.left + 'px;' ); } $( this.source ).addClassName('menu_active'); // Set active class on the source // Now set pos Debug.write("Menu position: " + pos.top + " x " + pos.left ); // If we have any fixed ancestors, then fix the menu too /*if( isFixed ){ $( this.target ).setStyle('position: fixed'); }*/ // And show new Effect.Appear( $( this.target ), { duration: 0.2, afterFinish: function(e){ if( Object.isFunction( this.callbacks['afterOpen'] ) ) { this.callbacks['afterOpen']( this ); } }.bind(this) } ); // Set key event so we can close on ESC Event.observe( document, 'keypress', this.checkKeyPress.bindAsEventListener( this ) ); }, checkKeyPress: function( e ) { //Debug.write( e ); if( e.keyCode == Event.KEY_ESC ) { this.doClose(); } }, mouseOutClose: function() { this.doClose(); }, doClose: function() { new Effect.Fade( $( this.target ), { duration: 0.3, afterFinish: function(e){ if( Object.isFunction( this.callbacks['afterClose'] ) ) { this.callbacks['afterClose']( this ); } }.bind( this ) } ); //Debug.write( "Closing " + $( this.source ).id ); this.source.removeClassName('menu_active'); }, targetClick: function(e) { if( !this.options.stopClose ){ this.doClose(); } /*try { var elem = Event.findElement(e); if ( elem.hasClassName('_noCloseMenuUponClick') ) { Event.stop(e); } } catch(e) { } if( ( this.options.stopClose && !$(elem).match("input") || $(elem).match("input") ) ){ //if( $(e.target).match("[type=checkbox]")){ // Debug.write( $(e.target).checked ); // $(e.target).checked = true; //} Event.stop(e); }*/ }, eventClick: function(e, elem) { if( this.options['eventType'] == 'click' ) { Event.stop(e); if( $( this.target ).visible() ){ if( Object.isFunction( this.callbacks['beforeClose'] ) ) { this.callbacks['beforeClose']( this ); } this.doClose(); } else { ipb.menus.closeAll( $(this.source).id ); if( Object.isFunction( this.callbacks['beforeOpen'] ) ) { this.callbacks['beforeOpen']( this ); } this.doOpen(elem); } } }, eventOver: function() { if( this.options['eventType'] == 'mouseover' ) { if( !$( this.target ).visible() ){ ipb.menus.closeAll( $(this.source).id ); if( Object.isFunction( this.callbacks['beforeOpen'] ) ) { this.callbacks['beforeOpen']( this ); } this.doOpen(); } } } }); /************************************************/ /* IPB3 Javascript */ /* -------------------------------------------- */ /* ips.popup.js - Popup creator */ /* (c) IPS, Inc 2008 */ /* -------------------------------------------- */ /* Author: Rikki Tissier */ /************************************************/ /** * Full list of options: * * type: balloon, pane * modal: true/false * w: width * h: height * classname: classname to be applied to wrapper * initial: initial content * ajaxURL: If supplied, will ping URL for content and update popup * close: element that will close popup (wont work with balloon) * attach: { target, event, mouse, offset } * hideAtStart: Hide after creation (allows showing at a later time) * stem: true/false * delay: { show, hide } */ _popup = window.IPBoard; _popup.prototype.Popup = Class.create({ initialize: function( id, options, callbacks ) { /* Set up properties */ this.id = ''; this.wrapper = null; this.inner = null; this.stem = null; this.options = {}; this.timer = []; this.ready = false; this.visible = false; this._startup = null; this.hideAfterSetup = false; this.eventPairs = { 'mouseover': 'mouseout', 'mousedown': 'mouseup' }; this._tmpEvent = null; /* Now run */ this.id = id; this.options = Object.extend({ type: 'pane', w: '500px', modal: false, modalOpacity: 0.4, hideAtStart: true, delay: { show: 0, hide: 0 }, defer: false, hideClose: false, black: false, warning: false, evalJs: true, closeContents: ipb.templates['close_popup'] }, arguments[1] || {}); this.callbacks = callbacks || {}; // Are we deferring the load? if( this.options.defer && $( this.options.attach.target ) ) { this._defer = this.init.bindAsEventListener( this ); $( this.options.attach.target ).observe( this.options.attach.event, this._defer ); if( this.eventPairs[ this.options.attach.event ] ) { this._startup = function(e){ this.hideAfterSetup = true; this.hide(); }.bindAsEventListener( this ); $( this.options.attach.target ).observe( this.eventPairs[ this.options.attach.event ], this._startup ); } } else { this.init(); } }, init: function() { try { Event.stopObserving( $( this.options.attach.target ), this.options.attach.event, this._defer ); if ( $(this.options.attach.target) ) { var toff = $( this.options.attach.target ).positionedOffset(); var menu = $(this.options.attach.target).up('.ipbmenu_content'); if ( toff.top == 0 && toff.left == 0 || $(menu) ) { /* make it a centered box */ this.options.type = 'modal'; this.options.attach = {}; } } } catch(err) { } this.wrapper = new Element('div', { 'id': this.id + '_popup' } ).setStyle('z-index: 10001').hide().addClassName('popupWrapper'); this.inner = new Element('div', { 'id': this.id + '_inner' } ).addClassName('popupInner'); if ( this.options.black ) { this.inner.addClassName('black_mode'); } if ( this.options.warning ) { this.inner.addClassName('warning_mode'); } if( this.options.w ){ this.inner.setStyle( 'width: ' + this.options.w ); } this.wrapper.insert( this.inner ); if( this.options.hideClose != true ) { this.closeLink = new Element('div', { 'id': this.id + '_close' } ).addClassName('popupClose').addClassName('clickable'); this.closeLink.update( this.options.closeContents ); this.closeLink.observe('click', this.hide.bindAsEventListener( this ) ); this.wrapper.insert( this.closeLink ); if ( this.options.black || this.options.warning ) { this.closeLink.addClassName('light_close_button'); } } $$('body')[0].insert( this.wrapper ); if( this.options.classname ){ this.wrapper.addClassName( this.options.classname ); } if( this.options.initial ){ this.update( this.options.initial ); } // Callback if( Object.isFunction( this.callbacks['beforeAjax'] ) ) { this.callbacks['beforeAjax']( this ); } // If we are updating with ajax, handle the show there if( this.options.ajaxURL ){ this.updateAjax(); setTimeout( this.continueInit.bind(this), 80 ); } else { this.ready = true; this.continueInit(); } }, continueInit: function() { if( !this.ready ) { setTimeout( this.continueInit.bind(this), 80 ); return; } /* Ensure pop-up isn't larger than viewport */ if( this.inner.select(".fixed_inner").size() ) { Debug.write("Found fixed_inner"); this.inner.select(".fixed_inner")[0].setStyle( 'height: ' + this.options.h + 'px; max-height: ' + this.options.h + 'px; overflow: auto' ); } else { var _vph = document.viewport.getDimensions().height - 25; this.options.h = ( this.options.h && _vph > this.options.h ) ? this.options.h : _vph; this.inner.setStyle( 'max-height: ' + this.options.h + 'px' ); } //Debug.write("Continuing..."); // What are we making? if( this.options.type == 'balloon' ){ this.setUpBalloon(); } else { this.setUpPane(); } // Set up close event try { if( this.options.close ){ closeElem = $( this.wrapper ).select( this.options.close )[0]; if( Object.isElement( closeElem ) ) { $( closeElem ).observe( 'click', this.hide.bindAsEventListener( this ) ); } } } catch( err ) { Debug.write( err ); } // Callback if( Object.isFunction( this.callbacks['afterInit'] ) ) { this.callbacks['afterInit']( this ); } if( !this.options.hideAtStart && !this.hideAfterSetup ) { this.show(); } if( this.hideAfterSetup && this._startup ) { Event.stopObserving( $( this.options.attach.target ), this.eventPairs[ this.options.attach.event ], this._startup ); } }, updateAjax: function() { Debug.write( this.options.ajaxURL ); new Ajax.Request( this.options.ajaxURL, { method: 'get', evalJS: this.options.evalJs, onSuccess: function(t) { if ( t.responseText != 'error' ) { try { if ( ! Object.isUndefined( t.responseJSON ) && ! Object.isUndefined( t.responseJSON['error'] ) ) { if ( t.responseJSON['__board_offline__'] ) { ipb.global.errorDialogue( ipb.lang['board_offline'] ); ipb.menus.closeAll(e); } else { ipb.global.errorDialogue( t.responseJSON['error'] ); } return false; } } catch(e){} if ( t.responseText == 'nopermission' ) { ipb.global.errorDialogue( ipb.lang['no_permission'] ); return; } /* Check for log out */ if ( t.responseText.match( "__session__expired__log__out__" ) ) { this.update(''); alert( ipb.lang['session_timed_out'] ); return false; } Debug.write( "AJAX done!" ); this.update( t.responseText ); this.ready = true; // Callback if( Object.isFunction( this.callbacks['afterAjax'] ) ) { this.callbacks['afterAjax']( this, t.responseText ); } } else { Debug.write( t.responseText ); return; } }.bind(this) }); }, show: function(e) { if( e ){ Event.stop(e); } if( this.timer['show'] ){ clearTimeout( this.timer['show'] ); } if( this.options.delay.show != 0 ){ this.timer['show'] = setTimeout( this._show.bind( this ), this.options.delay.show ); } else { this._show(); // Just show it } }, hide: function(e) { if( e ){ Event.stop(e); } if( this.document_event ){ Event.stopObserving( document, 'click', this.document_event ); Event.stopObserving( document, 'touchstart', this.document_event ); } if( this.timer['hide'] ){ clearTimeout( this.timer['hide'] ); } if( this.options.delay.hide != 0 ){ this.timer['hide'] = setTimeout( this._hide.bind( this ), this.options.delay.hide ); } else { this._hide(); // Just hide it } }, /* remove wrapper and kill timeouts */ kill: function() { if( this.timer['hide'] ){ clearTimeout( this.timer['hide'] ); } if( this.timer['show'] ){ clearTimeout( this.timer['show'] ); } if( $( this.wrapper ) ) { $( this.wrapper ).remove(); } }, _show: function() { this.visible = true; /* Experimental */ try { if ( this.options.warning ) { _wrap = this.inner.down('h3').next('div'); if ( _wrap ) { if ( ! _wrap.className.match( /moderated/ ) ) { _wrap.addClassName('moderated'); } } } } catch(e){} if( this.options.modal == false ){ new Effect.Appear( $( this.wrapper ), { duration: 0.3, afterFinish: function(){ if( Object.isFunction( this.callbacks['afterShow'] ) ) { this.callbacks['afterShow']( this ); } }.bind(this) } ); this.document_event = this.handleDocumentClick.bindAsEventListener(this); this.setDocumentEvent(); } else { new Effect.Appear( $('document_modal'), { duration: 0.3, to: this.options.modalOpacity, afterFinish: function(){ new Effect.Appear( $( this.wrapper ), { duration: 0.4, afterFinish: function(){ if( Object.isFunction( this.callbacks['afterShow'] ) ) { this.callbacks['afterShow']( this ); } }.bind(this) } ); }.bind(this) }); } }, _hide: function() { this.visible = false; if( this._tmpEvent != null ) { Event.stopObserving( $( this.wrapper ), 'mouseout', this._tmpEvent ); this._tmpEvent = null; } if( this.options.modal == false ){ new Effect.Fade( $( this.wrapper ), { duration: 0.3, afterFinish: function(){ if( Object.isFunction( this.callbacks['afterHide'] ) ) { this.callbacks['afterHide']( this ); } }.bind(this) } ); } else { new Effect.Fade( $( this.wrapper ), { duration: 0.3, afterFinish: function(){ new Effect.Fade( $('document_modal'), { duration: 0.2, afterFinish: function(){ if( Object.isFunction( this.callbacks['afterHide'] ) ) { this.callbacks['afterHide']( this ); } }.bind(this) } ); }.bind(this) }); } }, setDocumentEvent: function() { if( !ipb.vars['is_touch'] ){ Event.observe( document, 'click', this.document_event ); return; } // Touch event Event.observe( document, 'touchstart', this.document_event ); }, handleDocumentClick: function(e) { Debug.write( 'document click: ' + Event.element(e).id); if( !Event.element(e).descendantOf( this.wrapper ) && ( this.options.attach && ( Event.element(e).id != this.options.attach.target.id ) ) ) { this.hide(e); } }, update: function( content, evalScript ) { if( Object.isElement( content ) ){ this.inner.insert( { bottom: content } ); } else { this.inner.update( content ); } // Should this popup eval scripts? Default is YES if( Object.isUndefined( evalScript ) || evalScript != false ){ this.inner.innerHTML.evalScripts(); } }, setUpBalloon: function() { // Are we attaching? if( this.options.attach ) { var attach = this.options.attach; if( attach.target && $( attach.target ) ) { if( this.options.stem == true ) { this.createStem(); } // Get position if( !attach.position ){ attach.position = 'auto'; } if( isRTL ) { if( Object.isUndefined( attach.offset ) ){ attach.offset = { top: 0, right: 0 }; } if( Object.isUndefined( attach.offset.top ) ){ attach.offset.top = 0; } if( Object.isUndefined( attach.offset.left ) ){ attach.offset.right = 0; }else{ attach.offset.right = attach.offset.left; } } else { if( Object.isUndefined( attach.offset ) ){ attach.offset = { top: 0, left: 0 }; } if( Object.isUndefined( attach.offset.top ) ){ attach.offset.top = 0; } if( Object.isUndefined( attach.offset.left ) ){ attach.offset.left = 0; } } if( attach.position == 'auto' ) { Debug.write("Popup: auto-positioning"); var screendims = document.viewport.getDimensions(); var screenscroll = document.viewport.getScrollOffsets(); var toff = $( attach.target ).viewportOffset(); var wrapSize = $( this.wrapper ).getDimensions(); var delta = [0,0]; if (Element.getStyle( $( attach.target ), 'position') == 'absolute') { var parent = attach.target.getOffsetParent(); delta = parent.viewportOffset(); } if( isRTL ) { toff['right'] = screendims.width - ( toff[0] - delta[0] ); } else { toff['left'] = toff[0] - delta[0]; } toff['top'] = toff[1] - delta[1] + screenscroll.top; //Debug.write( toff['left'] + " " + toff['top'] ); // Need to figure out if it will be off-screen var start = 'top'; if( isRTL ){ var end = 'right'; } else { var end = 'left'; } //Debug.write( "Target offset top: " + toff.top + ", wrapSize Height: " + wrapSize.height + ", screenscroll top: " + screenscroll.top); if( ( toff.top - wrapSize.height - attach.offset.top ) < ( 0 + screenscroll.top ) ){ var start = 'bottom'; } if( isRTL ) { if( ( toff.right + wrapSize.width - attach.offset.right ) < ( screendims.width - screenscroll.left ) ){ var end = 'left'; } } else { if( ( toff.left + wrapSize.width - attach.offset.left ) > ( screendims.width - screenscroll.left ) ){ var end = 'right'; } } finalPos = this.position( start + end, { target: $( attach.target ), content: $( this.wrapper ), offset: attach.offset } ); if( this.options.stem == true ) { finalPos = this.positionStem( start + end, finalPos ); } } else { Debug.write("Popup: manual positioning"); finalPos = this.position( attach.position, { target: $( attach.target ), content: $( this.wrapper ), offset: attach.offset } ); if( this.options.stem == true ) { finalPos = this.positionStem( attach.position, finalPos ); } } // Add mouse events if( !Object.isUndefined( attach.event ) ){ $( attach.target ).observe( attach.event, this.show.bindAsEventListener( this ) ); if( attach.event != 'click' && !Object.isUndefined( this.eventPairs[ attach.event ] ) ){ $( attach.target ).observe( this.eventPairs[ attach.event ], this.hide.bindAsEventListener( this ) ); } $( this.wrapper ).observe( 'mouseover', this.wrapperEvent.bindAsEventListener( this ) ); } } } if( isRTL ) { Debug.write("Popup: Right: " + finalPos.right + "; Top: " + finalPos.top); $( this.wrapper ).setStyle( 'top: ' + finalPos.top + 'px; right: ' + finalPos.right + 'px; position: absolute;' ); } else { Debug.write("Popup: Left: " + finalPos.left + "; Top: " + finalPos.top); $( this.wrapper ).setStyle( 'top: ' + finalPos.top + 'px; left: ' + finalPos.left + 'px; position: absolute;' ); } }, wrapperEvent: function(e) { if( this.timer['hide'] ) { // Cancel event now clearTimeout( this.timer['hide'] ); this.timer['hide'] = null; if( this.options.attach.event && this.options.attach.event == 'mouseover' ) { // Set new event to account for mouseout of the popup, // but only if we don't already have one - otherwise we get // expontentially more event calls. Bad. if( this._tmpEvent == null ){ this._tmpEvent = this.hide.bindAsEventListener( this ); $( this.wrapper ).observe('mouseout', this._tmpEvent ); } } } }, positionStem: function( pos, finalPos ) { var stemSize = { height: 16, width: 31 }; var wrapStyle = {}; var stemStyle = {}; switch( pos.toLowerCase() ) { case 'topleft': wrapStyle = { marginBottom: stemSize.height + 'px' }; if( isRTL ) { stemStyle = { bottom: -(stemSize.height) + 'px', right: '5px' }; finalPos.right = finalPos.right - 15; } else { stemStyle = { bottom: -(stemSize.height) + 'px', left: '5px' }; finalPos.left = finalPos.left - 15; } break; case 'topright': wrapStyle = { marginBottom: stemSize.height + 'px' }; if( isRTL ) { stemStyle = { bottom: -(stemSize.height) + 'px', left: '5px' }; finalPos.right = finalPos.right + 15; } else { stemStyle = { bottom: -(stemSize.height) + 'px', right: '5px' }; finalPos.left = finalPos.left + 15; } break; case 'bottomleft': wrapStyle = { marginTop: stemSize.height + 'px' }; if( isRTL ) { stemStyle = { top: -(stemSize.height) + 'px', right: '5px' }; finalPos.right = finalPos.right - 15; } else { stemStyle = { top: -(stemSize.height) + 'px', left: '5px' }; finalPos.left = finalPos.left - 15; } break; case 'bottomright': wrapStyle = { marginTop: stemSize.height + 'px' }; if( isRTL ) { stemStyle = { top: -(stemSize.height) + 'px', left: '5px' }; finalPos.right = finalPos.right + 15; } else { stemStyle = { top: -(stemSize.height) + 'px', right: '5px' }; finalPos.left = finalPos.left + 15; } break; } $( this.wrapper ).setStyle( wrapStyle ); $( this.stem ).setStyle( stemStyle ).setStyle('z-index: 6000').addClassName( pos.toLowerCase() ); return finalPos; }, position: function( pos, v ) { finalPos = {}; v.target.identify(); var toff = $( v.target.id ).viewportOffset(); var tsize = $( v.target.id ).getDimensions(); var wrapSize = $( v.content ).getDimensions(); var screenscroll = document.viewport.getScrollOffsets(); var offset = v.offset; var delta = [0,0]; if (Element.getStyle( $( v.target.id ), 'position') == 'absolute') { var parent = $( v.target.id ).getOffsetParent(); delta = parent.viewportOffset(); /* That above doesn't help */ delta = [0,0]; } if( isRTL ) { toff['right'] = document.viewport.getDimensions().width - ( toff[0] - delta[0] ); } else { toff['left'] = toff[0] - delta[0]; } toff['top'] = toff['top'] - delta[1] + screenscroll.top; switch( pos.toLowerCase() ) { case 'topleft': finalPos.top = ( toff.top - wrapSize.height - ( tsize.height / 2 ) ) - offset.top; if( isRTL ) { finalPos.right = toff.right + offset.right; } else { finalPos.left = toff.left + offset.left; } break; case 'topright': finalPos.top = ( toff.top - wrapSize.height - ( tsize.height / 2 ) ) - offset.top; if( isRTL ) { finalPos.right = ( toff.right - ( wrapSize.width - tsize.width ) ) - offset.right; } else { finalPos.left = ( toff.left - ( wrapSize.width - tsize.width ) ) - offset.left; } break; case 'bottomleft': finalPos.top = ( toff.top + tsize.height ) + offset.top; if( isRTL ) { finalPos.right = toff.right + offset.right; } else { finalPos.left = toff.left + offset.left; } break; case 'bottomright': finalPos.top = ( toff.top + tsize.height ) + offset.top; if( isRTL ) { finalPos.right = ( toff.right - ( wrapSize.width - tsize.width ) ) - offset.right; } else { finalPos.left = ( toff.left - ( wrapSize.width - tsize.width ) ) - offset.left; } break; } return finalPos; }, createStem: function() { this.stem = new Element('div', { id: this.id + '_stem' } ).update(' ').addClassName('stem'); this.wrapper.insert( { top: this.stem } ); }, setUpPane: function() { // Does the document have a modal blackout? if( !$('document_modal') ){ this.createDocumentModal(); } this.positionPane(); }, positionPane: function() { // Position it in the middle var elem_s = $( this.wrapper ).getDimensions(); var window_s = document.viewport.getDimensions(); var window_offsets = document.viewport.getScrollOffsets(); if( ipb.vars['is_touch'] ){ // #35826: On some skins, webkit will handle the document viewport sizes incorrectly. // To try and protect against this, we'll use the actual screen size for these // calculations. window_s = { width: window.innerWidth, height: window.innerHeight }; } if( isRTL ) { var center = { right: ((window_s['width'] - elem_s['width']) / 2), top: (((window_s['height'] - elem_s['height']) / 2)/2) }; if( center.top < 10 ){ center.top = 10; } $( this.wrapper ).setStyle('top: ' + center['top'] + 'px; right: ' + center['right'] + 'px; position: fixed;'); } else { var center = { left: ((window_s['width'] - elem_s['width']) / 2), top: (((window_s['height'] - elem_s['height']) / 2)/2) }; if( center.top < 10 ){ center.top = 10; } $( this.wrapper ).setStyle('top: ' + center['top'] + 'px; left: ' + center['left'] + 'px; position: fixed;'); } }, createDocumentModal: function() { var pageLayout = $( document.body ).getLayout(); var pageSize = { width: pageLayout.get('width'), height: pageLayout.get('margin-box-height') }; var viewSize = document.viewport.getDimensions(); var dims = []; Debug.dir( pageSize ); Debug.dir( viewSize ); if( viewSize['height'] < pageSize['height'] ){ dims['height'] = pageSize['height']; } else { dims['height'] = viewSize['height']; } if( viewSize['width'] < pageSize['width'] ){ dims['width'] = pageSize['width']; } else { dims['width'] = viewSize['width']; } var modal = new Element( 'div', { 'id': 'document_modal' } ).addClassName('modal').hide(); if( isRTL ){ modal.setStyle('width: ' + dims['width'] + 'px; height: ' + dims['height'] + 'px; position: fixed; top: 0px; right: 0px; z-index: 10000;'); } else { modal.setStyle('width: ' + dims['width'] + 'px; height: ' + dims['height'] + 'px; position: fixed; top: 0px; left: 0px; z-index: 10000;'); } $$('body')[0].insert( modal ); }, getObj: function() { return $( this.wrapper ); } }); /************************************************/ /* IPB3 Javascript */ /* -------------------------------------------- */ /* ips.ticker.js - Popup creator */ /* (c) IPS, Inc 2008 */ /* -------------------------------------------- */ /* Author: Rikki Tissier */ /************************************************/ _ticker = window.IPBoard; _ticker.prototype.Ticker = Class.create({ initialize: function( root, options, callbacks ) { if( !$(root) ){ return; } this.root = $(root); this.options = Object.extend({ duration: 4, select: "li" }, options || {}); this.items = $( root ).select( this.options.select ); if( !this.items.length ){ return; } // Hide all items except first this.items.invoke('hide').first().show(); // Start timer this.timer = this.nextItem.bind( this ).delay( this.options.duration ); // Pause event $( this.root ).observe('mouseenter', this.pauseTicker.bindAsEventListener( this ) ); $( this.root ).observe('mouseleave', this.unpauseTicker.bindAsEventListener( this ) ); }, pauseTicker: function(e) { clearTimeout( this.timer ); }, unpauseTicker: function(e) { this.timer = this.nextItem.bind(this).delay( this.options.duration ); }, nextItem: function() { // Find current item var cur = this.items.find( function(elem){ return elem.visible(); }); var next = $( cur ).next( this.options.select ); if( Object.isUndefined( next ) ){ next = this.items.first(); } // Fade current new Effect.Fade( $( cur ), { duration: 0.4, queue: 'end', afterFinish: function(){ new Effect.Appear( $( next ), { duration: 0.8, queue: 'end' } ); } } ); // Reset timer this.timer = this.nextItem.bind( this ).delay( this.options.duration ); } }); function warningPopup( elem, id ) { var _url = ipb.vars['base_url'] + '&app=members&module=ajax&secure_key=' + ipb.vars['secure_hash'] + '§ion=warnings&id=' + id; new ipb.Popup( 'warning' + id, { type: 'balloon', stem: true, attach: { target: elem, position: 'auto' }, hideAtStart: false, ajaxURL: _url, w: '600px', h: 800 }); } ipb = new IPBoard; ipb.global.init(); ipb.menus.init();