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 Data | Values | ' +
+ '' +
+ '' +
+ 'Testing One | 5 | ' +
+ 'Testing Two | 4 | ' +
+ 'Testing Three | 3 | ' +
+ '' +
+ ' '
+
+ var multiple =
+ '' +
+ 'Multiple Table' +
+ '' +
+ 'Some Data | YES | NO | Total | ' +
+ '' +
+ '' +
+ 'Testing One | 5 | 6 | 11 | ' +
+ 'Testing Two | 6 | 2 | 8 | ' +
+ 'Testing Three | 3 | 9 | 12 | ' +
+ '' +
+ ' '
+
+ var multiple2 =
+ '' +
+ 'Multiple Table' +
+ '' +
+ 'Some Data | YES | NO | MAYBE | ' +
+ '' +
+ '' +
+ 'Testing One | 5 | 6 | 11 | ' +
+ 'Testing Two | 6 | 2 | 8 | ' +
+ 'Testing Three | 3 | 9 | 12 | ' +
+ '' +
+ ' '
+
+ var negative =
+ '' +
+ '' +
+ 'Some Data | | ' +
+ '' +
+ '' +
+ 'Something Negative | -5 | ' +
+ 'Something Positive | 10 | ' +
+ 'Something More Negative | -10 | ' +
+ 'Something Less Positive | 5 | ' +
+ '' +
+ ' '
+
+ var negative2 =
+ '' +
+ '' +
+ 'Some Data | | ' +
+ '' +
+ '' +
+ 'Something Negative | -5 | ' +
+ 'Something Positive | 10 | ' +
+ 'Something More Negative | -10 | ' +
+ 'Something Less Positive | 5 | ' +
+ '' +
+ ' '
+
+ var outdentAll =
+ '' +
+ '' +
+ 'Some Data | | ' +
+ '' +
+ '' +
+ 'Something Negative | -5 | ' +
+ 'Something Positive | 10 | ' +
+ 'Something More Negative | -10 | ' +
+ 'Something Less Positive | 5 | ' +
+ '' +
+ ' '
+
+ 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)
+ })
+ })
+})
|