2022-11-25 20:57:31 +01:00
/ * *
* digital ROCK jQuery based Javascript API
*
* @ link http : //www.digitalrock.de
* @ author Ralf Becker < RalfBecker @ digitalROCK . de >
* @ copyright 2010 - 18 by RalfBecker @ digitalROCK . de
* @ version $Id : dr _api . js 1250 2015 - 06 - 18 06 : 49 : 01 Z ralfbecker $
* /
/ * *
* Widgets defined in this file :
*
* - DrWidget : universal widget , which can display all data - types and implement reload - free / in - place navigation
* - Resultlist : displays results and rankings , inherits from Startlist
* - Startlist : displays startlists and implementes automatic scrolling and rotation through multiple results
* - Results : displays top results of multiple categories and allows to change competition
* - Starters : displays registration data
* - Competitions : displays calendar , allows to change year and optional filter
* - Profile : display profile of an athlete based on a html template
* - ResultTemplate : displays result based on a html template
* - Aggregated : displays an aggregated ranking : national team ranking , GER sektionenwertung or SUI regionalzentren
* - DrBaseWidget : virtual base of all widgets implements json ( p ) loading of data
* - DrTable : creates and updates a table from data and a column definition , used by most widgets
*
* In almost all cases you only need to use DrWidget as shown in following example :
*
* < script type = "text/javascript" src = "https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" > < / s c r i p t >
* < script type = "text/javascript" src = "http://www.digitalrock.de/egroupware/ranking/js/dr_api.js" > < / s c r i p t >
* < link type = "text/css" rel = "StyleSheet" href = "http://www.digitalrock.de/egroupware/ranking/templates/default/dr_list.css" / >
*
* < div id = "container" / >
* < script >
* var widget ;
* $ ( document ) . ready ( function ( ) {
* widget = new DrWidget ( 'container' , http : //www.digitalrock.de/egroupware/ranking/json.php');
* }
* < / s c r i p t >
*
* @ link http : //www.digitalrock.de/egroupware/ranking/README describes available parameters for json url
* @ link https : //developers.google.com/webmasters/ajax-crawling/ describes supported ajax crawling scheme
* @ link http : //svn.outdoor-training.de/repos/trunk/ranking/inc/class.ranking_widget.inc.php php class implementing ajax crawling
* /
/ * *
* Example with multi - result scrolling ( use c = and r = for cat and route )
*
* http : //www.digitalrock.de/egroupware/ranking/sitemgr/digitalrock/eliste.html?comp=1251&cat=1&route=2&detail=0&rotate=c=1,r=2:c=2,r=2
*
* You can also supply an optional parameter w = ( think of German "Wettkampf" as "c" was already taken ) to rotate though different competitions ( the first of which is specified by the "comp" parameter in the original URL .
*
* Example https : //www.digitalrock.de/egroupware/ranking/sitemgr/digitalrock/eliste.html?comp=1395&beamer=1&cat=1&route=0&rotate=w=1395,c=1,r=0:w=1396,c=1,r=0
*
* The interesting part here is rotate = w = 1395 , c = 1 , r = 0 : w = 1396 , c = 1 , r = 0
* /
/ * *
* Show nation specific footer
*
* @ param { jQuery | String } selector where to show the footer
* @ param { String } nation
* /
function showFooterByNation ( selector , nation ) {
var jelem = jQuery ( selector ) ;
var footer = "/icc_footer.inc.php" ;
switch ( nation ) {
case "GER" :
footer = "/dav_footer.inc.php" ;
break ;
case "SUI" :
footer = "/sac_footer.inc.php p:not(.register)" ;
break ;
}
jelem . load ( footer , function ( ) {
jelem . fadeIn ( "slow" ) ;
} ) ;
}
/ * *
* Show category specific footer
*
* @ param { jQuery | String } selector where to show the footer
* @ param { Number | String } cat default read it from cat parameter of document
* /
function showFooterByCat ( selector , cat ) {
if ( ! cat )
cat = ( document . location . href . match ( /cat=([a-z]{3}|\d+)/i ) || [ ] ) [ 1 ] ;
var national _cats = {
GER : [
212 , 211 , 207 , 294 , 205 , 14 , 202 , 201 , 296 , 200 , 206 , 213 , 4 , 215 , 13 ,
108 , 12 , 11 , 66 , 7 , 226 , 223 , 217 , 216 , 214 , 25 , 54 , 109 , 107 , 106 , 67 ,
48 , 49 , 50 , 51 , 52 , 53 , 110 , 111 , 113 , 114 , 28 , 27 , 26 , 112 , 115 ,
] ,
SUI : [
47 , 46 , 44 , 116 , 30 , 35 , 69 , 68 , 43 , 41 , 209 , 208 , 219 , 222 , 31 , 32 , 33 ,
34 , 36 , 37 , 38 , 39 ,
] ,
} ;
for ( var nation in national _cats ) {
if (
cat . toUpperCase ( ) === nation ||
national _cats [ nation ] . indexOf ( parseInt ( cat ) ) >= 0
) {
showFooterByNation ( selector , nation ) ;
return ;
}
}
showFooterByNation ( selector ) ;
}
/ * *
* Baseclass for all widgets
*
* We only use jQuery ( ) here ( not $ ( ) or $j ( ) ! ) to be able to run as well inside EGroupware as with stock jQuery from googleapis .
* /
var DrBaseWidget = ( function ( ) {
/ * *
* Constructor for all widgets from given json url
*
* Table get appended to specified _container
*
* @ param _container
* @ param _json _url url for data to load
* /
function DrBaseWidget ( _container , _json _url ) {
this . json _url = _json _url ;
this . container = jQuery (
typeof _container == "string" ? "#" + _container : _container
) ;
this . container . addClass ( this . constructor . name ) ;
}
/ * *
* Install update method as popstate or hashchange handler
* /
DrBaseWidget . prototype . installPopState = function ( ) {
// add popstate or hashchange (IE8,9) event listener, to use browser back button for navigation
// some browsers, eg. Chrome, generate a pop on inital page-load
// to prevent loading page initially twice, we store initial location
this . prevent _initial _pop = location . href ;
var initial _params = this . json _url . replace ( /^.*(#!|#|\?)/ , "" ) || "" ;
var that = this ;
jQuery ( window ) . bind (
window . history . pushState ? "popstate" : "hashchange" ,
function ( e ) {
if (
! that . prevent _initial _pop ||
that . prevent _initial _pop != location . href
) {
that . update ( location . hash || location . query || initial _params ) ;
}
delete that . prevent _initial _pop ;
}
) ;
} ;
/ * *
* Update Widget from json _url
*
* To be able to cache jsonp requests in CDN , we have to use the same callback .
* Using same callback leads to problems with concurrent requests : failed : parsererror ( jsonp was not called )
* To work around that we queue jsonp request , if there ' s already one running .
*
* Queue is maintained globally in DrBaseWidget . jsonp _queue , as requests come from different objects !
*
* @ param { boolean } ignore _queue used internally to start next object in queue without requeing it
* /
DrBaseWidget . prototype . update = function ( ignore _queue ) {
// remove our own parameters and current year from json url to improve caching
var url = this . json _url
. replace ( /(detail|beamer|rotate|toc)=[^&]*(&|$)/ , "" )
. replace ( new RegExp ( "year=" + new Date ( ) . getFullYear ( ) + "(&|$)" ) , "" )
. replace ( /&$/ , "" ) ;
// do we need a jsonp request
var jsonp =
this . json _url . indexOf ( "//" ) != - 1 &&
this . json _url . split ( "/" , 3 ) != location . href . split ( "/" , 3 ) ;
if ( typeof DrBaseWidget . jsonp _queue == "undefined" )
DrBaseWidget . jsonp _queue = [ ] ;
if ( ! ignore _queue && jsonp ) {
// add us to the queue
DrBaseWidget . jsonp _queue . push ( this ) ;
}
// if there's only one in the queue (or no queueing necessary: no jsonp) --> send ajax request
if ( ignore _queue || ! jsonp || DrBaseWidget . jsonp _queue . length == 1 ) {
jQuery . ajax ( {
url : url ,
async : true ,
context : this ,
data : "" ,
dataType : jsonp ? "jsonp" : "json" ,
jsonpCallback : "jsonp" , // otherwise jQuery generates a random name, not cachable by CDN
cache : true ,
type : "GET" ,
success : function ( _data ) {
// if we are first object in queue, remove us
if ( DrBaseWidget . jsonp _queue [ 0 ] === this )
DrBaseWidget . jsonp _queue . shift ( ) ;
// if someone left in queue, run it's update ignore the queue
if ( DrBaseWidget . jsonp _queue . length )
DrBaseWidget . jsonp _queue [ 0 ] . update ( true ) ;
this . handleResponse ( _data ) ;
} ,
error : function ( _xmlhttp , _err , _status ) {
// need same handling as success
if ( DrBaseWidget . jsonp _queue [ 0 ] === this )
DrBaseWidget . jsonp _queue . shift ( ) ;
if ( DrBaseWidget . jsonp _queue . length )
DrBaseWidget . jsonp _queue [ 0 ] . update ( true ) ;
//if (_err != 'timeout') alert('Ajax request to '+this.json_url+' failed: '+_err+(_status?' ('+_status+')':''));
// schedule update again after 60sec
this . update _handle = window . setTimeout (
jQuery . proxy ( this . update , this , ignore _queue ) ,
60000
) ;
} ,
} ) ;
}
} ;
/ * *
* Callback for loading data via ajax
*
* Virtual , need to be implemented in inheriting objects !
*
* @ param _data
* /
DrBaseWidget . prototype . handleResponse = function ( _data ) {
throw (
"No handleResponse implemented in " +
this . constructor . name +
" inheriting from DrBaseWidget!"
) ;
} ;
/ * *
* Add list with see also links , if not beamer or toc disabled
*
* @ param _see _also
* /
DrBaseWidget . prototype . seeAlso = function ( _see _also ) {
this . container . find ( "ul.seeAlso" ) . remove ( ) ;
if (
typeof _see _also != "undefined" &&
_see _also . length > 0 &&
! this . json _url . match ( /toc=0/ ) &&
! this . json _url . match ( /beamer=1/ )
) {
var ul = jQuery ( document . createElement ( "ul" ) ) . attr ( "class" , "seeAlso" ) ;
ul . prepend ( document . createTextNode ( this . lang ( "See also:" ) ) ) ;
for ( var i = 0 ; i < _see _also . length ; ++ i ) {
var tag = jQuery ( document . createElement ( "li" ) ) ;
ul . append ( tag ) ;
if ( _see _also [ i ] . url ) {
var a = jQuery ( document . createElement ( "a" ) ) . attr (
"href" ,
_see _also [ i ] . url
) ;
tag . append ( a ) ;
if ( this . navigateTo ) {
a . click ( this . navigateTo ) ;
}
tag = a ;
}
tag . text ( _see _also [ i ] . name ) ;
}
this . container . append ( ul ) ;
}
} ;
/ * *
* Replace attribute named from with one name to and value keeping the order of the attributes
*
* @ param { object } obj
* @ param { string } from
* @ param { string } to
* @ param { * } value
* /
DrBaseWidget . prototype . replace _attribute = function ( obj , from , to , value ) {
var found = false ;
for ( var attr in obj ) {
if ( ! found ) {
if ( attr == from ) {
found = true ;
delete obj [ attr ] ;
obj [ to ] = value ;
}
} else {
var val = obj [ attr ] ;
delete obj [ attr ] ;
obj [ attr ] = val ;
}
}
} ;
/ * *
* Replace "nation" column with what ' s specified in "display_athlete" on competition
*
* @ param { string } _display _athlete
* @ param { string } _nation
* /
DrBaseWidget . prototype . replace _nation = function ( _display _athlete , _nation ) {
switch ( _display _athlete ) {
case "none" :
delete this . columns . nation ;
break ;
case "city" :
case "pc_city" :
this . replace _attribute ( this . columns , "nation" , "city" , "City" ) ;
break ;
case "federation" :
case "fed_and_parent" :
var fed _label = "Federation" ;
switch ( _nation ) {
case "GER" :
fed _label = "DAV Sektion" ;
break ;
case "SUI" :
fed _label = "Sektion" ;
break ;
}
this . replace _attribute ( this . columns , "nation" , "federation" , fed _label ) ;
break ;
}
} ;
/ * *
* Format a date according to browser local format
*
* @ param { string } _ymd yyyy - mm - dd string or everything understood by date constructor
* @ returns { string }
* /
DrBaseWidget . prototype . formatDate = function ( _ymd ) {
if ( ! _ymd || typeof _ymd != "string" ) return "" ;
var date = new Date ( _ymd ) ;
return date . toLocaleDateString ( ) . replace ( /[0-9]+\./g , function ( _match ) {
return _match . length <= 2 ? "0" + _match : _match ;
} ) ;
} ;
/ * *
* Translate english phrase into user language
*
* @ param { string } _msg
* @ returns { string }
* /
DrBaseWidget . prototype . lang = function ( _msg ) {
if ( _msg === null ) {
return "" ;
}
if ( typeof _msg !== "string" && _msg ) {
console . log ( "Cannot translate an object" , _msg ) ;
return _msg ;
}
var translation = _msg ;
if ( typeof dr _translations !== "undefined" ) {
if ( typeof DrBaseWidget . user _lang === "undefined" ) {
var language =
( navigator . languages && navigator . languages [ 0 ] ) || // Chrome / Firefox
navigator . language || // All browsers
navigator . userLanguage ; // IE <= 10
DrBaseWidget . user _lang = language . replace ( /-[A-Z]+/ , "" ) ;
}
if (
dr _translations [ _msg ] &&
dr _translations [ _msg ] [ DrBaseWidget . user _lang ]
) {
translation = dr _translations [ _msg ] [ DrBaseWidget . user _lang ] ;
}
}
if ( arguments . length == 1 ) return translation ;
if ( arguments . length == 2 ) return translation . replace ( "%1" , arguments [ 1 ] ) ;
// to cope with arguments containing '%2' (eg. an urlencoded path like a referer),
// we first replace all placeholders '%N' with '|%N|' and then we replace all '|%N|' with arguments[N]
translation = translation . replace ( /%([0-9]+)/g , "|%$1|" ) ;
for ( var i = 1 ; i < arguments . length ; ++ i ) {
translation = translation . replace ( "|%" + i + "|" , arguments [ i ] ) ;
}
return translation ;
} ;
return DrBaseWidget ;
} ) ( ) ;
/ * *
* DrTable helper to construct table from colum - defition and data
* /
var DrTable = ( function ( ) {
/ * *
* Constructor for table with given data and columns
*
* Table get appended to specified _container
*
* @ param _data array with data for each participant
* @ param _columns hash with column name => header
* @ param _sort column name to sort by
* @ param _ascending
* @ param _quota quota if quota line should be drawn in result
* @ param _navigateTo click method for profiles
* @ param _showUnranked if true AND _sort == 'result_rank' show participants without rank , default do NOT show them
* /
function DrTable (
_data ,
_columns ,
_sort ,
_ascending ,
_quota ,
_navigateTo ,
_showUnranked
) {
this . data = _data ;
this . columns = _columns ;
if ( typeof _sort == "undefined" ) for ( _sort in _columns ) break ;
this . sort = _sort ;
if ( typeof _ascending == "undefined" ) _ascending = true ;
this . ascending = _ascending ;
this . quota = parseInt ( _quota ) ;
this . navigateTo = _navigateTo ;
this . showUnranked = _showUnranked ? true : false ;
// hash with PerId => tr containing athlete
this . athletes = { } ;
this . sortData ( ) ;
// header
this . dom = document . createElement ( "table" ) ;
jQuery ( this . dom ) . addClass ( "DrTable" ) ;
var thead = document . createElement ( "thead" ) ;
jQuery ( this . dom ) . append ( thead ) ;
var row = this . createRow ( this . columns , "th" ) ;
jQuery ( thead ) . append ( row ) ;
// athletes
var tbody = jQuery ( document . createElement ( "tbody" ) ) ;
jQuery ( this . dom ) . append ( tbody ) ;
for ( var i = 0 ; i < this . data . length ; ++ i ) {
var data = this . data [ i ] ;
if ( Array . isArray ( data . results ) ) {
// category with result
if ( typeof this . column _count == "undefined" ) {
this . column _count = 0 ;
for ( var c in this . columns ) ++ this . column _count ;
}
if ( typeof data . name != "undefined" ) {
row = document . createElement ( "tr" ) ;
var th = jQuery ( document . createElement ( "th" ) ) ;
th . attr ( "colspan" , this . column _count ) ;
th . text ( data . name ) ;
if ( typeof data . url != "undefined" ) {
var a = jQuery ( document . createElement ( "a" ) ) ;
a . attr ( "href" , data . url ) ;
a . text ( this . lang ( "Complete Results" ) ) ;
if ( this . navigateTo || typeof data . click != "undefined" )
a . click ( this . navigateTo || data . click ) ;
th . append ( a ) ;
}
jQuery ( row ) . append ( th ) ;
tbody . append ( row ) ;
}
for ( var j = 0 ; j < data . results . length ; ++ j ) {
tbody . append ( this . createRow ( data . results [ j ] ) ) ;
}
} // single result row
else {
if (
this . sort == "result_rank" &&
( ( typeof data . result _rank == "undefined" && ! this . showUnranked ) ||
data . result _rank < 1 )
) {
break ; // no more ranked competitiors
}
tbody . append ( this . createRow ( data ) ) ;
}
}
//console.log(this.athletes);
}
DrTable . prototype . lang = DrBaseWidget . prototype . lang ;
/ * *
* Update table with new data , trying to re - use existing rows
*
* @ param _data array with data for each participant
* @ param _quota quota if quota line should be drawn in result
* /
DrTable . prototype . update = function ( _data , _quota ) {
this . data = _data ;
if ( typeof _quota != "undefined" ) this . quota = parseInt ( _quota ) ;
//console.log(this.data);
this . sortData ( ) ;
var tbody = this . dom . firstChild . nextSibling ;
var pos ;
// uncomment to test update: reverses the list on every call
//if (this.data[0].PerId == tbody.firstChild.id) this.data.reverse();
var athletes = this . athletes ;
this . athletes = { } ;
for ( var i = 0 ; i < this . data . length ; ++ i ) {
var data = this . data [ i ] ;
var row ;
if ( data . PerId != "undefined" ) {
row = athletes [ data . PerId ] ;
} else if ( data . team _id != "undefined" ) {
row = athletes [ data . team _id ] ;
}
if (
this . sort == "result_rank" &&
( typeof data . result _rank == "undefined" || data . result _rank < 1 )
) {
break ; // no more ranked competitiors
}
// search athlete in tbody
if ( typeof row != "undefined" ) {
//jQuery(row).detach();
//this.updateRow(row,data);
jQuery ( row ) . remove ( ) ;
}
//else
{
row = this . createRow ( data ) ;
}
// no child in tbody --> append row
if ( typeof pos == "undefined" ) {
jQuery ( tbody ) . prepend ( row ) ;
} else {
jQuery ( pos ) . after ( row ) ;
}
pos = row ;
}
// remove further rows / athletes not in this.data
if ( typeof pos != "undefined" && typeof pos . nextSibling != "undefined" ) {
jQuery ( "#" + pos . id + " ~ tr" ) . remove ( ) ;
}
} ;
/ * *
* Update given data - row with changed content
*
* @ param { object } _row
* @ param { object } _data
* @ todo
* /
DrTable . prototype . updateRow = function ( _row , _data ) { } ;
/ * *
* Create new data - row with all columns from this . columns
*
* @ param { object } _data
* @ param { string } [ _tag = td ]
* /
DrTable . prototype . createRow = function ( _data , _tag ) {
//console.log(_data);
if ( typeof _tag == "undefined" ) _tag = "td" ;
var row = document . createElement ( "tr" ) ;
if ( typeof _data . PerId != "undefined" && _data . PerId > 0 ) {
row . id = _data . PerId ;
if ( _data . className ) {
row . className = _data . className ;
if ( row . className . match ( /hideNames/ ) )
row . title = this . lang ( "Athlete asked not to show his name anymore." ) ;
}
this . athletes [ _data . PerId ] = row ;
} else if ( typeof _data . team _id != "undefined" && _data . team _id > 0 ) {
row . id = _data . team _id ;
this . athletes [ _data . team _id ] = row ;
}
var span = 1 ;
for ( var col in this . columns ) {
if ( -- span > 0 ) continue ;
var url = _data . url ;
// if object has a special getter func, call it
var col _data ;
if ( typeof this . columns [ col ] == "function" ) {
col _data = this . columns [ col ] . call ( this , _data , _tag , col ) ;
} else {
col _data = _data [ col ] ;
}
// allow /-delemited expressions to index into arrays and objects
if ( typeof col _data == "undefined" && col . indexOf ( "/" ) != - 1 ) {
var parts = col . split ( "/" ) ;
col _data = _data ;
for ( var p in parts ) {
col = parts [ p ] ;
if ( col == "lastname" || col == "firstname" ) url = col _data . url ;
if ( typeof col _data != "undefined" ) col _data = col _data [ col ] ;
}
} else if ( col . indexOf ( "/" ) != - 1 )
col = col . substr ( col . lastIndexOf ( "/" ) + 1 ) ;
var tag = document . createElement ( _tag ) ;
tag . className = col ;
jQuery ( row ) . append ( tag ) ;
// add pstambl link to name & vorname
if (
typeof url != "undefined" &&
( col == "lastname" || col == "firstname" )
) {
var a = document . createElement ( "a" ) ;
a . href = url ;
a . target = "pstambl" ;
if ( this . navigateTo && url . indexOf ( "#" ) != - 1 )
jQuery ( a ) . click ( this . navigateTo ) ;
jQuery ( tag ) . append ( a ) ;
tag = a ;
}
if (
typeof _data . fed _url != "undefined" &&
( col == "nation" || col == "federation" )
) {
var a = document . createElement ( "a" ) ;
a . href = _data . fed _url ;
a . target = "_blank" ;
jQuery ( tag ) . append ( a ) ;
tag = a ;
}
if ( typeof col _data == "object" && col _data ) {
if ( typeof col _data . nodeName != "undefined" ) {
jQuery ( tag ) . append ( col _data ) ;
} else {
if ( col _data . colspan > 1 ) tag . colSpan = span = col _data . colspan ;
if ( col _data . className ) tag . className = col _data . className ;
if ( col _data . title ) tag . title = col _data . title ;
if ( col _data . url || col _data . click ) {
var a = document . createElement ( "a" ) ;
a . href = col _data . url || "#" ;
if ( col _data . click || this . navigateTo ) {
jQuery ( a ) . click ( col _data . click || this . navigateTo ) ;
}
jQuery ( tag ) . append ( a ) ;
tag = a ;
}
if ( col _data . nodes ) {
jQuery ( tag ) . append ( col _data . nodes ) ;
} else {
jQuery ( tag ) . text ( col _data . label ) ;
}
}
} else {
jQuery ( tag ) . text ( typeof col _data != "undefined" ? col _data : "" ) ;
span = 1 ;
}
}
// add or remove quota line
if (
this . sort == "result_rank" &&
this . quota &&
_data . result _rank &&
parseInt ( _data . result _rank ) >= 1 &&
parseInt ( _data . result _rank ) > this . quota
) {
row . className = "quota_line" ;
delete this . quota ; // to set quota line only once
}
return row ;
} ;
/ * *
* Sort data according to sort criteria
*
* @ todo get using this . sortNummeric callback working
* /
DrTable . prototype . sortData = function ( ) {
function sortResultRank ( _a , _b ) {
var rank _a = _a [ "result_rank" ] ;
if ( typeof rank _a == "undefined" || rank _a < 1 ) rank _a = 9999 ;
var rank _b = _b [ "result_rank" ] ;
if ( typeof rank _b == "undefined" || rank _b < 1 ) rank _b = 9999 ;
var ret = rank _a - rank _b ;
if ( ! ret ) ret = _a [ "lastname" ] > _b [ "lastname" ] ? 1 : - 1 ;
if ( ! ret ) ret = _a [ "firstname" ] > _b [ "firstname" ] ? 1 : - 1 ;
return ret ;
}
switch ( this . sort ) {
case false : // dont sort
break ;
case "result_rank" :
// not necessary as server returns them sorted this way
//this.data.sort(sortResultRank);
break ;
default :
var sort = this . sort ;
this . data . sort ( function ( _a , _b ) {
var a = sort == "start_order" ? parseInt ( _a [ sort ] ) : _a [ sort ] ;
var b = sort == "start_order" ? parseInt ( _b [ sort ] ) : _b [ sort ] ;
return a == b ? 0 : a < b ? - 1 : 1 ;
//return _a[sort] == _b[sort] ? 0 : (_a[sort] < _b[sort] ? -1 : 1);
} ) ;
break ;
}
if ( ! this . ascending ) this . data . reverse ( ) ;
} ;
return DrTable ;
} ) ( ) ;
/ * *
* Startlist widget inheriting from DrBaseWidget
* /
var Startlist = ( function ( ) {
/ * *
* Constructor for startlist from given json url
*
* Table get appended to specified _container
*
* @ param _container
* @ param _json _url url for data to load
* @ param { boolean } _no _navigation do NOT display TOC
* /
function Startlist ( _container , _json _url , _no _navigation ) {
DrBaseWidget . prototype . constructor . call ( this , _container , _json _url ) ;
this . no _navigation = _no _navigation ;
// do not continue, as constructor is called when inheriting from Startlist without parameters!
if ( typeof _container == "undefined" ) return ;
// Variables needed for scrolling in upDown
// scroll speed
this . scroll _by = 1 ;
// scroll interval, miliseconds (will be changed on resized windows where scroll_by is increased, so a constant scrolling speed is maintained)
this . scroll _interval = 20 ;
// current scrolling direction. 1: down, -1: up
this . scroll _dir = 1 ;
// sleep on the borders for sleep_for seconds
this . sleep _for = 4 ;
// margin in which to reverse scrolling
// CAUTION: At the beginning, we scroll pixelwise through the margin, one pixel each sleep_for seconds. Do not change the margin unless you know what you do.
this . margin = 2 ;
// helper variable
var now = new Date ( ) ;
this . sleep _until = now . getTime ( ) + 10000 ;
this . first _run = true ;
this . do _rotate = false ;
this . update ( ) ;
if ( this . json _url . match ( /rotate=/ ) ) {
var list = this ;
// 20110716: This doesn't seem to be needed anymore. Comment it for now.
//window.scrollBy(0, 20);
this . scroll _interval _handle = window . setInterval ( function ( ) {
list . upDown ( ) ;
} , 20 ) ;
}
}
// inherit from DrBaseWidget
Startlist . prototype = new DrBaseWidget ( ) ;
Startlist . prototype . constructor = Startlist ;
/ * *
* Callback for loading data via ajax
*
* @ param _data route data object
* /
Startlist . prototype . handleResponse = function ( _data ) {
//console.log(_data);
var detail = this . json _url . match ( /detail=([^&]+)/ ) ;
if ( detail ) detail = detail [ 1 ] ;
switch ( _data . discipline ) {
case "speedrelay" :
this . startlist _cols =
detail === null
? {
// default detail
start _order : this . lang ( "StartNr" ) ,
team _name : this . lang ( "Teamname" ) ,
"athletes/0/lastname" : this . lang ( "Athlete #1" ) ,
"athletes/1/lastname" : this . lang ( "Athlete #2" ) ,
"athletes/2/lastname" : this . lang ( "Athlete #3" ) ,
}
: detail
? {
// detail=1
start _order : this . lang ( "StartNr" ) ,
team _name : this . lang ( "Teamname" ) ,
//'team_nation': 'Nation',
"athletes/0/lastname" : {
label : this . lang ( "Athlete #1" ) ,
colspan : 3 ,
} ,
"athletes/0/firstname" : "" ,
"athletes/0/result_time" : "" ,
"athletes/1/lastname" : {
label : this . lang ( "Athlete #2" ) ,
colspan : 3 ,
} ,
"athletes/1/firstname" : "" ,
"athletes/1/result_time" : "" ,
"athletes/2/lastname" : {
label : this . lang ( "Athlete #3" ) ,
colspan : 3 ,
} ,
"athletes/2/firstname" : "" ,
"athletes/2/result_time" : "" ,
}
: {
// detail=0
start _order : this . lang ( "StartNr" ) ,
team _name : this . lang ( "Teamname" ) ,
team _nation : this . lang ( "Nation" ) ,
} ;
break ;
case "combined" :
this . result _cols . final _points = this . lang ( "Final Points" ) ;
delete this . result _cols . start _number ; // table is far too big anyway
// fall through
default :
this . startlist _cols = {
start _order : { label : this . lang ( "StartNr" ) , colspan : 2 } ,
start _number : "" ,
lastname : { label : this . lang ( "Name" ) , colspan : 2 } ,
firstname : "" ,
birthyear : this . lang ( "Birthyear" ) ,
nation : this . lang ( "Nation" ) ,
} ;
break ;
}
// if quali_preselected and heat = 1||2, we have to use a function to get either start_order or text "preselected"
if (
_data . quali _preselected &&
( _data . route _order == 0 || _data . route _order == 1 )
) {
var quali _preselected = _data . quali _preselected ;
var start _order = this . startlist _cols . start _order ;
this . startlist _cols . start _order = function ( _data , _tag , col ) {
if ( _tag == "th" ) return start _order ;
if ( _data . ranking <= quali _preselected )
return this . lang ( "Vorqualifiziert" ) ; //'preselected';
return _data [ col ] ;
} ;
}
var sort ;
// if we have no result columns or no ranked participant, show a startlist
if (
typeof this . result _cols == "undefined" ||
( _data . participants [ 0 ] &&
! _data . participants [ 0 ] . result _rank &&
_data . discipline != "ranking" )
) {
this . columns = this . startlist _cols ;
sort = "start_order" ;
this . container . attr ( "class" , "Startlist" ) ;
}
// if we are a result showing a startlist AND have now a ranked participant
// --> switch back to result
else {
this . columns = this . result _cols ;
sort = "result_rank" ;
}
this . replace _nation ( _data . display _athlete , _data . nation ) ;
// fix route_names containing only one or two qualifications are send as array because index 0 and 1
if ( Array . isArray ( _data . route _names ) ) {
var route _names = _data . route _names ;
delete _data . route _names ;
_data . route _names = { } ;
for ( var i = 0 ; i < route _names . length ; ++ i ) {
_data . route _names [ i ] = route _names [ i ] ;
}
}
// keep route_names to detect additional routes on updates
if ( typeof this . route _names == "undefined" ) {
this . route _names = _data . route _names ;
}
// remove whole table, if the discipline is speed and the number of route_names changes
if ( _data . discipline == "speed" && this . json _url . match ( /route=-1/ ) ) {
// && this.route_names != _data.route_names)
for ( var i = 2 ; i < 10 ; i ++ ) {
if ( typeof _data . route _names [ i ] != typeof this . route _names [ i ] ) {
// there was an update of the route_names array
this . route _names = _data . route _names ;
jQuery ( this . container ) . empty ( ) ;
delete this . table ;
break ;
}
}
}
// remove whole table, if discipline or startlist/resultlist (detemined by sort) changed
if (
( this . discipline && this . discipline != _data . discipline ) ||
( this . sort && this . sort != sort ) ||
_data . route _order != this . route _order || // switching heats (they can have different columns)
detail !== this . detail || // switching detail on/off
this . json _url != this . last _json _url
) {
jQuery ( this . container ) . empty ( ) ;
delete this . table ;
}
this . discipline = _data . discipline ;
this . sort = sort ;
this . route _order = _data . route _order ;
this . detail = detail ;
this . last _json _url = this . json _url ;
if ( typeof this . table == "undefined" ) {
// for general result use one column per heat
if ( this . columns . result && _data . route _names && _data . route _order == - 1 ) {
delete this . columns . result ;
// show final first and 2. quali behind 1. quali: eg. 3, 2, 0, 1
var routes = [ ] ;
if ( _data . route _names [ "1" ] ) routes . push ( "1" ) ;
for ( var id in _data . route _names ) {
if ( id != "-1" && id != "1" ) routes . push ( id ) ;
}
routes . reverse ( ) ;
for ( var i = 0 ; i < routes . length ; ++ i ) {
var route = routes [ i ] ;
// for ranking, we add link to results
if ( _data . discipline == "ranking" ) {
var id = route . replace ( / $/ , "" ) ; // remove space append to force js to keep the order
var comp _cat = id . split ( "_" ) ;
this . columns [ "result" + id ] = {
label : _data . route _names [ route ] ,
url :
"#!comp=" +
comp _cat [ 0 ] +
"&cat=" +
( comp _cat [ 1 ] || _data . cat . GrpId ) ,
} ;
} else {
this . columns [ "result" + route ] = _data . route _names [ route ] ;
}
}
// evtl. add points column
if ( _data . participants [ 0 ] && _data . participants [ 0 ] . quali _points ) {
this . columns [ "quali_points" ] = this . lang ( "Points" ) ;
// delete single qualification results
if ( this . no _navigation ) {
delete this . columns . result0 ;
delete this . columns . result1 ;
if ( _data . discipline == "combined" ) delete this . columns . result2 ;
this . columns [ "quali_points" ] =
_data . discipline == "combined"
? this . lang ( "Quali." )
: this . lang ( "Qualification" ) ;
}
}
if (
_data . discipline == "combined" &&
_data . participants [ 0 ] &&
typeof _data . participants [ 0 ] . final _points == "undefined"
) {
delete this . columns . final _points ;
}
title _prefix = "" ;
}
if (
this . columns . result &&
_data . participants [ 0 ] &&
_data . participants [ 0 ] . rank _prev _heat &&
! this . json _url . match ( /detail=0/ )
) {
this . columns [ "rank_prev_heat" ] = this . lang ( "previous heat" ) ;
}
// competition
this . comp _header = jQuery ( document . createElement ( "h1" ) ) ;
jQuery ( this . container ) . append ( this . comp _header ) ;
this . comp _header . addClass ( "compHeader" ) ;
// result date
this . result _date = jQuery ( document . createElement ( "h3" ) ) ;
jQuery ( this . container ) . append ( this . result _date ) ;
this . result _date . addClass ( "resultDate" ) ;
// route header
this . header = jQuery ( document . createElement ( "h1" ) ) ;
jQuery ( this . container ) . append ( this . header ) ;
this . header . addClass ( "listHeader" ) ;
// display a toc with all available heats, if not explicitly disabled (toc=0) or beamer
this . displayToc ( _data ) ;
// create new table
if ( ! _data . error && _data . participants . length ) {
this . table = new DrTable (
_data . participants ,
this . columns ,
this . sort ,
true ,
_data . route _result ? _data . route _quota : null ,
this . navigateTo ,
_data . discipline == "ranking" &&
( detail || ! _data . participants [ 0 ] . result _rank )
) ;
if ( _data . participants [ 0 ] . result _rank )
jQuery ( this . table . dom ) . addClass ( _data . discipline ) ;
jQuery ( this . container ) . append ( this . table . dom ) ;
}
this . seeAlso ( _data . see _also ) ;
} else {
// update a toc with all available heats, if not explicitly disabled (toc=0) or beamer
this . displayToc ( _data ) ;
// update existing table
this . table . update (
_data . participants ,
_data . route _result ? _data . route _quota : null
) ;
}
// set/update header line
this . setHeader ( _data ) ;
// if route is NOT offical, update list every 10 sec, of category not offical update every 5min (to get new heats)
if ( ! _data . category _offical && this . discipline != "ranking" ) {
var list = this ;
this . update _handle = window . setTimeout ( function ( ) {
list . update ( ) ;
} , _data . expires * 1000 ) ;
//console.log('setting up refresh in '+_data.expires+' seconds');
}
} ;
/ * *
* Create or update TOC ( list of available routes for navigation )
*
* Can be disabled via "toc=0" or "beamer=1" in json _url . Always disabled for rankings .
*
* @ param _data route data object
* /
Startlist . prototype . displayToc = function ( _data ) {
if (
this . json _url . match ( /toc=0/ ) ||
this . json _url . match ( /beamer=1/ ) ||
this . discipline == "ranking" ||
this . no _navigation
) {
return ; // --> no toc
}
var toc = this . container . find ( "ul.listToc" ) ;
var new _toc = ! toc . length ;
if ( new _toc ) toc = jQuery ( document . createElement ( "ul" ) ) . addClass ( "listToc" ) ;
else toc . empty ( ) ;
var href = location . href . replace ( /\?(.*)#/ , "#" ) ; // prevent query and hash messing up navigation
for ( var r in _data . route _names ) {
if ( r != this . route _order ) {
var li = jQuery ( document . createElement ( "li" ) ) ;
var a = jQuery ( document . createElement ( "a" ) ) ;
a . text ( _data . route _names [ r ] . replace ( " - " , "-" ) ) ;
var reg _exp = /route=[^&]+/ ;
var url = href . replace ( reg _exp , "route=" + r ) ;
if ( url . indexOf ( "route=" ) == - 1 ) url += "&route=" + r ;
a . attr ( "href" , url ) ;
if ( this . navigateTo ) {
a . click ( this . navigateTo ) ;
} else {
var that = this ;
a . click ( function ( e ) {
that . json _url = that . json _url . replace (
reg _exp ,
this . href . match ( reg _exp ) [ 0 ]
) ;
if ( that . json _url . indexOf ( "route=" ) == - 1 )
that . json _url += "&route=" + r ;
that . update ( ) ;
e . preventDefault ( ) ;
} ) ;
}
li . append ( a ) ;
toc . prepend ( li ) ;
}
}
// only add toc, if we have more then one route
if ( ! new _toc ) {
// already added
} else if ( toc . children ( ) . length ) {
jQuery ( this . container ) . append ( toc ) ;
} else {
toc . remove ( ) ;
}
// add category toc
if ( typeof _data . categorys == "undefined" ) return ;
var toc = this . container . find ( "ul.listCatToc" ) ;
var new _toc = ! toc . length ;
if ( new _toc )
toc = jQuery ( document . createElement ( "ul" ) ) . addClass ( "listCatToc" ) ;
else toc . empty ( ) ;
var cats = this . shortenNames ( _data . categorys , "name" ) ;
for ( var i = 0 ; i < cats . length ; ++ i ) {
var cat = cats [ i ] ;
if ( cat . GrpId != _data . GrpId ) {
var li = jQuery ( document . createElement ( "li" ) ) ;
var a = jQuery ( document . createElement ( "a" ) ) ;
a . text ( cat . name ) ;
var reg _exp = /cat=[^&]+/ ;
var url = href . replace ( reg _exp , "cat=" + cat . GrpId ) ;
if ( url . indexOf ( "cat=" ) == - 1 ) url += "&cat=" + cat . GrpId ;
a . attr ( "href" , url ) ;
if ( this . navigateTo ) {
a . click ( this . navigateTo ) ;
} else {
var that = this ;
a . click ( function ( e ) {
that . json _url = that . json _url . replace (
reg _exp ,
this . href . match ( reg _exp ) [ 0 ]
) ;
if ( that . json _url . indexOf ( "cat=" ) == - 1 )
that . json _url += "cat=" + cat . GrpId ;
that . update ( ) ;
e . preventDefault ( ) ;
} ) ;
}
li . append ( a ) ;
toc . append ( li ) ;
}
}
// only add toc, if we have more then one route
if ( ! new _toc ) {
// already added
} else if ( toc . children ( ) . length ) {
jQuery ( this . container ) . append ( toc ) ;
} else {
toc . remove ( ) ;
}
} ;
/ * *
* Shorten several names by removing parts common to all and remove spacing ( eg . "W O M E N" -- > "WOMEN" )
*
* shortenNames [ "M E N speed" , "W O M E N speed" ] ) returns [ "MEN" , "WOMEN" ]
*
* @ param { array } names array of strings or objects with attribute attr
* @ param { string } attr attribute name to use or undefined
* @ return { array }
* /
Startlist . prototype . shortenNames = function ( names , attr ) {
if ( ! jQuery . isArray ( names ) || ! names . length ) return names ;
var split _by _regexp = / +/ ;
var spacing _regexp = /([A-Z]) ([A-Z])/ ;
var strs = [ ] ;
for ( var i = 0 ; i < names . length ; ++ i ) {
var name = names [ i ] ;
if ( attr ) name = name [ attr ] ;
do {
var n = name ;
name = name . replace ( spacing _regexp , "$1$2" ) ;
} while ( n != name ) ;
strs . push ( name . split ( split _by _regexp ) ) ;
}
var first = [ ] . concat ( strs [ 0 ] ) ;
for ( var i = 0 ; i < first . length ; ++ i ) {
for ( var j = 1 ; j < strs . length ; ++ j ) {
if ( jQuery . inArray ( first [ i ] , strs [ j ] ) == - 1 ) {
break ;
}
}
if ( j == strs . length ) {
// in all strings --> remove first[i] from all strings
for ( var j = 0 ; j < strs . length ; ++ j ) {
strs [ j ] . splice ( jQuery . inArray ( first [ i ] , strs [ j ] ) , 1 ) ;
}
}
}
for ( var j = 0 ; j < strs . length ; ++ j ) {
strs [ j ] = strs [ j ] . join ( " " ) ;
if ( attr ) {
names [ j ] [ attr ] = strs [ j ] ;
} else {
names [ j ] = strs [ j ] ;
}
}
return names ;
} ;
/ * *
* Set header with a ( provisional ) Result or Startlist prefix
*
* @ param _data
* @ return
* /
Startlist . prototype . setHeader = function ( _data ) {
var title _prefix =
( this . sort == "start_order"
? this . lang ( "Startlist" )
: _data . route _result
? this . lang ( "Result" )
: this . lang ( "provisional Result" ) ) + ": " ;
var header = _data . route _name ;
// if NOT detail=0 and not for general result, add prefix before route name
if ( ! this . json _url . match ( /detail=0/ ) && _data . route _order != - 1 )
header = title _prefix + header ;
document . title = header ;
this . comp _header . empty ( ) ;
this . comp _header . text ( _data . comp _name ) ;
this . result _date . empty ( ) ;
if ( _data . error ) {
this . result _date . text ( _data . error ) ;
this . result _date . removeClass ( "resultDate" ) ;
this . result _date . addClass ( "error" ) ;
} else if ( _data . route _result ) {
this . result _date . text ( _data . route _result ) ;
this . result _date . prepend (
document . createTextNode ( this . lang ( "As of" ) + " " )
) ;
this . result _date . append (
document . createTextNode ( " " + this . lang ( "after" ) )
) ;
}
this . header . empty ( ) ;
this . header . text ( header ) ;
} ;
/ * *
* Return the current scrolling position , which is the top of the current view .
* /
Startlist . prototype . currentTopPosition = function ( ) {
var y = 0 ;
if ( window . pageYOffset ) {
// all other browsers
y = window . pageYOffset ;
} else if ( document . body && document . body . scrollTop ) {
// IE
y = document . body . scrollTop ;
}
return y ;
} ;
Startlist . prototype . upDown = function ( ) {
// check whether to sleep
var now = new Date ( ) ;
var now _ms = now . getTime ( ) ;
if ( now _ms < this . sleep _until ) {
// sleep: in this case we do nothing
return ;
}
if ( this . do _rotate ) {
// we scheduled a rotation. Do it and then return.
this . rotateURL ( ) ;
// wait for the page to build
this . sleep _until = now . getTime ( ) + 1000 ;
this . first _run = true ;
this . do _rotate = false ;
// reset scroll_by and scroll_interval, which might have been changed when the windows was resized.
this . scroll _by = 1 ;
this . scroll _interval = 20 ;
//console.log("reset scroll_by to " + this.scroll_by);
return ;
}
// Get current position
var y = 0 ;
var viewHeight = window . innerHeight ;
var pageHeight = document . body . offsetHeight ;
y = this . currentTopPosition ( ) ;
// Do the scrolling
window . scrollBy ( 0 , this . scroll _by * this . scroll _dir ) ;
// Check, if scrolling worked
var new _y = 0 ;
new _y = this . currentTopPosition ( ) ;
if ( y == new _y ) {
this . scroll _by += 1 ;
//console.log("increased scroll_by to " + this.scroll_by);
// reconfigure the scroll interval to maintain a constant speed
this . scroll _interval *= this . scroll _by ;
this . scroll _interval /= this . scroll _by - 1 ;
//console.log("scroll_interval is now " + this.scroll_interval + " ms");
window . clearInterval ( this . scroll _interval _handle ) ;
var list = this ;
this . scroll _interval _handle = window . setInterval ( function ( ) {
list . upDown ( ) ;
} , this . scroll _interval ) ;
}
// Set scrolling and sleeping parameters accordingly
var scrollTopPosition = y ;
var scrollBottomPosition = y + viewHeight ;
//alert("pageYOffset(y)="+pageYOffset+", innerHeight(wy)="+innerHeight+", offsetHeight(dy)="+document.body.offsetHeight);
var do _sleep = 0 ;
if ( pageHeight <= viewHeight ) {
// No scrolling at all
//console.log("Showing whole page");
do _sleep = 2 ;
this . do _rotate = true ;
} else if (
this . scroll _dir != - 1 &&
pageHeight - scrollBottomPosition <= this . margin
) {
// UP
this . scroll _dir = - 1 ;
this . first _run = false ;
do _sleep = 1 ;
} else if ( this . scroll _dir != 1 && scrollTopPosition <= this . margin ) {
// DOWN
this . scroll _dir = 1 ;
if ( ! this . first _run ) {
do _sleep = 1 ;
this . do _rotate = true ;
}
}
// Arm the sleep timer
//if (do_sleep > 0) { console.log("Sleeping for " + do_sleep * this.sleep_for + " seconds"); }
this . sleep _until = now . getTime ( ) + this . sleep _for * 1000 * do _sleep ;
} ;
Startlist . prototype . rotateURL = function ( ) {
var rotate _url _matches = this . json _url . match ( /rotate=([^&]+)/ ) ;
if ( rotate _url _matches ) {
var urls = rotate _url _matches [ 1 ] ;
//console.log(urls);
var current _comp = this . json _url . match ( /comp=([^&]+)/ ) [ 1 ] ;
var current _cat = this . json _url . match ( /cat=([^&]+)/ ) [ 1 ] ;
var current _route = this . json _url . match ( /route=([^&]+)/ ) [ 1 ] ;
//console.log(current_cat);
var next = urls . match (
"(?:^|:|w=" +
current _comp +
",)" +
"c=" +
current _cat +
",r=" +
current _route +
":(?:w=([0-9_a-z]+),)?" +
"c=([0-9_a-z]+),r=(-?[\\d]+)"
) ;
//console.log(next);
if ( ! next ) {
// at the end of the list, take the first argument
next = urls . match (
"^(?:w=([0-9_a-z]+),)?" + "c=([0-9_a-z]+),r=(-?[\\d]+)"
) ;
//console.log("starting over");
//console.log(next);
}
// We might not find a next competition in the rotate parameter
var next _comp = current _comp ;
if ( next [ 1 ] ) {
next _comp = next [ 1 ] ;
}
// Extract category and route
var next _cat = next [ 2 ] ;
var next _route = next [ 3 ] ;
//console.log("current_cat = " + current_cat + ", current_route = " + current_route + ", next_cat = " + next_cat + ", next_route = " + next_route);
this . json _url = this . json _url . replace (
/comp=[0-9_a-z]+/ ,
"comp=" + next _comp
) ;
this . json _url = this . json _url . replace (
/cat=[0-9_a-z]+/ ,
"cat=" + next _cat
) ;
this . json _url = this . json _url . replace (
/route=[\d]+/ ,
"route=" + next _route
) ;
//console.log(this.json_url);
// cancel the currently pending request before starting a new one.
window . clearTimeout ( this . update _handle ) ;
this . update ( ) ;
}
} ;
return Startlist ;
} ) ( ) ;
/ * *
* Resultlist widget inheriting from Startlist
* /
var Resultlist = ( function ( ) {
/ * *
* Constructor for result from given json url
*
* Table get appended to specified _container
*
* @ param _container
* @ param _json _url url for data to load
* @ param { boolean } _no _navigation
* /
function Resultlist ( _container , _json _url , _no _navigation ) {
Startlist . prototype . constructor . call (
this ,
_container ,
_json _url ,
_no _navigation
) ;
}
// inherit from Startlist
Resultlist . prototype = new Startlist ( ) ;
Resultlist . prototype . constructor = Resultlist ;
/ * *
* Callback for loading data via ajax
*
* Reimplemented to use different columns depending on discipline
*
* @ param _data route data object
* /
Resultlist . prototype . handleResponse = function ( _data ) {
var detail = this . json _url . match ( /detail=([^&]+)/ ) ;
switch ( _data . discipline ) {
case "speedrelay" :
this . result _cols = ! detail
? {
// default detail
result _rank : this . lang ( "Rank" ) ,
team _name : this . lang ( "Teamname" ) ,
"athletes/0/lastname" : this . lang ( "Athlete #1" ) ,
"athletes/1/lastname" : this . lang ( "Athlete #2" ) ,
"athletes/2/lastname" : this . lang ( "Athlete #3" ) ,
result : this . lang ( "Sum" ) ,
}
: detail [ 1 ] == "1"
? {
// detail=1
result _rank : this . lang ( "Rank" ) ,
team _name : this . lang ( "Teamname" ) ,
//'team_nation': this.lang('Nation'),
"athletes/0/lastname" : {
label : this . lang ( "Athlete #1" ) ,
colspan : 3 ,
} ,
"athletes/0/firstname" : "" ,
"athletes/0/result_time" : "" ,
"athletes/1/lastname" : {
label : this . lang ( "Athlete #2" ) ,
colspan : 3 ,
} ,
"athletes/1/firstname" : "" ,
"athletes/1/result_time" : "" ,
"athletes/2/lastname" : {
label : this . lang ( "Athlete #3" ) ,
colspan : 3 ,
} ,
"athletes/2/firstname" : "" ,
"athletes/2/result_time" : "" ,
result : this . lang ( "Sum" ) ,
}
: {
// detail=0
result _rank : this . lang ( "Rank" ) ,
team _name : this . lang ( "Teamname" ) ,
team _nation : this . lang ( "Nation" ) ,
result : this . lang ( "Sum" ) ,
} ;
break ;
case "ranking" :
this . result _cols = {
result _rank : this . lang ( "Rank" ) ,
lastname : { label : this . lang ( "Name" ) , colspan : 2 } ,
firstname : "" ,
nation : this . lang ( "Nation" ) ,
points : this . lang ( "Points" ) ,
result : this . lang ( "Result" ) ,
} ;
// default columns for SUI ranking with NO details
if ( ( ! detail || detail [ 1 ] == "0" ) && _data . nation == "SUI" ) {
this . result _cols = {
result _rank : this . lang ( "Rank" ) ,
lastname : { label : this . lang ( "Name" ) , colspan : 2 } ,
firstname : "" ,
birthyear : this . lang ( "Agegroup" ) ,
city : this . lang ( "City" ) ,
federation : "Sektion" ,
rgz : "Regionalzentrum" ,
points : this . lang ( "Points" ) ,
result : this . lang ( "Result" ) ,
} ;
}
if (
( ! detail || detail [ 1 ] == "0" ) &&
_data . participants [ 0 ] &&
_data . participants [ 0 ] . result _rank
) {
delete this . result _cols . result ;
// allow to click on points to show single results
this . result _cols . points = {
label : this . result _cols . points ,
url : location . href + "&detail=1" ,
} ;
// add calculation to see-also links
if ( typeof _data . see _also == "undefined" ) _data . see _also = [ ] ;
_data . see _also . push ( {
name : this . lang ( "calculation of this ranking" ) ,
url : location . href + "&detail=1" ,
} ) ;
}
break ;
default :
// default columns for SUI ranking with NO details
if ( ( ! detail || detail [ 1 ] == "0" ) && _data . nation == "SUI" ) {
this . result _cols = {
result _rank : this . lang ( "Rank" ) ,
lastname : { label : this . lang ( "Name" ) , colspan : 2 } ,
firstname : "" ,
birthyear : this . lang ( "Agegroup" ) ,
city : this . lang ( "City" ) ,
federation : this . lang ( "Sektion" ) ,
rgz : this . lang ( "Regionalzentrum" ) ,
result : this . lang ( "Result" ) ,
} ;
} else {
this . result _cols =
detail && detail [ 1 ] == "0"
? {
result _rank : this . lang ( "Rank" ) ,
lastname : { label : this . lang ( "Name" ) , colspan : 2 } ,
firstname : "" ,
nation : this . lang ( "Nation" ) ,
result : this . lang ( "Result" ) ,
}
2022-11-25 20:57:46 +01:00
: _data . discipline == "speed" && _data . route _order == "0"
? {
result _rank : this . lang ( "Rank" ) ,
lastname : { label : this . lang ( "Name" ) , colspan : 2 } ,
firstname : "" ,
nation : this . lang ( "Nation" ) ,
start _number : this . lang ( "StartNr" ) ,
result : this . lang ( "Result" ) ,
result _l : this . lang ( "Result (A)" ) ,
result _r : this . lang ( "Result (B)" ) ,
}
2022-11-25 20:57:31 +01:00
: {
result _rank : this . lang ( "Rank" ) ,
lastname : { label : this . lang ( "Name" ) , colspan : 2 } ,
firstname : "" ,
nation : this . lang ( "Nation" ) ,
start _number : this . lang ( "StartNr" ) ,
result : this . lang ( "Result" ) ,
} ;
}
// for boulder heats use new display, but not for general result!
if (
_data . discipline . substr ( 0 , 7 ) == "boulder" &&
_data . route _order != - 1
) {
delete this . result _cols . result ;
var that = this ;
var num _problems = parseInt ( _data . route _num _problems ) ;
this . result _cols . boulder = function ( _data , _tag ) {
return that . getBoulderResult . call ( that , _data , _tag , num _problems ) ;
} ;
//Resultlist.prototype.getBoulderResult;
if ( ! detail || detail [ 1 ] != 0 )
this . result _cols . result = this . lang ( "Sum" ) ;
}
break ;
}
// remove start-number column if no start-numbers used (determined on first participant only)
if (
typeof this . result _cols . start _number != "undefined" &&
! _data . participants [ 0 ] . start _number
) {
delete this . result _cols . start _number ;
}
Startlist . prototype . handleResponse . call ( this , _data ) ;
align _td _nbsp ( "table.DrTable td" ) ;
if (
_data . discipline == "ranking" &&
! _data . error &&
( ( detail && detail [ 1 ] == "1" ) || ! _data . participants [ 0 ] . result _rank ) &&
( _data . max _comp || _data . max _disciplines )
) {
var tfoot = jQuery ( document . createElement ( "tfoot" ) ) ;
jQuery ( this . table . dom ) . append ( tfoot ) ;
var th = jQuery ( document . createElement ( "th" ) ) ;
tfoot . append ( jQuery ( document . createElement ( "tr" ) ) . append ( th ) ) ;
var cols = 0 ;
for ( var c in this . result _cols ) cols ++ ;
th . attr ( "colspan" , cols ) ;
th . attr ( "class" , "footer" ) ;
var max _disciplines = "" ;
if ( _data . max _disciplines ) {
for ( var discipline in _data . max _disciplines ) {
max _disciplines +=
( max _disciplines ? ", " : "" ) +
discipline [ 0 ] . toUpperCase ( ) +
discipline . slice ( 1 ) +
": " +
_data . max _disciplines [ discipline ] ;
}
}
if ( _data . nation ) {
th . html (
( _data . max _comp
? "Für " +
( _data . cup ? "den " + _data . cup . name : "die Rangliste" ) +
" zählen die " +
_data . max _comp +
" besten Ergebnisse. "
: "" ) +
( max _disciplines
? " Maximal zählende Ergebnisse pro Disziplin: " +
max _disciplines +
". "
: "" ) +
"Nicht zählende Ergebnisse sind eingeklammert. " +
( _data . min _disciplines
? "<br/>Teilnahme an mindestens " +
_data . min _disciplines +
" Disziplinen ist erforderlich. "
: "" ) +
( _data . drop _equally
? "Streichresultate erfolgen in allen Disziplinen gleichmäßig. "
: "" )
) ;
} else {
th . html (
( _data . max _comp
? _data . max _comp +
" best competition results are counting for " +
( _data . cup ? _data . cup . name : "the ranking" ) +
". "
: "" ) +
( max _disciplines
? "Maximum number of counting results per discipline: " +
max _disciplines +
". "
: "" ) +
"Not counting points are in brackets. " +
( _data . min _disciplines
? "<br/>Participation in at least " +
_data . min _disciplines +
" disciplines is required."
: "" ) +
( _data . drop _equally
? "Not counting results are selected from all disciplines equally."
: "" )
) ;
}
}
if (
_data . statistics &&
( _data . discipline == "selfscore" || this . json _url . match ( "&stats=" ) )
) {
if ( ! jQuery ( "#jqplot-css" ) . length ) {
var ranking _url = this . json _url . replace ( /json.php.*$/ , "" ) ;
var jqplot _url =
this . json _url . replace ( /ranking\/json.php.*$/ , "" ) +
"vendor/npm-asset/as-jqplot/dist/" ;
jQuery ( "<link/>" , {
id : "jqplot-css" ,
href : jqplot _url + "jquery.jqplot.min.css" ,
type : "text/css" ,
} ) . appendTo ( "head" ) ;
var load = [
jqplot _url + "jquery.jqplot.min.js" ,
// not sure why bar-renderer does not work :(
//jqplot_url+'plugins/jqplot.barRenderer.min.js',
jqplot _url + "plugins/jqplot.highlighter.min.js" ,
ranking _url + "js/dr_statistics.js?" + _data . dr _statistics ,
] ;
for ( var i = 0 ; i < load . length ; ++ i ) {
load [ i ] = jQuery . ajax ( {
url : load [ i ] ,
dataType : "script" ,
cache : true , // no cache buster!
} ) ;
}
var container = this . container ;
jQuery . when . apply ( jQuery , load ) . done ( function ( ) {
dr _statistics ( container , _data ) ;
} ) ;
// dono why, but above done is not always executed, if files are already cached
window . setTimeout ( function ( ) {
typeof window . dr _statistics != "undefined" &&
dr _statistics ( container , _data ) ;
} , 100 ) ;
} else {
dr _statistics ( this . container , _data ) ;
}
}
} ;
/ * *
* Get DOM nodes for display of graphical boulder - result
*
* @ param _data
* @ param _tag 'th' for header , 'td' for data rows
* @ param _num _problems
* @ return DOM node
* /
Resultlist . prototype . getBoulderResult = function (
_data ,
_tag ,
_num _problems
) {
if ( _tag == "th" ) return "Result" ;
var tag = document . createElement ( "div" ) ;
for ( var i = 1 ; i <= _num _problems ; ++ i ) {
var boulder = document . createElement ( "div" ) ;
var result = _data [ "boulder" + i ] ;
if ( result && result != "z0" && result != "b0" ) {
var top _tries = result . match ( /t([0-9]+)/ ) ;
var bonus _tries = result . match ( /(b|z)([0-9]+)/ ) ;
if ( top _tries ) {
boulder . className = "boulderTop" ;
var top _text = document . createElement ( "div" ) ;
top _text . className = "topTries" ;
jQuery ( top _text ) . text ( top _tries [ 1 ] ) ;
jQuery ( boulder ) . append ( top _text ) ;
} else {
boulder . className = "boulderBonus" ;
}
var bonus _text = document . createElement ( "div" ) ;
bonus _text . className = "bonusTries" ;
jQuery ( bonus _text ) . text ( bonus _tries [ 2 ] ) ;
jQuery ( boulder ) . append ( bonus _text ) ;
} else {
boulder . className = result ? "boulderNone" : "boulder" ;
}
jQuery ( tag ) . append ( boulder ) ;
}
return tag ;
} ;
return Resultlist ;
} ) ( ) ;
/ * *
* Results widget inheriting from DrBaseWidget
* /
var Results = ( function ( ) {
/ * *
* Constructor for results from given json url
*
* Table get appended to specified _container
*
* @ param _container
* @ param _json _url url for data to load
* @ param { boolean } _no _navigation do not show competition chooser
* /
function Results ( _container , _json _url , _no _navigation ) {
DrBaseWidget . prototype . constructor . call ( this , _container , _json _url ) ;
this . no _navigation = _no _navigation ;
this . update ( ) ;
}
// inherite from DrBaseWidget
Results . prototype = new DrBaseWidget ( ) ;
Results . prototype . constructor = Results ;
/ * *
* Callback for loading data via ajax
*
* @ param _data route data object
* /
Results . prototype . handleResponse = function ( _data ) {
this . columns = {
result _rank : this . lang ( "Rank" ) ,
lastname : { label : this . lang ( "Name" ) , colspan : 2 } ,
firstname : "" ,
nation : this . lang ( "Nation" ) ,
} ;
this . replace _nation ( _data . display _athlete , _data . nation ) ;
if ( typeof this . table == "undefined" ) {
// competition chooser
if ( ! this . no _navigation ) {
this . comp _chooser = jQuery ( document . createElement ( "select" ) ) ;
this . comp _chooser . addClass ( "compChooser" ) ;
this . container . append ( this . comp _chooser ) ;
var that = this ;
this . comp _chooser . change ( function ( e ) {
that . json _url = that . json _url . replace (
/comp=[^&]+/ ,
"comp=" + this . value
) ;
if ( that . navigateTo ) that . navigateTo ( that . json _url ) ;
else that . update ( ) ;
} ) ;
}
// competition
this . comp _header = jQuery ( document . createElement ( "h1" ) ) ;
this . comp _header . addClass ( "compHeader" ) ;
this . container . append ( this . comp _header ) ;
// result date
this . comp _date = jQuery ( document . createElement ( "h3" ) ) ;
this . comp _date . addClass ( "resultDate" ) ;
this . container . append ( this . comp _date ) ;
} else {
jQuery ( this . table . dom ) . remove ( ) ;
if ( ! this . no _navigation ) this . comp _chooser . empty ( ) ;
this . comp _header . empty ( ) ;
this . comp _date . empty ( ) ;
}
// fill competition chooser
if ( ! this . no _navigation ) {
var option = jQuery ( document . createElement ( "option" ) ) ;
option . text ( this . lang ( "Select another competition ..." ) ) ;
this . comp _chooser . append ( option ) ;
for ( var i = 0 ; i < _data . competitions . length ; ++ i ) {
var competition = _data . competitions [ i ] ;
if ( _data . WetId == competition . WetId ) continue ; // we dont show current competition
option = jQuery ( document . createElement ( "option" ) ) ;
option . attr ( { value : competition . WetId , title : competition . date _span } ) ;
option . text ( competition . name ) ;
this . comp _chooser . append ( option ) ;
}
}
this . comp _header . text ( _data . name ) ;
this . comp _date . text ( _data . date _span ) ;
for ( var i = 0 ; i < _data . categorys . length ; ++ i ) {
var cat = _data . categorys [ i ] ;
var that = this ;
cat . click = function ( e ) {
that . showCompleteResult ( e ) ;
} ;
}
// create new table
this . table = new DrTable (
_data . categorys ,
this . columns ,
"result_rank" ,
true ,
null ,
this . navigateTo
) ;
this . container . append ( this . table . dom ) ;
this . seeAlso ( _data . see _also ) ;
} ;
/ * *
* Switch from Results ( of all categories ) to Resultlist ( of a single category )
*
* @ param e
* /
Results . prototype . showCompleteResult = function ( e ) {
this . container . empty ( ) ;
this . container . removeClass ( "Results" ) ;
new Resultlist (
this . container ,
this . json _url . replace ( /\?.*$/ , e . target . href . match ( /\?.*$/ ) [ 0 ] )
) ;
e . preventDefault ( ) ;
} ;
return Results ;
} ) ( ) ;
/ * *
* Starters / registration widget inheriting from DrBaseWidget
* /
var Starters = ( function ( ) {
/ * *
* Constructor for results from given json url
*
* Table get appended to specified _container
*
* @ param _container
* @ param _json _url url for data to load
* /
function Starters ( _container , _json _url ) {
DrBaseWidget . prototype . constructor . call ( this , _container , _json _url ) ;
this . update ( ) ;
}
// inherite from DrBaseWidget
Starters . prototype = new DrBaseWidget ( ) ;
Starters . prototype . constructor = Starters ;
/ * *
* Callback for loading data via ajax
*
* @ param _data route data object
* /
Starters . prototype . handleResponse = function ( _data ) {
this . data = _data ;
if ( typeof this . table == "undefined" ) {
// competition
this . comp _header = jQuery ( document . createElement ( "h1" ) ) ;
this . comp _header . addClass ( "compHeader" ) ;
this . container . append ( this . comp _header ) ;
// result date
this . comp _date = jQuery ( document . createElement ( "h3" ) ) ;
this . comp _date . addClass ( "resultDate" ) ;
this . container . append ( this . comp _date ) ;
} else {
delete this . table ;
this . comp _header . empty ( ) ;
this . comp _date . empty ( ) ;
}
this . comp _header . text ( _data . name + " : " + _data . date _span ) ;
if ( _data . deadline )
this . comp _date . text ( this . lang ( "Deadline" ) + ": " + _data . deadline ) ;
this . table = jQuery ( document . createElement ( "table" ) ) . addClass ( "DrTable" ) ;
this . container . append ( this . table ) ;
var thead = jQuery ( document . createElement ( "thead" ) ) ;
this . table . append ( thead ) ;
// create header row
var row = jQuery ( document . createElement ( "tr" ) ) ;
var th = jQuery ( document . createElement ( "th" ) ) ;
th . text (
typeof _data . federations != "undefined"
? this . lang ( "Federation" )
: this . lang ( "Nation" )
) ;
if ( ! this . json _url . match ( /no_fed=1/ ) ) row . append ( th ) ;
var cats = { } ;
for ( var i = 0 ; i < _data . categorys . length ; ++ i ) {
var th = jQuery ( document . createElement ( "th" ) ) ;
th . addClass ( "category" ) ;
th . text ( _data . categorys [ i ] . name ) ;
row . append ( th ) ;
cats [ _data . categorys [ i ] . GrpId ] = i ;
}
thead . append ( row ) ;
var tbody = jQuery ( document . createElement ( "tbody" ) ) ;
this . table . append ( tbody ) ;
var fed ;
this . fed _rows = [ ] ;
this . fed _rows _pos = [ ] ;
var num _competitors = 0 ;
for ( var i = 0 ; i < _data . athletes . length ; ++ i ) {
var athlete = _data . athletes [ i ] ;
// evtl. create new row for federation/nation
if (
( typeof fed == "undefined" || fed != athlete . reg _fed _id ) &&
! this . json _url . match ( /no_fed=1/ )
) {
this . fillUpFedRows ( ) ;
// reset fed rows to empty
this . fed _rows = [ ] ;
this . fed _rows _pos = [ ] ;
}
// find rows with space in column of category
var cat _col = cats [ athlete . cat ] ;
for ( var r = 0 ; r < this . fed _rows . length ; ++ r ) {
if ( this . fed _rows _pos [ r ] <= cat _col ) break ;
}
if ( r == this . fed _rows . length ) {
// create a new fed-row
row = jQuery ( document . createElement ( "tr" ) ) ;
tbody . append ( row ) ;
th = jQuery ( document . createElement ( "th" ) ) ;
if ( ! this . json _url . match ( /no_fed=1/ ) ) row . append ( th ) ;
this . fed _rows . push ( row ) ;
this . fed _rows _pos . push ( 0 ) ;
if ( typeof fed == "undefined" || fed != athlete . reg _fed _id ) {
fed = athlete . reg _fed _id ;
th . text ( this . federation ( athlete . reg _fed _id ) ) ;
th . addClass ( "federation" ) ;
}
}
this . fillUpFedRow ( r , cat _col ) ;
// create athlete cell
var td = jQuery ( document . createElement ( "td" ) ) ;
td . addClass ( "athlete" ) ;
var lastname = jQuery ( document . createElement ( "span" ) )
. addClass ( "lastname" )
. text ( athlete . lastname ) ;
var firstname = jQuery ( document . createElement ( "span" ) )
. addClass ( "firstname" )
. text ( athlete . firstname ) ;
td . append ( lastname ) . append ( firstname ) ;
this . fed _rows [ r ] . append ( td ) ;
this . fed _rows _pos [ r ] ++ ;
// do not count
if ( athlete . cat != 120 ) num _competitors ++ ;
}
this . fillUpFedRows ( ) ;
var tfoot = jQuery ( document . createElement ( "tfoot" ) ) ;
this . table . append ( tfoot ) ;
var th = jQuery ( document . createElement ( "th" ) ) ;
tfoot . append ( jQuery ( document . createElement ( "tr" ) ) . append ( th ) ) ;
th . attr ( "colspan" , 1 + _data . categorys . length ) ;
th . text (
this . lang (
"Total of %1 athletes registered in all categories." ,
num _competitors
)
) ;
} ;
/ * *
* Fill a single fed - row up to a given position with empty td ' s
*
* @ param { number } _r row - number
* @ param { number } _to column - number , default whole row
* /
Starters . prototype . fillUpFedRow = function ( _r , _to ) {
if ( typeof _to == "undefined" ) _to = this . data . categorys . length ;
while ( this . fed _rows _pos [ _r ] < _to ) {
var td = jQuery ( document . createElement ( "td" ) ) ;
this . fed _rows [ _r ] . append ( td ) ;
this . fed _rows _pos [ _r ] ++ ;
}
} ;
/ * *
* Fill up all fed rows with empty td ' s
* /
Starters . prototype . fillUpFedRows = function ( ) {
for ( var r = 0 ; r < this . fed _rows . length ; ++ r ) {
this . fillUpFedRow ( r ) ;
}
} ;
/ * *
* Get name of federation specified by given id
*
* @ param _fed _id
* @ returns string with name
* /
Starters . prototype . federation = function ( _fed _id ) {
if ( typeof this . data . federations == "undefined" ) {
return _fed _id ; // nation of int. competition
}
for ( var i = 0 ; i < this . data . federations . length ; ++ i ) {
var fed = this . data . federations [ i ] ;
if ( fed . fed _id == _fed _id ) return fed . shortcut || fed . name ;
}
} ;
return Starters ;
} ) ( ) ;
/ * *
* Profile widget inheriting from DrBaseWidget
* /
var Profile = ( function ( ) {
/ * *
* Constructor for profile from given json url
*
* Table get appended to specified _container
*
* @ param _container
* @ param _json _url url for data to load
* @ param _template optional string with html - template
* @ param _remove _leading _slash fix Joomla behavior of adding a slash to < a href = "$$something$$"
* /
function Profile ( _container , _json _url , _template , _remove _leading _slash ) {
DrBaseWidget . prototype . constructor . call ( this , _container , _json _url ) ;
if ( _template ) this . template = _template ;
if ( typeof _remove _leading _slash == "undefined" )
_remove _leading _slash = false ;
this . pattern = new RegExp (
( _remove _leading _slash ? "/?" : "" ) + "\\$\\$([^$]+)\\$\\$" ,
"g"
) ;
this . pattern _results = new RegExp (
( _remove _leading _slash ? "/?" : "" ) + "\\$\\$results/N/([^$]+)\\$\\$" ,
"g"
) ;
this . container . empty ( ) ;
this . bestResults = 12 ;
this . update ( ) ;
}
// inherite from DrBaseWidget
Profile . prototype = new DrBaseWidget ( ) ;
Profile . prototype . constructor = Profile ;
/ * *
* Callback for loading data via ajax
*
* @ param _data route data object
* /
Profile . prototype . handleResponse = function ( _data ) {
if ( _data . error ) {
var error = jQuery ( document . createElement ( "h3" ) ) ;
error . addClass ( "error" ) ;
error . text ( _data . error ) ;
this . container . replaceWith ( error ) ;
return ;
}
// replace non-result data
var that = this ;
var html = this . template . replace (
this . pattern ,
function ( match , placeholder ) {
switch ( placeholder ) {
case "categoryChooser" :
var select = '<select class="chooseCategory">\n' ;
if ( typeof _data . categorys === "undefined" ) {
return "" ;
}
for ( var i = 0 ; i < _data . categorys . length ; ++ i ) {
var cat = _data . categorys [ i ] ;
select +=
'<option value="' +
cat . GrpId +
'"' +
( cat . GrpId == _data . GrpId ? " selected" : "" ) +
">" +
cat . name +
"</option>\n" ;
}
select += "</select>\n" ;
return select ;
}
var parts = placeholder . split ( "/" ) ;
var data = _data ;
for ( var i = 0 ; i < parts . length ; ++ i ) {
if ( typeof data [ parts [ i ] ] == "undefined" || ! data [ parts [ i ] ] ) {
return parts [ i ] === "N" ? match : "" ;
}
data = data [ parts [ i ] ] ;
}
switch ( placeholder ) {
case "practice" :
data +=
" " +
that . lang ( "years, since" ) +
" " +
( new Date ( ) . getFullYear ( ) - data ) ;
break ;
case "height" :
data += " cm" ;
break ;
case "weight" :
data += " kg" ;
break ;
}
return data ;
}
) ;
// replace result data
var bestResults = this . bestResults ;
var that = this ;
html = html . replace ( /[\s]*<tr[\s\S]*?<\/tr>\n?/g , function ( match ) {
if ( match . indexOf ( "$$results/N/" ) == - 1 ) return match ;
// find and mark N best results
var year = new Date ( ) . getFullYear ( ) ;
var limits = [ ] ;
for ( var i = 0 ; i < _data . results . length ; ++ i ) {
var result = _data . results [ i ] ;
result . weight =
result . rank / 2 + ( year - parseInt ( result . date ) ) + 4 * ! result . nation ;
// maintain array of N best competitions (least weight)
if (
limits . length < bestResults ||
result . weight < limits [ limits . length - 1 ]
) {
var limit = 0 ;
for ( var l = 0 ; l < limits . length ; ++ l ) {
limit = limits [ l ] ;
if ( limit > result . weight ) break ;
}
if ( limit < result . weight && l == limits . length - 1 )
l = limits . length ;
limits = limits
. slice ( 0 , l )
. concat ( [ result . weight ] )
. concat ( limits . slice ( l , bestResults - 1 - l ) ) ;
}
}
var weight _limit = limits . pop ( ) ;
var rows = "" ;
var l = 0 ;
for ( var i = 0 ; i < _data . results . length ; ++ i ) {
var result = _data . results [ i ] ;
if (
match . indexOf ( "$$results/N/weightClass$$" ) >= 0 &&
( result . weight > weight _limit || ++ l > bestResults )
) {
result . weightClass = "profileResultHidden" ;
}
rows += match . replace (
that . pattern _results ,
function ( match , placeholder ) {
switch ( placeholder ) {
case "cat_name+name" :
return (
( result . GrpId != _data . GrpId ? result . cat _name + ": " : "" ) +
result . name
) ;
case "date" :
return that . formatDate ( result . date ) ;
default :
return typeof result [ placeholder ] != "undefined"
? result [ placeholder ]
: "" ;
}
}
) ;
}
return rows ;
} ) ;
this . container . html ( html ) ;
// remove links with empty href
this . container . find ( 'a[href=""]' ) . replaceWith ( function ( ) {
return jQuery ( this ) . contents ( ) ;
} ) ;
// remove images with empty src
this . container . find ( 'img[src=""]' ) . remove ( ) ;
// hide rows with profileHideRowIfEmpty, if ALL td.profileHideRowIfEmpty are empty
this . container . find ( "tr.profileHideRowIfEmpty" ) . each ( function ( index , row ) {
var tds = jQuery ( row ) . children ( "td.profileHideRowIfEmpty" ) ;
if ( tds . length == tds . filter ( ":empty" ) . length ) {
jQuery ( row ) . hide ( ) ;
}
} ) ;
// install click handler from DrWidget
if ( this . navigateTo )
this . container
. find ( '.profileData a:not(a[href^="javascript:"])' )
. click ( this . navigateTo ) ;
// bind chooseCategory handler (works with multiple templates)
var that = this ;
this . container . find ( "select.chooseCategory" ) . change ( function ( e ) {
that . chooseCategory . call ( that , this . value ) ;
e . stopImmediatePropagation ( ) ;
return false ;
} ) ;
} ;
/ * *
* toggle between best results and all results
* /
Profile . prototype . toggleResults = function ( ) {
var hidden _rows = this . container . find ( "tr.profileResultHidden" ) ;
var display = hidden _rows . length
? jQuery ( hidden _rows [ 0 ] ) . css ( "display" )
: "none" ;
hidden _rows . css ( "display" , display == "none" ? "table-row" : "none" ) ;
} ;
/ * *
* choose a given category for rankings
*
* @ param { string } GrpId
* /
Profile . prototype . chooseCategory = function ( GrpId ) {
var cat _regexp = /([#&])cat=([^&]+)/ ;
function replace _cat ( str , GrpId ) {
if ( str . match ( cat _regexp ) ) {
return str . replace ( cat _regexp , "$1cat=" + GrpId ) ;
}
return str + "&cat=" + GrpId ;
}
location . hash = replace _cat ( location . hash , GrpId ) ;
this . json _url = replace _cat ( this . json _url , GrpId ) ;
this . update ( ) ;
} ;
/ * *
* Default template for Profile widget
* /
Profile . prototype . template =
"<div>\n" +
'<table class="profileHeader">\n' +
" <thead>\n" +
" <tr>\n" +
' <td class="profilePhoto"><img src="$$photo$$" border="0"></td>\n' +
" <td>\n" +
' <h1><a href="$$homepage$$" target="_blank">\n' +
' <span class="firstname">$$firstname$$</span>\n' +
' <span class="lastname">$$lastname$$</span>\n' +
" </a></h1>\n" +
' <h2 class="profileNation">$$nation$$</h1>\n' +
' <h3 class="profileFederation"><a href="$$fed_url$$" target="_blank">$$federation$$</a></h1>\n' +
" </td>\n" +
' <td class="profileLogo"><a href="http://www.digitalROCK.de" target=_blank><img src="http://www.digitalrock.de/dig_rock-155x100.png" title="digital ROCK\'s Homepage" /></a></td>\n' +
" </tr>\n" +
" </thead>\n" +
"</table>\n" +
'<table cols="6" class="profileData">\n' +
" <thead>\n" +
" <tr>\n" +
" <td>age:</td>\n" +
' <td class="profileAge">$$age$$</td>\n' +
" <td>year of birth:</td>\n" +
' <td colspan="3" class="profileBirthdate">$$birthdate$$</td>\n' +
" </tr>\n" +
' <tr class="profileHideRowIfEmpty">\n' +
' <td colspan="2"></td>\n' +
" <td>place of birth:</td>\n" +
' <td colspan="3" class="profileBirthplace profileHideRowIfEmpty">$$birthplace$$</td>\n' +
" </tr>\n" +
' <tr class="profileHideRowIfEmpty">\n' +
" <td>height:</td>\n" +
' <td class="profileHeight profileHideRowIfEmpty">$$height$$</td>\n' +
" <td>weight:</td>\n" +
' <td colspan="3" class="profileWeight profileHideRowIfEmpty">$$weight$$</td>\n' +
" </tr>\n" +
' <tr class="profileMarginTop profileHideRowIfEmpty">\n' +
" <td>address:</td>\n" +
' <td colspan="2" class="profileCity profileHideRowIfEmpty">$$postcode$$ $$city$$</td>\n' +
' <td colspan="3" class="profileStreet profileHideRowIfEmpty">$$street$$</td>\n' +
" </tr>\n" +
' <tr class="profileMarginTop profileHideRowIfEmpty">\n' +
' <td colspan="2">practicing climbing for:</td>\n' +
' <td colspan="4" class="profilePractice profileHideRowIfEmpty">$$practice$$</td>\n' +
" </tr>\n" +
' <tr class="profileHideRowIfEmpty">\n' +
' <td colspan="2">professional climber (if not, profession):</td>\n' +
' <td colspan="4" class="profileProfessional profileHideRowIfEmpty">$$professional$$</td>\n' +
" </tr>\n" +
' <tr class="profileHideRowIfEmpty">\n' +
' <td colspan="2">other sports practiced:</td>\n' +
' <td colspan="4" class="profileOtherSports profileHideRowIfEmpty">$$other_sports$$</td>\n' +
" </tr>\n" +
' <tr class="profileMarginTop profileHideRowIfEmpty">\n' +
' <td colspan="6" class="profileFreetext profileHideRowIfEmpty">$$freetext$$</td>\n' +
" </tr>\n" +
' <tr class="profileMarginTop">\n' +
' <td colspan="6">Category: $$categoryChooser$$</td>\n' +
" </tr>\n" +
" <tr>\n" +
' <td colspan="2" class="profileRanglist"><a href="$$rankings/0/url$$">$$rankings/0/name$$</a>:</td>\n' +
' <td class="profileRank">$$rankings/0/rank$$</td>\n' +
' <td colspan="2" class="profileRanglist"><a href="$$rankings/1/url$$">$$rankings/1/name$$</a>:</td>\n' +
' <td class="profileRank">$$rankings/1/rank$$</td>\n' +
" </tr>\n" +
" <tr>\n" +
' <td colspan="2" class="profileRanglist"><a href="$$rankings/2/url$$">$$rankings/2/name$$</a>:</td>\n' +
' <td class="profileRank">$$rankings/2/rank$$</td>\n' +
' <td colspan="2" class="profileRanglist"><a href="$$rankings/3/url$$">$$rankings/3/name$$</a>:</td>\n' +
' <td class="profileRank">$$rankings/3/rank$$</td>\n' +
" </tr>\n" +
' <tr class="profileResultHeader profileMarginTop">\n' +
' <td colspan="6"><a href="javascript:widget.widget.toggleResults()" title="click to toggle between best results and all results">best results / all results:</a></td>\n' +
" </tr>\n" +
" </thead>\n" +
" <tbody>\n" +
' <tr class="profileResult $$results/N/weightClass$$">\n' +
' <td class="profileResultRank">$$results/N/rank$$</td>\n' +
' <td colspan="4" class="profileResultName"><a href="$$results/N/url$$">$$results/N/cat_name+name$$</a></td>\n' +
' <td class="profileResultDate">$$results/N/date$$</td>\n' +
" </tr>\n" +
" </tbody>\n" +
"</table>\n" +
"</div>\n" ;
return Profile ;
} ) ( ) ;
/ * *
* ResultTemplate widget inheriting from DrBaseWidget
* /
var ResultTemplate = ( function ( ) {
/ * *
* Constructor for ResultTemplate from given json url
*
* Table get appended to specified _container
*
* @ param _container
* @ param _json _url url for data to load
* @ param _template optional string with html - template
* /
function ResultTemplate ( _container , _json _url , _template ) {
DrBaseWidget . prototype . constructor . call ( this , _container , _json _url ) ;
if ( _template ) this . template = _template ;
else this . template = this . container . html ( ) ;
this . container . empty ( ) ;
this . update ( ) ;
}
// inherite from DrBaseWidget
ResultTemplate . prototype = new DrBaseWidget ( ) ;
ResultTemplate . prototype . constructor = ResultTemplate ;
/ * *
* Callback for loading data via ajax
*
* @ param _data route data object
* /
ResultTemplate . prototype . handleResponse = function ( _data ) {
// if route is NOT offical, update list every 10 sec
if ( ! _data . route _result && typeof this . update _handle == "undefined" ) {
var list = this ;
this . update _handle = window . setInterval ( function ( ) {
list . update ( ) ;
} , 10000 ) ;
}
// if route is offical stop reload
else if ( _data . route _result && this . update _handle ) {
window . clearInterval ( this . update _handle ) ;
delete this . update _handle ;
}
// replace non-result data
var pattern = /\$\$([^$]+)\$\$/g ;
var html = this . template . replace ( pattern , function ( match , placeholder ) {
var parts = placeholder . split ( "/" ) ;
var data = _data ;
for ( var i = 0 ; i < parts . length ; ++ i ) {
if ( typeof data [ parts [ i ] ] == "undefined" || ! data [ parts [ i ] ] ) {
return parts [ i ] === "N" ? match : "" ;
}
data = data [ parts [ i ] ] ;
}
switch ( placeholder ) {
}
return data ;
} ) ;
// replace result data
pattern = /\$\$participants\/N\/([^$]+)\$\$/g ;
html = html . replace ( /[\s]*<tr[\s\S]*?<\/tr>\n?/g , function ( match ) {
if ( match . indexOf ( "$$participants/N/" ) == - 1 ) return match ;
var rows = "" ;
for ( var i = 0 ; i < _data . participants . length ; ++ i ) {
var result = _data . participants [ i ] ;
rows += match . replace ( pattern , function ( match , placeholder ) {
switch ( placeholder ) {
default :
return typeof result [ placeholder ] != "undefined"
? result [ placeholder ]
: "" ;
}
} ) ;
}
return rows ;
} ) ;
// replace container
this . container . html ( html ) ;
} ;
return ResultTemplate ;
} ) ( ) ;
/ * *
* Competitions / calendar widget inheriting from DrBaseWidget
* /
var Competitions = ( function ( ) {
/ * *
* Constructor for ompetitions / calendar from given json url
*
* Table get appended to specified _container
*
* @ param _container
* @ param _json _url url for data to load
* @ param _filters object with filters and optional _comp _url
* { string } _filters . _comp _url url to use as link with added WetId for competition name
* /
function Competitions ( _container , _json _url , _filters ) {
DrBaseWidget . prototype . constructor . call ( this , _container , _json _url ) ;
if ( typeof _filters != "undefined" ) {
this . filters = _filters ;
if ( typeof _filters . _comp _url != "undefined" ) {
this . comp _url = _filters . _comp _url ;
delete this . filters . _comp _url ;
}
if ( typeof _filters . _comp _url _label != "undefined" ) {
this . comp _url _label = _filters . _comp _url _label ;
delete this . filters . _comp _url _label ;
}
}
this . year _regexp = /([&?])year=(\d+)/ ;
this . update ( ) ;
}
// inherite from DrBaseWidget
Competitions . prototype = new DrBaseWidget ( ) ;
Competitions . prototype . constructor = Competitions ;
/ * *
* Callback for loading data via ajax
*
* @ param _data route data object
* /
Competitions . prototype . handleResponse = function ( _data ) {
this . container . empty ( ) ;
var year = this . json _url . match ( this . year _regexp ) ;
year = year ? parseInt ( year [ 2 ] ) : new Date ( ) . getFullYear ( ) ;
var h1 = jQuery ( document . createElement ( "h1" ) ) . text (
this . lang ( "Calendar" ) + " " + year
) ;
this . container . append ( h1 ) ;
var filter = jQuery ( document . createElement ( "div" ) ) . addClass ( "filter" ) ;
var select = jQuery ( document . createElement ( "select" ) ) . attr ( "name" , "year" ) ;
var years = _data . years || [ year + 1 , year , year - 1 ] ;
for ( var i = 0 ; i < years . length ; ++ i ) {
var y = years [ i ] ;
var option = jQuery ( document . createElement ( "option" ) ) . attr ( "value" , y ) ;
option . text ( y ) ;
if ( year == y ) option . attr ( "selected" , "selected" ) ;
select . append ( option ) ;
}
var that = this ;
select . change ( function ( e ) {
that . changeYear ( this . value ) ;
} ) ;
select . attr ( "style" , "margin-right: 5px" ) ;
filter . append ( select ) ;
if (
typeof this . filters != "undefied" &&
! jQuery . isEmptyObject ( this . filters )
) {
select = jQuery ( document . createElement ( "select" ) ) . attr ( "name" , "filter" ) ;
for ( var f in this . filters ) {
var option = jQuery ( document . createElement ( "option" ) ) . attr (
"value" ,
this . filters [ f ]
) ;
option . text ( f ) ;
if ( decodeURI ( this . json _url ) . indexOf ( this . filters [ f ] ) != - 1 )
option . attr ( "selected" , "selected" ) ;
select . append ( option ) ;
}
select . change ( function ( e ) {
that . changeFilter ( this . value ) ;
} ) ;
filter . append ( select ) ;
}
this . container . append ( filter ) ;
var competitions = jQuery ( document . createElement ( "div" ) ) . addClass (
"competitions"
) ;
this . container . append ( competitions ) ;
var now = new Date ( ) ;
// until incl. Wednesday (=3) we display competitions from last week first, after that from this week
var week _to _display = now . getWeek ( ) - ( now . getDay ( ) <= 3 ? 1 : 0 ) ;
var closest , closest _dist ;
for ( var i = 0 ; i < _data . competitions . length ; ++ i ) {
var competition = _data . competitions [ i ] ;
var comp _div = jQuery ( document . createElement ( "div" ) ) . addClass (
"competition"
) ;
var title = jQuery ( document . createElement ( "div" ) )
. addClass ( "title" )
. text ( competition . name ) ;
if ( this . comp _url ) {
title = jQuery ( document . createElement ( "a" ) )
. attr ( { href : this . comp _url + competition . WetId } )
. append ( title ) ;
}
comp _div . append ( title ) ;
comp _div . append (
jQuery ( document . createElement ( "div" ) )
. addClass ( "date" )
. text ( competition . date _span )
) ;
var cats _ul = jQuery ( document . createElement ( "ul" ) ) . addClass ( "cats" ) ;
var have _cats = false ;
var links = {
homepage : this . lang ( "Event Website" ) ,
info : this . lang ( "Regulation" ) ,
info2 : this . lang ( "Info Sheet" ) ,
startlist : this . lang ( "Startlist" ) ,
result : this . lang ( "Result" ) ,
} ;
// add comp_url as first link with given label
if ( this . comp _url && this . comp _url _label ) {
links = jQuery . extend ( { comp _url : this . comp _url _label } , links ) ;
competition . comp _url = this . comp _url + competition . WetId ;
}
if ( typeof competition . cats == "undefined" ) competition . cats = [ ] ;
for ( var c = 0 ; c < competition . cats . length ; ++ c ) {
var cat = competition . cats [ c ] ;
var url = "" ;
if ( typeof cat . status != "undefined" ) {
switch ( cat . status ) {
case 4 : // registration
links . starters = this . lang ( "Starters" ) ;
competition . starters =
"#!type=starters&comp=" + competition . WetId ;
break ;
case 2 : // startlist in result-service
case 1 : // result in result-service
case 0 : // result in ranking (ToDo: need extra export, as it might not be in result-service)
url = "#!comp=" + competition . WetId + "&cat=" + cat . GrpId ;
break ;
}
}
var cat _li = jQuery ( document . createElement ( "li" ) ) ;
if ( url != "" ) {
var a = jQuery ( document . createElement ( "a" ) ) . attr ( "href" , url ) ;
a . text ( cat . name ) ;
if ( this . navigateTo ) a . click ( this . navigateTo ) ;
cat _li . append ( a ) ;
} else {
cat _li . text ( cat . name ) ;
}
cats _ul . append ( cat _li ) ;
have _cats = true ;
}
var links _ul = jQuery ( document . createElement ( "ul" ) ) . addClass ( "links" ) ;
var have _links = false ;
for ( var l in links ) {
if ( typeof competition [ l ] == "undefined" || competition [ l ] === null )
continue ;
var a = jQuery ( document . createElement ( "a" ) ) ;
a . attr ( "href" , competition [ l ] ) ;
if ( l == "comp_url" && this . comp _url [ 0 ] == "/" ) ;
else if ( l != "starters" ) a . attr ( "target" , "_blank" ) ;
else if ( this . navigateTo ) a . click ( this . navigateTo ) ;
a . text ( links [ l ] ) ;
links _ul . append (
jQuery ( document . createElement ( "li" ) )
. addClass ( l + "Link" )
. append ( a )
) ;
have _links = true ;
}
if ( have _links ) comp _div . append ( links _ul ) ;
if ( have _cats ) comp _div . append ( cats _ul ) ;
competitions . append ( comp _div ) ;
var dist = Math . abs (
new Date ( competition . date ) . getWeek ( ) - week _to _display
) ;
if ( typeof closest _dist == "undefined" || dist < closest _dist ) {
closest _dist = dist ;
closest = comp _div [ 0 ] ;
}
}
if ( closest && year == new Date ( ) . getFullYear ( ) ) {
// need to delay scrolling a bit, layout seems to need some time
window . setTimeout ( function ( ) {
closest . parentElement . scrollTop =
closest . offsetTop + closest . parentElement . offsetTop ;
} , 100 ) ;
}
} ;
Competitions . prototype . changeYear = function ( year ) {
if ( this . json _url . match ( this . year _regexp ) ) {
this . json _url = this . json _url . replace ( this . year _regexp , "$1year=" + year ) ;
} else {
if ( this . json _url . substr ( - 1 ) != "?" )
this . json _url += this . json _url . indexOf ( "?" ) == - 1 ? "?" : "&" ;
this . json _url += "year=" + year ;
}
if ( this . navigateTo ) {
this . navigateTo ( this . json _url ) ;
} else {
this . update ( ) ;
}
} ;
Competitions . prototype . changeFilter = function ( filter ) {
if ( this . json _url . indexOf ( "?" ) == - 1 ) {
this . json _url += "?" + filter ;
} else {
var year = this . json _url . match ( this . year _regexp ) ;
this . json _url = this . json _url . replace (
/\?.*$/ ,
"?" + ( year && year [ 2 ] ? "year=" + year [ 2 ] + "&" : "" ) + filter
) ;
}
if ( this . navigateTo ) {
this . navigateTo ( this . json _url ) ;
} else {
this . update ( ) ;
}
} ;
return Competitions ;
} ) ( ) ;
/ * *
* Aggregated rankings widget inheriting from DrBaseWidget
* /
var Aggregated = ( function ( ) {
/ * *
* Constructor for aggregated rankings ( nat . team ranking , sektionenwertung , ... ) from given json url
*
* Table get appended to specified _container
*
* @ param _container
* @ param _json _url url for data to load
* /
function Aggregated ( _container , _json _url ) {
DrBaseWidget . prototype . constructor . call ( this , _container , _json _url ) ;
this . update ( ) ;
}
// inherite from DrBaseWidget
Aggregated . prototype = new DrBaseWidget ( ) ;
Aggregated . prototype . constructor = Aggregated ;
/ * *
* Callback for loading data via ajax
*
* @ param _data route data object
* /
Aggregated . prototype . handleResponse = function ( _data ) {
var that = this ;
// if we are not controlled by DrWidget, install our own navigation
if ( ! this . navigateTo ) {
this . navigateTo = function ( e ) {
document . location . hash = this . href . replace ( /^.*#!/ , "" ) ;
e . preventDefault ( ) ;
} ;
this . update = function ( ) {
that . json _url =
that . json _url . replace ( /&(cup|comp|cat)=[^&]+/ , "" ) +
"&" +
document . location . hash . substr ( 1 ) ;
DrBaseWidget . prototype . update . call ( that ) ;
} ;
this . installPopState ( ) ;
}
this . columns = {
rank : this . lang ( "Rank" ) ,
nation : { label : _data . aggregated _name , colspan : 2 } ,
name : _data . aggregated _name ,
points : { label : this . lang ( "Points" ) } ,
} ;
if ( location . hash . indexOf ( "detail=1" ) == - 1 ) {
this . columns . points . click = function ( e ) {
var hidden _cols = that . container . find ( ".result,.calculationHidden" ) ;
var display = hidden _cols . length
? jQuery ( hidden _cols [ 0 ] ) . css ( "display" )
: "none" ;
hidden _cols . css ( "display" , display == "none" ? "table-cell" : "none" ) ;
location . hash += "&detail=1" ;
e . preventDefault ( ) ;
} ;
// add calculation to see-also links
if ( typeof _data . see _also == "undefined" ) _data . see _also = [ ] ;
_data . see _also . push ( {
name : "calculation of this ranking" ,
url : location . href + "&detail=1" ,
} ) ;
}
if ( _data . aggregate _by != "nation" ) delete this . columns . nation ;
if ( typeof this . table == "undefined" ) {
this . ranking _name = jQuery ( document . createElement ( "h1" ) ) . addClass (
"rankingName"
) ;
this . container . append ( this . ranking _name ) ;
// cup or competition
this . header = jQuery ( document . createElement ( "h2" ) ) . addClass (
"rankingHeader"
) ;
this . container . append ( this . header ) ;
// category names
this . header2 = jQuery ( document . createElement ( "h3" ) ) . addClass (
"rankingHeader2"
) ;
this . container . append ( this . header2 ) ;
} else {
jQuery ( this . table . dom ) . remove ( ) ;
this . header . empty ( ) ;
this . header2 . empty ( ) ;
}
this . ranking _name . text ( _data . name ) ;
this . header . text ( _data . cup _name || _data . comp _name ) ;
// if we filter by cat display categories as 2. header
if ( _data . cat _filter ) {
if ( _data . cat _name ) {
// category name given, use it but upcase and space it
this . header2 . text ( _data . cat _name . toUpperCase ( ) . split ( "" ) . join ( " " ) ) ;
} else {
var names = "" ;
for ( var i in _data . categorys ) {
names += ( names ? ", " : "" ) + _data . categorys [ i ] . name ;
}
this . header2 . text ( names ) ;
}
}
// make _data available to other methods
this . data = _data ;
var comps = [ ] ;
for ( var c in _data . competitions ) comps . push ( _data . competitions [ c ] ) ;
// use competition columns for more then one comp. and international or SUI
if ( comps . length > 1 && ( ! _data . nation || _data . nation == "SUI" ) ) {
comps . sort ( function ( a , b ) {
return a . date < b . date ? 1 : - 1 ;
} ) ;
for ( var c = 0 ; c < comps . length ; ++ c ) {
this . columns [ "result" + comps [ c ] . WetId ] = function (
_data ,
_tag ,
_name
) {
return that . comp _column . call ( that , _data , _tag , _name ) ;
} ;
}
} // otherwise use category header
else {
var cats = [ ] ;
for ( var c in _data . categorys ) cats . push ( _data . categorys [ c ] ) ;
cats . sort ( function ( a , b ) {
return a . name < b . name ? - 1 : 1 ;
} ) ;
for ( var c = 0 ; c < cats . length ; ++ c ) {
this . columns [ "result" + cats [ c ] . GrpId ] = function ( _data , _tag , _name ) {
return that . cat _column . call ( that , _data , _tag , _name ) ;
} ;
}
}
if ( ! _data . use _cup _points ) {
// display all ranking points with 2 digits
for ( var f = 0 ; f < _data . federations . length ; ++ f ) {
_data . federations [ f ] . points = _data . federations [ f ] . points . toFixed ( 2 ) ;
}
}
// create new table
this . table = new DrTable (
_data . federations ,
this . columns ,
false ,
true ,
null ,
this . navigateTo
) ;
// add table footer with note about how many results are counting
var tfoot = jQuery ( document . createElement ( "tfoot" ) ) ;
jQuery ( this . table . dom ) . append ( tfoot ) ;
var th = jQuery ( document . createElement ( "th" ) ) . addClass ( "result" ) ;
if ( this . json _url . indexOf ( "detail=1" ) == - 1 )
th . addClass ( "calculationHidden" ) ;
tfoot . append ( jQuery ( document . createElement ( "tr" ) ) . append ( th ) ) ;
var cols = 0 ;
for ( var c in this . columns ) cols ++ ;
th . attr ( "colspan" , cols ) ;
th . text (
this . lang (
"For %1 %2 best results per competition and category are counting." ,
_data . name ,
_data . best _results
) +
" " +
this . lang ( "Not counting results are in brackets." )
) ;
this . container . append ( this . table . dom ) ;
this . seeAlso ( _data . see _also ) ;
} ;
/ * *
* Display a competition column
*
* @ param _data
* @ param _tag tag 'th' for header or 'td' for data row
* @ param _name column - name
* /
Aggregated . prototype . comp _column = function ( _data , _tag , _name ) {
var id = _name . substr ( 6 ) ;
var ret = { className : "result" } ;
if ( this . json _url . indexOf ( "detail=1" ) == - 1 )
ret . className += " calculationHidden" ;
if ( _tag == "th" ) {
// use comp. shortcut plus date as column header
ret . label =
( this . data . competitions [ id ] . short ||
this . data . competitions [ id ] . name . replace ( /^.* - / , "" ) ) +
"\n" +
this . formatDate ( this . data . competitions [ id ] . date ) ;
// add comp to url evtl. replacing cup
ret . url =
location . href . indexOf ( "cup=" ) == - 1
? location . href +
( location . href . indexOf ( "#!" ) == - 1 ? "#!" : "&" ) +
"comp=" +
id
: location . href . replace ( /(cup)=[^&]+/ , "comp=" + id ) ;
// nat. team ranking selects a cat, if none given, need to add it to not get a different selected
if ( this . data . cat _filter && ret . url . indexOf ( "cat=" ) == - 1 )
ret . url += "&cat=" + this . data . cat _filter ;
// keep in detailed view
if ( ret . url . indexOf ( "detail=1" ) == - 1 ) ret . url += "&detail=1" ;
ret . title = this . data . competitions [ id ] . name ;
} else if (
this . data . cat _filter &&
this . data . cat _filter . indexOf ( "," ) == - 1
) {
ret . label = "" ;
ret . nodes = this . results ( id , "WetId" , _data . counting ) ;
} else {
ret . label = _data . comps [ id ] ;
}
return ret ;
} ;
/ * *
* Display a category column
*
* @ param _data
* @ param _tag tag 'th' for header or 'td' for data row
* @ param _name column - name
* /
Aggregated . prototype . cat _column = function ( _data , _tag , _name ) {
var id = _name . substr ( 6 ) ;
var ret = { className : "result" } ;
if ( this . json _url . indexOf ( "detail=1" ) == - 1 )
ret . className += " calculationHidden" ;
if ( _tag == "th" ) {
ret . label = this . data . categorys [ id ] . name ;
// get less wide headers by inserting a newline
ret . label = ret . label
. replace ( /(lead|speed|boulder)/ , "\n$1" )
. replace ( /(männliche|weibliche|male|female) */ , "$1\n" ) ;
if ( ! this . data . comp _filter && ! this . data . cat _filter ) {
ret . url = location . href + "&cat=" + id ;
// keep in detailed view
if ( ret . url . indexOf ( "detail=1" ) == - 1 ) ret . url += "&detail=1" ;
}
} else if ( ! this . data . comp _filter && ! this . data . cat _filter ) {
// sektionenwertung
var points = 0.0 ;
for ( var r = 0 ; r < _data . counting . length ; ++ r ) {
var result = _data . counting [ r ] ;
if ( result . GrpId == id ) {
points += result . points ;
}
}
ret . label = points . toFixed ( 2 ) ;
} else {
ret . label = "" ;
ret . nodes = this . results ( id , "GrpId" , _data . counting ) ;
}
return ret ;
} ;
Aggregated . prototype . results = function ( _id , _attr , _results ) {
var cols = [ "rank" , "lastname" , "firstname" , "points" ] ;
var nodes ;
for ( var r = 0 ; r < _results . length ; ++ r ) {
var result = _results [ r ] ;
if ( result [ _attr ] == _id ) {
if ( typeof nodes == "undefined" ) {
nodes = jQuery ( document . createElement ( "div" ) ) . addClass ( "resultRows" ) ;
}
var div = jQuery ( document . createElement ( "div" ) ) . addClass ( "resultRow" ) ;
for ( var c = 0 ; c < cols . length ; ++ c ) {
var col = cols [ c ] ;
var span = jQuery ( document . createElement ( "span" ) ) . addClass ( col ) ;
span . text (
col != "points" || this . data . use _cup _points
? result [ col ]
: result [ col ] . toFixed ( 2 )
) ;
div . append ( span ) ;
}
nodes . append ( div ) ;
}
}
return nodes ;
} ;
return Aggregated ;
} ) ( ) ;
/ * *
* Universal widget to display all data specified by _json _url or location
* /
var DrWidget = ( function ( ) {
/ * *
* call appropriate widget to display data specified by _json _url or location
*
* @ param _container
* @ param _json _url url for data to load
* @ param _arg3 object with widget specific 3. argument , eg . { Competitions : { filters } , Profile : 'template-id' }
* /
function DrWidget ( _container , _json _url , _arg3 ) {
DrBaseWidget . prototype . constructor . call ( this , _container , _json _url ) ;
this . arg3 = _arg3 || { } ;
var matches = this . json _url . match ( /\?.*$/ ) ;
this . update ( matches ? matches [ 0 ] : null ) ;
// install this.update as PopState handler
this . installPopState ( ) ;
}
// inherit from DrBaseWidget
DrWidget . prototype = new DrBaseWidget ( ) ;
DrWidget . prototype . constructor = DrWidget ;
/ * *
* Navigate to a certain result - page
*
* @ param _params default if not specified first location . hash then location . search
* @ param { DrBaseWidget } _widget to clear evtl . pending update timer
* /
DrWidget . prototype . navigateTo = function ( _params , _widget ) {
// clear pending update timer of widget, to stay on new widget we navigate to now
if ( _widget && _widget . update _handle ) {
window . clearTimeout ( _widget . update _handle ) ;
delete _widget . update _handle ;
}
delete this . prevent _initial _pop ;
// check if we have an ordinary link without hash or query, eg. result PDF
if ( ! _params . match ( /(#|\?)/ ) ) {
document . location = _params ;
}
var params = "!" + _params . replace ( /^.*(#!|#|\?)/ , "" ) ;
// update location hash, to reflect current page-content
if ( document . location . hash != "#" + params ) document . location . hash = params ;
} ;
DrWidget . prototype . update = function ( _params ) {
var params = _params || location . hash || location . search ;
params = params . replace ( /^.*(#!|#|\?)/ , "" ) ;
this . json _url = this . json _url . replace ( /\?.*$/ , "" ) + "?" + params ;
// check which widget is needed to render requested content
function hasParam ( _param , _value ) {
if ( typeof _value == "undefined" ) _value = "" ;
return params . indexOf ( _param + "=" + _value ) != - 1 ;
}
var widget ;
if (
hasParam ( "type" , "nat_team_ranking" ) ||
hasParam ( "type" , "sektionenwertung" ) ||
hasParam ( "type" , "regionalzentren" )
) {
widget = "Aggregated" ;
} else if ( hasParam ( "person" ) ) {
widget = "Profile" ;
} else if ( hasParam ( "cat" ) && ! hasParam ( "comp" ) ) {
widget = "Resultlist" ; // ranking uses Resultlist!
} else if ( hasParam ( "nation" ) || ! hasParam ( "comp" ) ) {
widget = "Competitions" ;
} else if ( hasParam ( "comp" ) && hasParam ( "type" , "starters" ) ) {
widget = "Starters" ;
} else if ( ( hasParam ( "comp" ) && ! hasParam ( "cat" ) ) || hasParam ( "filter" ) ) {
widget = "Results" ;
} else if ( hasParam ( "type" , "startlist" ) ) {
widget = "Startlist" ;
} else {
widget = "Resultlist" ;
}
// check if widget is currently instancated and only need to update or need to be instancated
if (
typeof this . widget == "undefined" ||
this . widget . constructor != window [ widget ]
) {
this . container . html ( "" ) ; // following .empty() does NOT work in IE8 Grrrr
this . container . empty ( ) ;
// do a new of objects whos name is stored in widget
this . widget = Object . create ( window [ widget ] . prototype ) ;
// Object.create, does NOT call constructor, so do it now manually
window [ widget ] . call (
this . widget ,
this . container ,
this . json _url ,
this . arg3 [ widget ]
) ;
var that = this ;
this . widget . navigateTo = function ( e ) {
if ( typeof e == "string" ) {
that . navigateTo ( e , that . widget ) ;
} else {
that . navigateTo ( this . href , that . widget ) ;
e . preventDefault ( ) ;
}
} ;
} else {
this . widget . json _url = this . json _url ;
this . widget . update ( ) ;
}
} ;
return DrWidget ;
} ) ( ) ;
/ * *
* Widget to let user choose a competition and category to show its result
*
* Chooser selectboxes stay visible , when user navigates in result eg . to show a profile
* /
var ResultChooser = ( function ( ) {
/ * *
* call appropriate widget to display data specified by _json _url or location
*
* @ param _container
* @ param _json _url url for data to load
* @ param { object } _arg3 object with 3. parameter to pass to widget used to display results
* /
function ResultChooser ( _container , _json _url , _arg3 ) {
DrBaseWidget . prototype . constructor . call (
this ,
_container ,
_json _url . replace ( /&cat=[^&]+/ , "" )
) ;
this . arg3 = _arg3 || {
Results : true , // show NO own navigation
Startlist : true ,
Resultlist : true ,
} ;
var matches = this . json _url . match ( /\?.*$/ ) ;
this . update ( matches ? matches [ 0 ] : null ) ;
this . comp _chooser = this . cat _chooser = undefined ;
var matches = _json _url . match ( /&cat=([^&]+)/ ) ;
this . cat = matches ? matches [ 1 ] : undefined ;
this . widget = undefined ;
// install this.update as PopState handler
//this.installPopState();
}
// inherit from DrBaseWidget
ResultChooser . prototype = new DrBaseWidget ( ) ;
ResultChooser . prototype . constructor = ResultChooser ;
/ * *
* Callback for loading data via ajax
*
* @ param _data route data object
* /
ResultChooser . prototype . handleResponse = function ( _data ) {
if ( ! this . comp _chooser ) {
// competition chooser
this . comp _chooser = jQuery ( document . createElement ( "select" ) ) ;
this . comp _chooser . addClass ( "compChooser" ) ;
this . container . append ( this . comp _chooser ) ;
var that = this ;
this . comp _chooser . change ( function ( e ) {
that . json _url = that . json _url
. replace ( /comp=[^&]+/ , "comp=" + this . value )
. replace ( /&cat=[^&]+/ , "" ) ;
that . update ( ) ;
} ) ;
this . cat _chooser = jQuery ( document . createElement ( "select" ) ) ;
this . cat _chooser . addClass ( "catChooser" ) ;
this . container . append ( this . cat _chooser ) ;
this . cat _chooser . change ( function ( e ) {
that . cat = this . value ;
that . json _url = that . json _url . replace (
/comp=[^&]+/ ,
"comp=" + that . comp _chooser . val ( )
) ;
if ( ! that . cat ) that . json _url = that . json _url . replace ( /&cat=[^&]+/ , "" ) ;
else if ( that . json _url . search ( "cat=" ) == - 1 )
that . json _url += "&cat=" + this . value ;
else
that . json _url = that . json _url . replace (
/cat=[^&]+/ ,
"cat=" + this . value
) ;
that . widget . navigateTo ( that . json _url ) ;
} ) ;
} else {
this . comp _chooser . empty ( ) ;
this . cat _chooser . empty ( ) ;
}
// fill competition chooser
for ( var i = 0 ; i < _data . competitions . length ; ++ i ) {
var competition = _data . competitions [ i ] ;
var option = jQuery ( document . createElement ( "option" ) ) ;
option . attr ( { value : competition . WetId , title : competition . date _span } ) ;
option . text ( competition . name ) ;
if ( competition . WetId == _data . WetId ) option . attr ( "selected" , true ) ;
this . comp _chooser . append ( option ) ;
}
// fill category chooser
var option = jQuery ( document . createElement ( "option" ) ) ;
option . attr ( "value" , "" ) ;
option . text ( this . lang ( "Select a single category to show ..." ) ) ;
this . cat _chooser . append ( option ) ;
var cat _found = false ;
for ( var i = 0 ; i < _data . categorys . length ; ++ i ) {
var cat = _data . categorys [ i ] ;
option = jQuery ( document . createElement ( "option" ) ) ;
option . attr ( "value" , cat . GrpId ) ;
option . text ( cat . name ) ;
if ( cat . GrpId == this . cat ) {
option . attr ( "selected" , true ) ;
cat _found = true ;
}
this . cat _chooser . append ( option ) ;
}
if ( ! cat _found ) this . cat = undefined ;
if ( ! this . widget ) {
var widget _container = jQuery ( document . createElement ( "div" ) ) . appendTo (
this . container
) ;
this . widget = new DrWidget (
widget _container ,
this . json _url + ( this . cat ? "&cat=" + this . cat : "" ) ,
this . arg3
) ;
} else {
this . widget . navigateTo (
this . json _url + ( this . cat ? "&cat=" + this . cat : "" )
) ;
}
} ;
return ResultChooser ;
} ) ( ) ;
/ * *
* Dynamically load a css file
*
* @ param href url to css file
* /
function load _css ( href ) {
//Get the head node and append a new link node with the stylesheet url to it
var headID = document . getElementsByTagName ( "head" ) [ 0 ] ;
var cssnode = document . createElement ( "link" ) ;
cssnode . type = "text/css" ;
cssnode . rel = "stylesheet" ;
cssnode . href = href ;
headID . appendChild ( cssnode ) ;
}
/ * *
* Align non - breaking - space separated parts of text in a td by wrapping them in equally sized spans
*
* @ param { string | jQuery } elems
* /
function align _td _nbsp ( elems ) {
jQuery ( elems ) . replaceWith ( function ( ) {
var parts = jQuery ( this )
. contents ( )
. text ( )
. split ( /\u00A0+/ ) ;
if ( parts . length == 1 ) return jQuery ( this ) . clone ( ) ;
var prefix = '<div class="tdAlign' + parts . length + '">' ;
var postfix = "</div>" ;
return jQuery (
"<td>" + prefix + parts . join ( postfix + prefix ) + postfix + "</td>"
) . addClass ( this . className ) ;
} ) ;
}
/ * *
* Some compatibilty functions to cope with older javascript implementations
* /
if ( ! Array . isArray ) {
Array . isArray = function ( vArg ) {
return Object . prototype . toString . call ( vArg ) === "[object Array]" ;
} ;
}
if ( ! Object . create ) {
Object . create = function ( o ) {
function F ( ) { }
F . prototype = o ;
return new F ( ) ;
} ;
}
if ( ! Date . getWeek ) {
Date . prototype . getWeek = function ( ) {
var onejan = new Date ( this . getFullYear ( ) , 0 , 1 ) ;
return Math . ceil ( ( ( this - onejan ) / 86400000 + onejan . getDay ( ) + 1 ) / 7 ) ;
} ;
}