/** * Created by Owen Gannon (gannono2) for The Irish Times on 06/01/2015. * * This plugin is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License * http://creativecommons.org/licenses/by-sa/4.0/ */ (function($){ var templateRoot = "/cstatic/static/general-election/templates/"; var noResultsText = "Results Pending"; var totalSeats = 158; // By default, the total number of seats for 2016 is 158 var electionCode = "gen2016"; // The code of the election to query the api is gen2016 var totalConstituencies = 40; // By default, the total number of constituencies is 40 var constituencyLookup = []; // By default, the Ceann Comhairle is FG (2016) var ceannComhairle = { party: "FG", name: "Barrett, Seán", constituencyCode: "DLR" }; $.fn.extend({ initNational: function(options, callback){ // Error handling the options if (options.constituencyLookup === undefined || options.constituencyLookup === null) { return callback({err: true, msg: "ERR: The constituency lookup list must be specified in options."}); } constituencyLookup = options.constituencyLookup; if (options.ceannComhairle === undefined || options.ceannComhairle === null) { return callback({err: true, msg: "ERR: The Ceann Comhairle's party code must be specified in options."}); } ceannComhairle = options.ceannComhairle; if (options.totalConstituencies === undefined || options.totalConstituencies === null) { return callback({err: true, msg: "ERR: Total Constituencies must be specified in options."}); } totalConstituencies = options.totalConstituencies; if (options.totalSeats === undefined || options.totalSeats === null) { return callback({err: true, msg: "ERR: Total Seats must be specified in options."}); } totalSeats = options.totalSeats; if (options.electionCode === undefined || options.electionCode === null) { return callback({err: true, msg: "ERR: Election code must be specified in options."}); } electionCode = options.electionCode; var ts = new Date().getTime(); var url = "/cstatic/election-api/api/public/v1/elections/" + electionCode + "/nationalpage.js" + "?ts=" + ts; $.getJSON(url, function(json){ if(json["error_msg"]) { return callback({ err: true }); } // Assign the response properties to variables var results = []; var ioFirstPref = 0; var ioSeats = 0; var keys = Object.keys(json["parties"]); for(var i = 0; i < keys.length; i++){ var party = keys[i]; var colourClass = keys[i].toLowerCase(); if(party.toLowerCase() === "ind" || party.toLowerCase() === "oth") { ioFirstPref += json["parties"][keys[i]]["firstpreference"]; ioSeats += json["parties"][keys[i]]["seats"]; } else { results.push({ party: party, firstpreference: json["parties"][keys[i]]["firstpreference"], seats: json["parties"][keys[i]]["seats"], colourClass: colourClass }); } } // Push the independents and others into the results list results.push({ party: "IO", firstpreference: ioFirstPref, seats: ioSeats, colourClass: "io" }); results.sort(function(a, b){ return b.firstpreference - a.firstpreference; }); // Start off with nothing... var filled = 0; // Loop through all the constituencies returned by the api for(var j = 0; j < json.constituencies.length; j++){ // add up the seats filled in each constituency filled += json.constituencies[j].seatsfilled; } var complete = 0; for(var k = 0; k < json.constituencies.length; k++){ // add up the completed constituencies if(json.constituencies[k].elected.length === json.constituencies[k].totalseats){ complete++; } } var indicators = { seatsFilled: filled+1, // Ceann Comhairle constituenciesCompleted: complete, firstPreferences: json["firstpreferencescompleted"] }; return callback({ results: results, indicators: indicators, constituencies: json["constituencies"] }); }).fail(function(){ return {err: true }; }); }, nullState: function(element){ var $this = $(this); if(element === "spread"){ var spread = new EJS({url: templateRoot + 'national-spread.ejs'}).render({err: true, msg: noResultsText}); $this.empty().append(spread); } if(element === "spread-seats"){ var seatsFilled = 0; var seatsSpread = new EJS({url: templateRoot + 'national-spread-seats.ejs'}).render({ err: true, ceannComhairle: ceannComhairle, msg: noResultsText, totalSeats: seatsFilled, maxSeats: totalSeats }); $this.empty().append(seatsSpread); } if(element === "legend"){ var legend = new EJS({url: templateRoot + 'national-legend.ejs'}).render({ err: true, ceannComhairle: ceannComhairle }); $this.empty().append(legend); } if(element === "indicators"){ var indicators = { constituenciesCompleted: 0, firstPreferences: 0, seatsFilled: 0 }; var totals = { totalConstituencies: totalConstituencies, totalSeats: totalSeats }; var indicatorHtml = new EJS({url: templateRoot + 'national-indicators.ejs'}).render({ indicators: indicators, totals: totals }); $this.empty().append(indicatorHtml); } if(element === "cards"){ // Prepare the lookup data for(var a = 0; a < constituencyLookup.length; a++){ constituencyLookup[a].elected = []; constituencyLookup[a].seatsfilled = 0; constituencyLookup[a].totalseats = constituencyLookup[a].seats; if(ceannComhairle.constituencyCode.toUpperCase() === constituencyLookup[a].code.toUpperCase()){ constituencyLookup[a].seatsfilled++; constituencyLookup[a].elected.push({ name: ceannComhairle.name, party: ceannComhairle.party, firstpreference: "Ceann Comhairle" }); } } var html = new EJS({url: templateRoot + 'national-cards.ejs'}).render({ constituencies: constituencyLookup, showIndicator: false, filtered: false }); $this.empty().append(html); $.fn.cardsToPanels(); } }, drawSpread: function(data){ var $this = $(this); var html = new EJS({url: templateRoot + 'national-spread.ejs'}).render({ err: false, data: data, ceannComhairle: ceannComhairle }); $this.empty().append(html); }, drawSpreadSeats: function(data){ var $this = $(this); var seatsFilled = 0; for(var i = 0; i < data.results.length; i++){ seatsFilled += data.results[i].seats; } data.results.sort(function(a, b){ return b.seats - a.seats; }); var html = new EJS({url: templateRoot + 'national-spread-seats.ejs'}).render({ err: false, data: data, ceannComhairle: ceannComhairle, seatsFilled: seatsFilled, totalSeats: totalSeats }); $this.empty().append(html); }, drawLegend: function(data){ var $this = $(this); var html = new EJS({url: templateRoot + 'national-legend.ejs'}).render({ err: false, data: data, ceannComhairle: ceannComhairle }); $this.empty().append(html); }, drawLegendSeats: function(data){ var $this = $(this); var seatsFilled = 0; for(var i = 0; i < data.results.length; i++){ seatsFilled += data.results[i].seats; } data.results.sort(function(a, b){ return b.seats - a.seats; }); var html = new EJS({url: templateRoot + 'national-legend-seats.ejs'}).render({ err: false, data: data, ceannComhairle: ceannComhairle, seatsFilled: seatsFilled, totalSeats: totalSeats }); $this.empty().append(html); }, drawIndicators: function(data){ var $this = $(this); // Default var valid = data.constituencies !== undefined; var indicators = { constituenciesCompleted: valid ? data.indicators.constituenciesCompleted : 0, firstPreferences: valid ? data.indicators.firstPreferences: 0, seatsFilled: valid ? data.indicators.seatsFilled : 1 }; var totals = { totalConstituencies: totalConstituencies, totalSeats: totalSeats }; var html = new EJS({url: templateRoot + 'national-indicators.ejs'}).render({ indicators: indicators, totals: totals }); $this.empty().append(html); }, drawFilters: function(callback){ var $this = $(this); var html = new EJS({url: templateRoot + 'national-cards-filters.ejs'}).render(); $this.empty().append(html); return callback(); }, drawCards: function(data){ // Prepare the lookup data for(var a = 0; a < constituencyLookup.length; a++){ constituencyLookup[a].elected = []; constituencyLookup[a].seatsfilled = 0; constituencyLookup[a].totalseats = constituencyLookup[a].seats; if(ceannComhairle.constituencyCode.toUpperCase() === constituencyLookup[a].code.toUpperCase()){ constituencyLookup[a].seatsfilled++; constituencyLookup[a].elected.push({ name: ceannComhairle.name, party: ceannComhairle.party, firstpreference: "Ceann Comhairle" }); } } // Apply changes from API to master constituencies list if(data.constituencies !== undefined){ var constituencies = data.constituencies; for(var x = 0; x < constituencies.length; x++){ var current = constituencies[x]; // Find the current constituency in the lookup for(var y = 0; y < constituencyLookup.length; y++){ var normalCurrentName = current.name.replace(/\s+/g, '-').toLowerCase(); var normalLookupName = constituencyLookup[y].name.replace(/\s+/g, '-').toLowerCase(); if(normalCurrentName === normalLookupName){ // Found it... apply the changes constituencyLookup[y].seatsfilled += current.seatsfilled; constituencyLookup[y].totalSeats = constituencyLookup[y].seats; if(current.elected.length > 0){ for(var z = 0; z < current.elected.length; z++){ constituencyLookup[y].elected.push(current.elected[z]); } } } } } } var $this = $(this); var html = new EJS({url: templateRoot + 'national-cards.ejs'}).render({ constituencies: constituencyLookup, showIndicator: data.indicators === undefined ? false : data.indicators.firstPreferences > 0, filtered: false }); $this.empty().append(html); $.fn.cardsToPanels(); }, redrawCards: function(data, region){ var $this = $(this); // Get rid of all the cards... $(".national-view-card").remove(); if(region !== "*") { // show only the region selected region = region.replace(".", ""); var filteredConstituencies = []; for (var i = 0; i < constituencyLookup.length; i++) { if (constituencyLookup[i].region.toLowerCase() === region) { filteredConstituencies.push(constituencyLookup[i]); } } // Prepare the lookup data for(var a = 0; a < filteredConstituencies.length; a++){ filteredConstituencies[a].elected = []; filteredConstituencies[a].seatsfilled = 0; filteredConstituencies[a].totalseats = filteredConstituencies[a].seats; if(ceannComhairle.constituencyCode.toUpperCase() === filteredConstituencies[a].code.toUpperCase()){ filteredConstituencies[a].seatsfilled++; filteredConstituencies[a].elected.push({ name: ceannComhairle.name, party: ceannComhairle.party, firstpreference: "Ceann Comhairle" }); } } // Apply changes from API to master constituencies list if(data.constituencies !== undefined) { var constituencies = data.constituencies; for (var x = 0; x < constituencies.length; x++) { var current = constituencies[x]; // We only want constituencies in the desired filter if(current.region.toLowerCase() !== filteredConstituencies[0].region.toLowerCase()){ continue; } // Find the current constituency in the lookup for (var y = 0; y < filteredConstituencies.length; y++) { var normalCurrentName = current.name.replace(/\s+/g, '-').toLowerCase(); var normalLookupName = filteredConstituencies[y].name.replace(/\s+/g, '-').toLowerCase(); if(normalCurrentName === normalLookupName){ // Found it... apply the changes filteredConstituencies[y].seatsfilled += current.seatsfilled; filteredConstituencies[y].totalSeats = filteredConstituencies[y].seats; if (current.elected.length > 0) { for (var z = 0; z < current.elected.length; z++) { filteredConstituencies[y].elected.push(current.elected[z]); } } } } } } var html = new EJS({url: templateRoot + 'national-cards.ejs'}).render({ constituencies: filteredConstituencies, showIndicator: data.indicators === undefined ? false : data.indicators.firstPreferences > 0, filtered: true }); $this.empty().append(html); $.fn.cardsToPanels(); } else { $this.empty(); $this.drawCards(data); } }, cardsToPanels: function(){ // Hiding the panel content. If JS is inactive, content will be displayed $( '.panel-content' ).hide(); // Preparing the DOM // -- Update the markup of accordion container $( '.accordion' ).attr({ role: 'tablist', multiselectable: 'true' }); // -- Adding ID, aria-labelled-by, role and aria-labelledby attributes to panel content $( '.panel-content' ).attr( 'id', function( IDcount ) { return 'panel-' + IDcount; }); $( '.panel-content' ).attr( 'aria-labelledby', function( IDcount ) { return 'control-panel-' + IDcount; }); $( '.panel-content' ).attr( 'aria-hidden' , 'true' ); // ---- Only for accordion, add role tabpanel $( '.accordion .panel-content' ).attr( 'role' , 'tabpanel' ); // -- Wrapping panel title content with a $( '.panel-title' ).each(function(i){ // ---- Need to identify the target, easy it's the immediate brother $target = $(this).next( '.panel-content' )[0].id; // ---- Creating the link with aria and link it to the panel content $link = $( '', { 'href': '#' + $target, 'aria-expanded': 'false', 'aria-controls': $target, 'id' : 'control-' + $target }); // ---- Output the link $(this).wrapInner($link); }); // Optional : include an icon. Better in JS because without JS it have non-sense. $( '.panel-title a' ).append(''); // Now we can play with it $( '.panel-title a' ).click(function() { if ($(this).attr( 'aria-expanded' ) == 'false'){ //If aria expanded is false then it's not opened and we want it opened ! // -- Only for accordion effect (2 options) : comment or uncomment the one you want // ---- Option 1 : close only opened panel in the same accordion // search through the current Accordion container for opened panel and close it, remove class and change aria expanded value $(this).parents( '.accordion' ).find( '[aria-expanded=true]' ).attr( 'aria-expanded' , false ).removeClass( 'active' ).parent().next( '.panel-content' ).slideUp(200).attr( 'aria-hidden' , 'true'); // Option 2 : close all opened panels in all accordion container //$('.accordion .panel-title > a').attr('aria-expanded', false).removeClass('active').parent().next('.panel-content').slideUp(200); // Finally we open the panel, set class active for styling purpose on a and aria-expanded to "true" $(this).attr( 'aria-expanded' , true ).addClass( 'active' ).parent().next( '.panel-content' ).slideDown(200).attr( 'aria-hidden' , 'false'); } else { // The current panel is opened and we want to close it $(this).attr( 'aria-expanded' , false ).removeClass( 'active' ).parent().next( '.panel-content' ).slideUp(200).attr( 'aria-hidden' , 'true');; } return false; }); } }); })(jQuery);