diff --git a/app/assets/javascripts/govuk_publishing_components/lib/govspeak/barchart-enhancement.js b/app/assets/javascripts/govuk_publishing_components/lib/govspeak/barchart-enhancement.js index 3488f41f98..5309079c04 100644 --- a/app/assets/javascripts/govuk_publishing_components/lib/govspeak/barchart-enhancement.js +++ b/app/assets/javascripts/govuk_publishing_components/lib/govspeak/barchart-enhancement.js @@ -1,4 +1,4 @@ -// = require govuk_publishing_components/vendor/magna-charta.min +// = require govuk_publishing_components/lib/govspeak/magna-charta window.GOVUK = window.GOVUK || {}; diff --git a/app/assets/javascripts/govuk_publishing_components/lib/govspeak/magna-charta.js b/app/assets/javascripts/govuk_publishing_components/lib/govspeak/magna-charta.js new file mode 100644 index 0000000000..8b12b72645 --- /dev/null +++ b/app/assets/javascripts/govuk_publishing_components/lib/govspeak/magna-charta.js @@ -0,0 +1,398 @@ +/* global jQuery */ +/* + * magna-charta + * https://github.com/alphagov/magna-charta + * + * Copyright (c) 2012 Jack Franklin + * Licensed under the MIT license. +*/ + +(function ($) { + 'use strict' + + var MagnaCharta = function () { + this.init = function (table, options) { + var defaults = { + outOf: 65, + applyOnInit: true, + toggleText: 'Toggle between chart and table', + autoOutdent: false, + outdentAll: false, + toggleAfter: false // BOOL set TRUE to append the toggle link + } + + this.options = $.extend({}, defaults, options) + + /* detecting IE version + * original from James Padolsey: https://gist.github.com/527683 + * and then rewritten by Jack Franklin to pass JSHint + */ + var ie = (function () { + var undef + var v = 3 + var div = document.createElement('div') + var all = div.getElementsByTagName('i') + + do { + div.innerHTML = '' + } while (v < 10 && all[0]) + + return (v > 4) ? v : undef + })() + + // if it's IE7 or less, we just show the plain tables + this.ENABLED = !(ie && ie < 8) + + // store a reference to the table in the object + this.$table = table + + // lets make what will become the new graph + this.$graph = $('
').attr('aria-hidden', 'true') + + // copy over classes from the table, and add the extra one + this.$graph.attr('class', this.$table.attr('class')).addClass('mc-chart') + + // set the stacked option based on + // giving the table a class of mc-stacked + this.options.stacked = this.$table.hasClass('mc-stacked') + + // set the negative option based on + // giving the table a class of mc-negative + this.options.negative = this.$table.hasClass('mc-negative') + + // true if it's a 'multiple' table + // this means multiple bars per rows, but not stacked. + this.options.multiple = !this.options.stacked && ( + this.$table.hasClass('mc-multiple') || + this.$table.find('tbody tr').first().find('td').length > 2) + + // set the outdent options + // which can be set via classes or overriden by setting the value to true + // in the initial options object that's passed in + this.options.autoOutdent = this.options.autoOutdent || + this.$table.hasClass('mc-auto-outdent') + + this.options.outdentAll = this.options.outdentAll || + this.$table.hasClass('mc-outdented') + + // add a mc-multiple class if it is + if (this.options.multiple) { this.$graph.addClass('mc-multiple') } + + this.options.hasCaption = !!this.$table.find('caption').length + + if (this.ENABLED) { + this.apply() + // if applyOnInit is false, toggle immediately + // showing the table, hiding the graph + if (!this.options.applyOnInit) { + this.toggle() + } + } + return this + } + } + + // methods for constructing the chart + MagnaCharta.prototype.construct = {} + + // constructs the header + MagnaCharta.prototype.construct.thead = function () { + var thead = $('
', { + class: 'mc-thead' + }) + + var tr = $('
', { class: 'mc-tr' }) + var output = '' + this.$table.find('th').each(function (i, item) { + output += '
' + output += $(item).html() + output += '
' + }) + tr.append(output) + thead.append(tr) + + return thead + } + + MagnaCharta.prototype.construct.tbody = function () { + var tbody = $('
', { + class: 'mc-tbody' + }) + + this.$table.find('tbody tr').each(function (i, item) { + var tr = $('
', { class: 'mc-tr' }) + var cellsOutput = '' + $(item).find('td').each(function (j, cell) { + cellsOutput += '
' + cellsOutput += $(cell).html() + cellsOutput += '
' + }) + tr.append(cellsOutput) + tbody.append(tr) + }) + return tbody + } + + MagnaCharta.prototype.construct.caption = function () { + var cap = this.$table.find('caption') + return cap.clone() + } + + // construct a link to allow the user to toggle between chart and table + MagnaCharta.prototype.construct.toggleLink = function () { + var that = this + return $('', { + href: '#', + class: 'mc-toggle-link', + text: this.options.toggleText, + 'aria-hidden': 'true' + }).on('click', function (e) { + that.toggle(e) + }) + } + + MagnaCharta.prototype.constructChart = function () { + // turn every element in the table into divs with appropriate classes + // call them and define this as scope so it's easier to + // get at options and properties + var thead = this.construct.thead.call(this) + var tbody = this.construct.tbody.call(this) + var toggleLink = this.construct.toggleLink.call(this) + + if (this.options.hasCaption) { + var caption = this.construct.caption.call(this) + this.$graph.append(caption) + } + + if (this.options.toggleAfter) { + this.$table.after(toggleLink) + } else { + this.$table.before(toggleLink) + } + + this.$graph.append(thead) + this.$graph.append(tbody) + } + + MagnaCharta.prototype.apply = function () { + if (this.ENABLED) { + this.constructChart() + this.addClassesToHeader() + this.calculateMaxWidth() + this.applyWidths() + this.insert() + this.$table.addClass('visually-hidden') + this.applyOutdent() + } + } + + // toggles between showing the table and showing the chart + MagnaCharta.prototype.toggle = function (e) { + this.$graph.toggle() + this.$table.toggleClass('visually-hidden') + if (e) { e.preventDefault() } + } + + // some handy utility methods + MagnaCharta.prototype.utils = { + isFloat: function (val) { + return !isNaN(parseFloat(val)) + }, + stripValue: function (val) { + var re = new RegExp('\\,|£|%|[a-z]', 'gi') + return val.replace(re, '') + }, + returnMax: function (values) { + var max = 0 + for (var i = 0; i < values.length; i++) { + if (values[i] > max) { max = values[i] } + } + return max + }, + isNegative: function (value) { + return (value < 0) + } + } + + MagnaCharta.prototype.addClassesToHeader = function () { + var headerCells = this.$graph.find('.mc-th').filter(':not(:first)') + + if (this.options.stacked) { + headerCells.last().addClass('mc-stacked-header mc-header-total') + headerCells = headerCells.filter(':not(:last)') + } + + headerCells.addClass('mc-key-header').filter(':not(.mc-stacked-header)').each(function (i, item) { + $(item).addClass('mc-key-' + (i + 1)) + }) + } + + MagnaCharta.prototype.calculateMaxWidth = function () { + // JS scoping sucks + var that = this + + // store the cell values in here so later + // so we can figure out the maximum value later + var values = [] + + // var to store the maximum negative value + // (used only for negative charts) + var maxNegativeValue = 0 + + // loop through every tr in the table + this.$graph.find('.mc-tr').each(function (i, item) { + var $this = $(item) + + // the first td is going to be the key, so ignore it + var $bodyCells = $this.find('.mc-td:not(:first)') + + // if it's stacked, the last column is a totals + // so we don't want that in our calculations + if (that.options.stacked) { + $bodyCells.last().addClass('mc-stacked-total') + $bodyCells = $bodyCells.filter(':not(:last)') + } + + // first td in each row is key + $this.find('.mc-td:first').addClass('mc-key-cell') + + // store the total value of the bar cells in a row + // for anything but stacked, this is just the value of one + var cellsTotalValue = 0 + + $bodyCells.each(function (j, cell) { + var $cell = $(cell).addClass('mc-bar-cell').addClass('mc-bar-' + (j + 1)) + var cellVal = that.utils.stripValue($cell.text()) + + if (that.utils.isFloat(cellVal)) { + var parsedVal = parseFloat(cellVal, 10) + var absParsedVal = Math.abs(parsedVal) + if (parsedVal === 0) { + $cell.addClass('mc-bar-zero') + } + + if (that.options.negative) { + if (that.utils.isNegative(parsedVal)) { + $cell.addClass('mc-bar-negative') + if (absParsedVal > maxNegativeValue) { + maxNegativeValue = absParsedVal + } + } else { + $cell.addClass('mc-bar-positive') + } + } + // now we are done with our negative calculations + // set parsedVal to absParsedVal + parsedVal = absParsedVal + + if (!that.options.stacked) { + cellsTotalValue = parsedVal + values.push(parsedVal) + } else { + cellsTotalValue += parsedVal + } + } + }) + + // if stacked, we need to push the total value of the row + // to the values array + if (that.options.stacked) { values.push(cellsTotalValue) } + }) + + var resp = {} + resp.max = parseFloat(that.utils.returnMax(values), 10) + resp.single = parseFloat(this.options.outOf / resp.max, 10) + + if (this.options.negative) { + resp.marginLeft = parseFloat(maxNegativeValue, 10) * resp.single + resp.maxNegative = parseFloat(maxNegativeValue, 10) + } + + return resp + } + + MagnaCharta.prototype.applyWidths = function () { + this.dimensions = this.calculateMaxWidth() + var that = this + + this.$graph.find('.mc-tr').each(function (i, row) { + var $this = $(row) + + $this.find('.mc-bar-cell').each(function (j, cell) { + var $cell = $(cell) + var parsedCellVal = parseFloat(that.utils.stripValue($cell.text()), 10) + var parsedVal = parsedCellVal * that.dimensions.single + var absParsedCellVal = Math.abs(parsedCellVal) + var absParsedVal = Math.abs(parsedVal) + + // apply the left margin to the positive bars + if (that.options.negative) { + if ($cell.hasClass('mc-bar-positive')) { + $cell.css('margin-left', that.dimensions.marginLeft + '%') + } else { + // if its negative but not the maximum negative + // we need to give it enough margin to push it further right to align + if (absParsedCellVal < that.dimensions.maxNegative) { + // left margin needs to be + // (largestNegVal - thisNegVal)*single + var leftMarg = (that.dimensions.maxNegative - absParsedCellVal) * that.dimensions.single + $cell.css('margin-left', leftMarg + '%') + } + } + } + + // wrap the cell value in a span tag + $cell.wrapInner('') + $cell.css('width', absParsedVal + '%') + }) + }) + } + + MagnaCharta.prototype.insert = function () { + this.$table.after(this.$graph) + } + + MagnaCharta.prototype.applyOutdent = function () { + /* + * this figures out if a cell needs an outdent and applies it + * it needs an outdent if the width of the text is greater than the width of the bar + * if this is the case, wrap the value in a span, and use absolute positioning + * to push it out (the bar is styled to be relative) + * unfortunately this has to be done once the chart has been inserted + */ + var that = this + + this.$graph.find('.mc-bar-cell').each(function (i, cell) { + var $cell = $(cell) + var cellVal = parseFloat(that.utils.stripValue($cell.text()), 10) + var $cellSpan = $cell.children('span') + var spanWidth = $cellSpan.width() + 10 // +10 just for extra padding + var cellWidth = $cell.width() + + if (!that.options.stacked) { + // if it's 0, it is effectively outdented + if (cellVal === 0) { $cell.addClass('mc-bar-outdented') } + + if ((that.options.autoOutdent && spanWidth > cellWidth) || that.options.outdentAll) { + $cell.addClass('mc-bar-outdented') + + $cellSpan.css({ + 'margin-left': '100%', + display: 'inline-block' + }) + } else { + $cell.addClass('mc-bar-indented') + } + } else { + // if it's a stacked graph + if (spanWidth > cellWidth && cellVal > 0) { + $cell.addClass('mc-value-overflow') + } + } + }) + } + + $.magnaCharta = function (table, options) { + return new MagnaCharta().init(table, options) + } +}(jQuery)) diff --git a/app/assets/javascripts/govuk_publishing_components/vendor/magna-charta.min.js b/app/assets/javascripts/govuk_publishing_components/vendor/magna-charta.min.js deleted file mode 100644 index 18f7eef795..0000000000 --- a/app/assets/javascripts/govuk_publishing_components/vendor/magna-charta.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! Magna Charta - v3.0.0 - 2012-12-04 -* https://github.com/alphagov/magna-charta - */ -(function(e){var t=function(){this.init=function(t,n){var r={outOf:65,applyOnInit:!0,toggleText:"Toggle between chart and table",autoOutdent:!1,outdentAll:!1};this.options=e.extend({},r,n);var i=function(){var e,t=3,n=document.createElement("div"),r=n.getElementsByTagName("i");do n.innerHTML="";while(t<10&&r[0]);return t>4?t:e}();return this.ENABLED=!(i&&i<8),this.$table=t,this.$graph=e("
").attr("aria-hidden","true"),this.$graph.attr("class",this.$table.attr("class")).addClass("mc-chart"),this.options.stacked=this.$table.hasClass("mc-stacked"),this.options.negative=this.$table.hasClass("mc-negative"),this.options.multiple=!this.options.stacked&&(this.$table.hasClass("mc-multiple")||this.$table.find("tbody tr").first().find("td").length>2),this.options.autoOutdent=this.options.autoOutdent||this.$table.hasClass("mc-auto-outdent"),this.options.outdentAll=this.options.outdentAll||this.$table.hasClass("mc-outdented"),this.options.multiple&&this.$graph.addClass("mc-multiple"),this.options.hasCaption=!!this.$table.find("caption").length,this.ENABLED&&(this.apply(),this.options.applyOnInit||this.toggle()),this}};t.prototype.construct={},t.prototype.construct.thead=function(){var t=e("
",{"class":"mc-thead"}),n=e("
",{"class":"mc-tr"}),r="";return this.$table.find("th").each(function(t,n){r+='
',r+=e(n).html(),r+="
"}),n.append(r),t.append(n),t},t.prototype.construct.tbody=function(){var t=e("
",{"class":"mc-tbody"}),n="";return this.$table.find("tbody tr").each(function(n,r){var i=e("
",{"class":"mc-tr"}),s="";e(r).find("td").each(function(t,n){s+='
',s+=e(n).html(),s+="
"}),i.append(s),t.append(i)}),t},t.prototype.construct.caption=function(){var e=this.$table.find("caption");return e.clone()},t.prototype.construct.toggleLink=function(){var t=this;return e("
",{href:"#","class":"mc-toggle-link",text:this.options.toggleText}).on("click",function(e){t.toggle(e)})},t.prototype.constructChart=function(){var e=this.construct.thead.call(this),t=this.construct.tbody.call(this),n=this.construct.toggleLink.call(this);if(this.options.hasCaption){var r=this.construct.caption.call(this);this.$graph.append(r)}this.$table.before(n),this.$graph.append(e),this.$graph.append(t)},t.prototype.apply=function(){this.ENABLED&&(this.constructChart(),this.addClassesToHeader(),this.calculateMaxWidth(),this.applyWidths(),this.insert(),this.$table.addClass("visually-hidden"),this.applyOutdent())},t.prototype.toggle=function(e){this.$graph.toggle(),this.$table.toggleClass("visually-hidden"),e&&e.preventDefault()},t.prototype.utils={isFloat:function(e){return!isNaN(parseFloat(e))},stripValue:function(e){var t=new RegExp("\\,|£|%|[a-z]","gi");return e.replace(t,"")},returnMax:function(e){var t=0;for(var n=0;nt&&(t=e[n]);return t},isNegative:function(e){return e<0}},t.prototype.addClassesToHeader=function(){var t=this.$graph.find(".mc-th").filter(":not(:first)");this.options.stacked&&(t.last().addClass("mc-stacked-header mc-header-total"),t=t.filter(":not(:last)")),t.addClass("mc-key-header").filter(":not(.mc-stacked-header)").each(function(t,n){e(n).addClass("mc-key-"+(t+1))})},t.prototype.calculateMaxWidth=function(){var t=this,n=[],r=0;this.$graph.find(".mc-tr").each(function(i,s){var o=e(s),u=o.find(".mc-td:not(:first)");if(t.options.stacked){var a=u.last().addClass("mc-stacked-total");u=u.filter(":not(:last)")}o.find(".mc-td:first").addClass("mc-key-cell");var f=0;u.each(function(i,s){var o=e(s).addClass("mc-bar-cell").addClass("mc-bar-"+(i+1)),u=t.utils.stripValue(o.text());if(t.utils.isFloat(u)){var a=parseFloat(u,10),l=Math.abs(a);a===0&&o.addClass("mc-bar-zero"),t.options.negative&&(t.utils.isNegative(a)?(o.addClass("mc-bar-negative"),l>r&&(r=l)):o.addClass("mc-bar-positive")),a=l,t.options.stacked?f+=a:(f=a,n.push(a))}}),t.options.stacked&&n.push(f)});var i={};return i.max=parseFloat(t.utils.returnMax(n),10),i.single=parseFloat(this.options.outOf/i.max,10),this.options.negative&&(i.marginLeft=parseFloat(r,10)*i.single,i.maxNegative=parseFloat(r,10)),i},t.prototype.applyWidths=function(){this.dimensions=this.calculateMaxWidth();var t=this;this.$graph.find(".mc-tr").each(function(n,r){var i=e(r),s=i.find(".mc-bar-cell:not(.mc-bar-zero)").length;i.find(".mc-bar-cell").each(function(n,r){var i=e(r),s=parseFloat(t.utils.stripValue(i.text()),10),o=s*t.dimensions.single,u=Math.abs(s),a=Math.abs(o);if(t.options.negative)if(i.hasClass("mc-bar-positive"))i.css("margin-left",t.dimensions.marginLeft+"%");else if(u"),i.css("width",a+"%")})})},t.prototype.insert=function(){this.$table.after(this.$graph)},t.prototype.applyOutdent=function(){var t=this,n=this.$graph.find(".mc-bar-cell");this.$graph.find(".mc-bar-cell").each(function(n,r){var i=e(r),s=parseFloat(t.utils.stripValue(i.text()),10),o=i.children("span"),u=o.width()+10,a=i.width(),f=parseFloat(i[0].style.width,10),l=i.height();t.options.stacked?u>a&&s>0&&i.addClass("mc-value-overflow"):(s===0&&i.addClass("mc-bar-outdented"),t.options.autoOutdent&&u>a||t.options.outdentAll?(i.addClass("mc-bar-outdented"),o.css({"margin-left":"100%",display:"inline-block"})):i.addClass("mc-bar-indented"))})},e.magnaCharta=function(e,n){return(new t).init(e,n)}})(jQuery); \ No newline at end of file diff --git a/spec/javascripts/govuk_publishing_components/lib/govspeak/magna-charta-spec.js b/spec/javascripts/govuk_publishing_components/lib/govspeak/magna-charta-spec.js new file mode 100644 index 0000000000..a0ffbed818 --- /dev/null +++ b/spec/javascripts/govuk_publishing_components/lib/govspeak/magna-charta-spec.js @@ -0,0 +1,378 @@ +/* eslint-env jasmine, jquery */ + +describe('Magna charta', function () { + 'use strict' + + var element + var magna + + // widths are 65/max * val (65 by default) + var cW = function (max, val, padding) { + padding = padding || 0 + var result = ((65 / max) * val + padding).toString() + // truncate the result to only 4 digits after the decimal place + // e.g. 27.0833333333 becomes 27.0833, 27.1 and 27 remain the same + var split = result.split('.') + if (split.length > 1) { + result = split[0] + '.' + split[1].substring(0, 4) + } + return result + '%' + } + + var single = + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
Single Table
Some DataValues
Testing One5
Testing Two4
Testing Three3
' + + var multiple = + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
Multiple Table
Some DataYESNOTotal
Testing One5611
Testing Two628
Testing Three3912
' + + var multiple2 = + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
Multiple Table
Some DataYESNOMAYBE
Testing One5611
Testing Two628
Testing Three3912
' + + var negative = + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
Some Data
Something Negative-5
Something Positive10
Something More Negative-10
Something Less Positive5
' + + var negative2 = + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
Some Data
Something Negative-5
Something Positive10
Something More Negative-10
Something Less Positive5
' + + var outdentAll = + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
Some Data
Something Negative-5
Something Positive10
Something More Negative-10
Something Less Positive5
' + + describe('creating a graph of a single table', function () { + beforeEach(function () { + element = $('
').attr('id', 'test-magna-charta').html(single) + $('body').append(element) + magna = $.magnaCharta(element.find('#single')) + }) + + afterEach(function () { + $('body').find('#test-magna-charta').remove() + }) + + it('creates a new div containing the chart', function () { + expect(magna.$graph.length).toEqual(1) + }) + + it('the new chart div has a class mc-chart', function () { + expect(magna.$graph).toHaveClass('mc-chart') + }) + + it('the new chart copies over any other classes', function () { + expect(magna.$graph).toHaveClass('no-key') + }) + + it('running toggle switches between chart and table', function () { + magna.toggle() + expect(magna.$table).not.toHaveClass('visually-hidden') + expect(magna.$graph.filter(':visible').length).toBe(0) + + // toggle it back + magna.toggle() + expect(magna.$table).toHaveClass('visually-hidden') + expect(magna.$graph.filter(':visible').length).toBe(1) + }) + + it('new chart div contains all table bits as divs', function () { + expect(magna.$graph.find('.mc-thead').length).toBe(1) + expect(magna.$graph.find('.mc-tr').length).toBe(4) + expect(magna.$graph.find('.mc-th').length).toBe(2) + expect(magna.$graph.find('.mc-td').length).toBe(6) + }) + + it('new chart divs contain the right values', function () { + var cells = magna.$graph.find('.mc-td') + expect(cells.eq(0).text()).toBe('Testing One') + expect(cells.eq(1).text()).toBe('5') + expect(magna.$graph.find('.mc-th').eq(0).text()).toBe('Some Data') + }) + + it('figures out the maximum graph value', function () { + var test = magna.calculateMaxWidth() + expect(test.max).toBe(parseFloat(5, 10)) + expect(test.single).toBe(parseFloat(65 / 5, 10)) + }) + + it('divs that are bars or keys are given correct classes', function () { + expect(magna.$graph.find('.mc-key-cell').length).toBe(3) + expect(magna.$graph.find('.mc-bar-cell').length).toBe(3) + }) + + it('bar cells have their values wrapped in a span tag', function () { + expect(magna.$graph.find('.mc-bar-cell span').length).toBe(3) + }) + + it('bars are given the correct width', function () { + var bars = magna.$graph.find('.mc-bar-cell') + expect(bars.get(0).style.width).toBe(cW(5, 5)) + expect(bars.get(1).style.width).toBe(cW(5, 4)) + expect(bars.get(2).style.width).toBe(cW(5, 3)) + }) + + it('new chart is inserted into DOM after table', function () { + expect(magna.$table.next()).toHaveClass('mc-chart') + }) + + it('bars are given classes to track what number they are', function () { + magna.$graph.find('.mc-bar-cell').each(function (i, item) { + expect($(item)).toHaveClass('mc-bar-1') + }) + }) + }) + + describe('creating a graph of a multiple table', function () { + beforeEach(function () { + element = $('
').attr('id', 'test-magna-charta').html(multiple2) + $('body').append(element) + magna = $.magnaCharta(element.find('#multiple2')) + }) + + afterEach(function () { + $('body').find('#test-magna-charta').remove() + }) + + it('the graph of a multiple table is given a class', function () { + expect(magna.$graph).toHaveClass('mc-multiple') + expect(magna.options.multiple).toBe(true) + }) + }) + + describe('creating a graph of a stacked table', function () { + beforeEach(function () { + element = $('
').attr('id', 'test-magna-charta').html(multiple) + $('body').append(element) + magna = $.magnaCharta(element.find('#multiple')) + }) + + afterEach(function () { + $('body').find('#test-magna-charta').remove() + }) + + it('having the class of mc-stacked sets stacked to true', function () { + expect(magna.options.stacked).toBe(true) + }) + + it('the cells that become bars are given the right classes', function () { + expect(magna.$graph.find('.mc-bar-cell').length).toBe(6) // bar cells + expect(magna.$graph.find('.mc-key-cell').length).toBe(3) // key cells + expect(magna.$graph.find('.mc-stacked-total').length).toBe(3) // total cells + }) + + it('header cells get the right values', function () { + var head = magna.$graph.find('.mc-thead') + expect(head.find('.mc-stacked-header').length).toBe(1) + expect(head.find('.mc-th').eq(1)).toHaveClass('mc-key-1') + expect(head.find('.mc-key-header').length).toBe(2) + }) + + it('the bar cells are given the right widths', function () { + var cells = magna.$graph.find('.mc-bar-cell') + expect(cells.get(0).style.width).toEqual(cW(12, 5)) + expect(cells.get(1).style.width).toEqual(cW(12, 6)) + expect(cells.get(2).style.width).toEqual(cW(12, 6)) + expect(cells.get(3).style.width).toEqual(cW(12, 2)) + expect(cells.get(4).style.width).toEqual(cW(12, 3)) + expect(cells.get(5).style.width).toEqual(cW(12, 9)) + }) + + it('the bar cells are given classes denoting their index', function () { + var rows = magna.$graph.find('.mc-tbody .mc-tr') + rows.each(function (_, row) { + var cells = $(row).find('.mc-bar-cell') + cells.each(function (i, cell) { + expect($(cell)).toHaveClass('mc-bar-' + (i + 1)) + }) + }) + }) + + it('calulateMaxWidth returns object with right max value in', function () { + var test = magna.calculateMaxWidth() + expect(test.max).toEqual(parseFloat(12, 10)) + expect(test.single).toEqual(parseFloat(65 / 12, 10)) + }) + }) + + describe('test applyOnInit', function () { + beforeEach(function () { + element = $('
').attr('id', 'test-magna-charta').html(negative2) + $('body').append(element) + magna = $.magnaCharta(element.find('#negative2'), { + applyOnInit: false + }) + }) + + afterEach(function () { + $('body').find('#test-magna-charta').remove() + }) + + it('doesnt show the chart initially', function () { + expect(magna.$graph.filter(':visible').length).toBe(0) + expect(element.find('#negative2')).not.toHaveClass('visually-hidden') + }) + + it('graph is shown when toggle is called', function () { + magna.toggle() + expect(magna.$graph.filter(':visible').length).toBe(1) + expect(element.find('#negative2')).toHaveClass('visually-hidden') + }) + }) + + describe('test negative', function () { + beforeEach(function () { + element = $('
').attr('id', 'test-magna-charta').html(negative) + $('body').append(element) + magna = $.magnaCharta(element.find('#negative')) + }) + + afterEach(function () { + $('body').find('#test-magna-charta').remove() + }) + + it('class mc-negative sets negative option to true', function () { + expect(magna.options.negative).toBe(true) + }) + + it('cells are given positive and negative classes', function () { + expect(magna.$graph.find('.mc-bar-negative').length).toBe(2) + expect(magna.$graph.find('.mc-bar-positive').length).toBe(2) + }) + + it('cells are given the right width', function () { + var cells = magna.$graph.find('.mc-bar-cell') + expect(cells.get(0).style.width).toEqual(cW(10, 5)) + expect(cells.get(1).style.width).toEqual(cW(10, 10)) + expect(cells.get(2).style.width).toEqual(cW(10, 10)) + expect(cells.get(3).style.width).toEqual(cW(10, 5)) + }) + + it('positive cells are given a left margin to align them with negative cells', function () { + var cells = magna.$graph.find('.mc-bar-positive') + expect(cells.get(0).style.marginLeft).toEqual(cW(10, 10)) + }) + + it('calculateMaxWidth() returns extra info on negative chart', function () { + var test = magna.calculateMaxWidth() + // Gives back extra info for the negative charts + expect(test.max).toEqual(parseFloat(10, 10)) + expect(test.single).toEqual(parseFloat(65 / 10, 10)) + expect(test.marginLeft).toEqual(parseFloat(10, 10) * parseFloat(65 / 10, 10)) + expect(test.maxNegative).toEqual(parseFloat(10, 10)) + }) + }) + + describe('test outdent all', function () { + beforeEach(function () { + element = $('
').attr('id', 'test-magna-charta').html(outdentAll) + $('body').append(element) + magna = $.magnaCharta(element.find('#outdent-all')) + }) + + afterEach(function () { + $('body').find('#test-magna-charta').remove() + }) + + it('all cell values are pushed left', function () { + magna.$graph.find('.mc-bar-cell span').each(function (i, item) { + expect(item.style.marginLeft).toBe('100%') + }) + }) + }) + + describe('test utils', function () { + beforeEach(function () { + element = $('
').attr('id', 'test-magna-charta').html(single) + $('body').append(element) + magna = $.magnaCharta(element.find('#single')) + }) + + afterEach(function () { + $('body').find('#test-magna-charta').remove() + }) + + it('utils.isFloat', function () { + expect(magna.utils.isFloat(4.56)).toBe(true) // 4.56 is a float + expect(magna.utils.isFloat(7)).toBe(true) // 7 is a float + expect(magna.utils.isFloat('hello')).not.toBe(true) // hello is not a float + expect(magna.utils.isFloat('hello1344')).not.toBe(true) // hello1344 is not a float + expect(magna.utils.isFloat('-4')).toBe(true) // -4 is a float + expect(magna.utils.isFloat('-4.56m')).toBe(true) // -4.56 is a float + }) + + it('utils.returnMax', function () { + expect(magna.utils.returnMax([5, 6, 7, 1])).toBe(7) + expect(magna.utils.returnMax([1, 2, 1, 6])).toBe(6) + expect(magna.utils.returnMax([2, 2, 1, 3])).toBe(3) + expect(magna.utils.returnMax([5, 4, 3])).toBe(5) + }) + + it('utils.stripValue', function () { + expect(magna.utils.stripValue('1.23m')).toBe('1.23') + expect(magna.utils.stripValue('£1.23m')).toBe('1.23') + expect(magna.utils.stripValue('0.56%')).toBe('0.56') + expect(magna.utils.stripValue('2,35m')).toBe('235') + }) + + it('utils.isNegative', function () { + expect(magna.utils.isNegative(4)).toBe(false) + expect(magna.utils.isNegative(-4)).toBe(true) + }) + }) +})