diff --git a/modules/backend/formwidgets/DataGrid.php b/modules/backend/formwidgets/DataGrid.php
index 030590784..249b7f0e3 100644
--- a/modules/backend/formwidgets/DataGrid.php
+++ b/modules/backend/formwidgets/DataGrid.php
@@ -65,6 +65,7 @@ class DataGrid extends FormWidgetBase
$this->vars['columnWidths'] = $this->getColumnWidths();
$this->vars['size'] = $this->size;
$this->vars['toolbarWidget'] = $this->makeToolbarWidget();
+ $this->vars['value'] = json_encode($this->model->{$this->columnName});
}
protected function makeToolbarWidget()
@@ -184,6 +185,6 @@ class DataGrid extends FormWidgetBase
*/
public function getSaveData($value)
{
- return $value;
+ return json_decode($value);
}
}
\ No newline at end of file
diff --git a/modules/backend/formwidgets/datagrid/assets/js/datagrid.js b/modules/backend/formwidgets/datagrid/assets/js/datagrid.js
index f9d90f716..83dfd2971 100644
--- a/modules/backend/formwidgets/datagrid/assets/js/datagrid.js
+++ b/modules/backend/formwidgets/datagrid/assets/js/datagrid.js
@@ -48,6 +48,27 @@
if (this.options.autoInsertRows)
handsontableOptions.minSpareRows = 1
+ if (this.options.dataLocker) {
+ /*
+ * Event to update the data locker
+ */
+ this.$dataLocker = $(this.options.dataLocker)
+ handsontableOptions.afterChange = function(changes, source) {
+ if (!self.gridInstance) return
+ self.$dataLocker.val(JSON.stringify(self.getData()))
+ }
+
+ /*
+ * Populate existing data
+ */
+ try {
+ var existingData = JSON.parse(this.$dataLocker.val())
+ if (existingData) handsontableOptions.data = existingData
+ } catch (e) {
+ delete handsontableOptions.data
+ }
+ }
+
this.$el.handsontable(handsontableOptions)
this.gridInstance = this.$el.handsontable('getInstance')
@@ -109,6 +130,7 @@
}
DataGrid.DEFAULTS = {
+ dataLocker: null,
startRows: 1,
minRows: 1,
autoInsertRows: false,
@@ -127,11 +149,18 @@
}
DataGrid.prototype.getData = function() {
- var results = [],
+ var self = this,
+ results = [],
dataArray = this.gridInstance.getData()
$.each(dataArray, function(index, object){
- results.push($.extend(true, {}, object))
+ var dataObj = {}
+
+ // Prune out unwanted array data
+ $.each(self.columns, function(index, column){
+ dataObj[column.data] = object[column.data]
+ })
+ results.push(dataObj)
})
return results
}
diff --git a/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/jquery.handsontable.js b/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/jquery.handsontable.js
index d4c418fd9..8b7ed63cb 100644
--- a/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/jquery.handsontable.js
+++ b/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/jquery.handsontable.js
@@ -10446,4 +10446,523 @@ if (!Array.prototype.filter) {
};
}
-})(jQuery, window, Handsontable);
\ No newline at end of file
+})(jQuery, window, Handsontable);
+
+// numeral.js
+// version : 1.4.7
+// author : Adam Draper
+// license : MIT
+// http://adamwdraper.github.com/Numeral-js/
+
+(function () {
+
+ /************************************
+ Constants
+ ************************************/
+
+ var numeral,
+ VERSION = '1.4.7',
+ // internal storage for language config files
+ languages = {},
+ currentLanguage = 'en',
+ zeroFormat = null,
+ // check for nodeJS
+ hasModule = (typeof module !== 'undefined' && module.exports);
+
+
+ /************************************
+ Constructors
+ ************************************/
+
+
+ // Numeral prototype object
+ function Numeral (number) {
+ this._n = number;
+ }
+
+ /**
+ * Implementation of toFixed() that treats floats more like decimals
+ *
+ * Fixes binary rounding issues (eg. (0.615).toFixed(2) === '0.61') that present
+ * problems for accounting- and finance-related software.
+ */
+ function toFixed (value, precision, optionals) {
+ var power = Math.pow(10, precision),
+ output;
+
+ // Multiply up by precision, round accurately, then divide and use native toFixed():
+ output = (Math.round(value * power) / power).toFixed(precision);
+
+ if (optionals) {
+ var optionalsRegExp = new RegExp('0{1,' + optionals + '}$');
+ output = output.replace(optionalsRegExp, '');
+ }
+
+ return output;
+ }
+
+ /************************************
+ Formatting
+ ************************************/
+
+ // determine what type of formatting we need to do
+ function formatNumeral (n, format) {
+ var output;
+
+ // figure out what kind of format we are dealing with
+ if (format.indexOf('$') > -1) { // currency!!!!!
+ output = formatCurrency(n, format);
+ } else if (format.indexOf('%') > -1) { // percentage
+ output = formatPercentage(n, format);
+ } else if (format.indexOf(':') > -1) { // time
+ output = formatTime(n, format);
+ } else { // plain ol' numbers or bytes
+ output = formatNumber(n, format);
+ }
+
+ // return string
+ return output;
+ }
+
+ // revert to number
+ function unformatNumeral (n, string) {
+ if (string.indexOf(':') > -1) {
+ n._n = unformatTime(string);
+ } else {
+ if (string === zeroFormat) {
+ n._n = 0;
+ } else {
+ var stringOriginal = string;
+ if (languages[currentLanguage].delimiters.decimal !== '.') {
+ string = string.replace(/\./g,'').replace(languages[currentLanguage].delimiters.decimal, '.');
+ }
+
+ // see if abbreviations are there so that we can multiply to the correct number
+ var thousandRegExp = new RegExp(languages[currentLanguage].abbreviations.thousand + '(?:\\)|(\\' + languages[currentLanguage].currency.symbol + ')?(?:\\))?)?$'),
+ millionRegExp = new RegExp(languages[currentLanguage].abbreviations.million + '(?:\\)|(\\' + languages[currentLanguage].currency.symbol + ')?(?:\\))?)?$'),
+ billionRegExp = new RegExp(languages[currentLanguage].abbreviations.billion + '(?:\\)|(\\' + languages[currentLanguage].currency.symbol + ')?(?:\\))?)?$'),
+ trillionRegExp = new RegExp(languages[currentLanguage].abbreviations.trillion + '(?:\\)|(\\' + languages[currentLanguage].currency.symbol + ')?(?:\\))?)?$');
+
+ // see if bytes are there so that we can multiply to the correct number
+ var prefixes = ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
+ bytesMultiplier = false;
+
+ for (var power = 0; power <= prefixes.length; power++) {
+ bytesMultiplier = (string.indexOf(prefixes[power]) > -1) ? Math.pow(1024, power + 1) : false;
+
+ if (bytesMultiplier) {
+ break;
+ }
+ }
+
+ // do some math to create our number
+ n._n = ((bytesMultiplier) ? bytesMultiplier : 1) * ((stringOriginal.match(thousandRegExp)) ? Math.pow(10, 3) : 1) * ((stringOriginal.match(millionRegExp)) ? Math.pow(10, 6) : 1) * ((stringOriginal.match(billionRegExp)) ? Math.pow(10, 9) : 1) * ((stringOriginal.match(trillionRegExp)) ? Math.pow(10, 12) : 1) * ((string.indexOf('%') > -1) ? 0.01 : 1) * Number(((string.indexOf('(') > -1) ? '-' : '') + string.replace(/[^0-9\.-]+/g, ''));
+
+ // round if we are talking about bytes
+ n._n = (bytesMultiplier) ? Math.ceil(n._n) : n._n;
+ }
+ }
+ return n._n;
+ }
+
+ function formatCurrency (n, format) {
+ var prependSymbol = (format.indexOf('$') <= 1) ? true : false;
+
+ // remove $ for the moment
+ var space = '';
+
+ // check for space before or after currency
+ if (format.indexOf(' $') > -1) {
+ space = ' ';
+ format = format.replace(' $', '');
+ } else if (format.indexOf('$ ') > -1) {
+ space = ' ';
+ format = format.replace('$ ', '');
+ } else {
+ format = format.replace('$', '');
+ }
+
+ // format the number
+ var output = formatNumeral(n, format);
+
+ // position the symbol
+ if (prependSymbol) {
+ if (output.indexOf('(') > -1 || output.indexOf('-') > -1) {
+ output = output.split('');
+ output.splice(1, 0, languages[currentLanguage].currency.symbol + space);
+ output = output.join('');
+ } else {
+ output = languages[currentLanguage].currency.symbol + space + output;
+ }
+ } else {
+ if (output.indexOf(')') > -1) {
+ output = output.split('');
+ output.splice(-1, 0, space + languages[currentLanguage].currency.symbol);
+ output = output.join('');
+ } else {
+ output = output + space + languages[currentLanguage].currency.symbol;
+ }
+ }
+
+ return output;
+ }
+
+ function formatPercentage (n, format) {
+ var space = '';
+ // check for space before %
+ if (format.indexOf(' %') > -1) {
+ space = ' ';
+ format = format.replace(' %', '');
+ } else {
+ format = format.replace('%', '');
+ }
+
+ n._n = n._n * 100;
+ var output = formatNumeral(n, format);
+ if (output.indexOf(')') > -1 ) {
+ output = output.split('');
+ output.splice(-1, 0, space + '%');
+ output = output.join('');
+ } else {
+ output = output + space + '%';
+ }
+ return output;
+ }
+
+ function formatTime (n, format) {
+ var hours = Math.floor(n._n/60/60),
+ minutes = Math.floor((n._n - (hours * 60 * 60))/60),
+ seconds = Math.round(n._n - (hours * 60 * 60) - (minutes * 60));
+ return hours + ':' + ((minutes < 10) ? '0' + minutes : minutes) + ':' + ((seconds < 10) ? '0' + seconds : seconds);
+ }
+
+ function unformatTime (string) {
+ var timeArray = string.split(':'),
+ seconds = 0;
+ // turn hours and minutes into seconds and add them all up
+ if (timeArray.length === 3) {
+ // hours
+ seconds = seconds + (Number(timeArray[0]) * 60 * 60);
+ // minutes
+ seconds = seconds + (Number(timeArray[1]) * 60);
+ // seconds
+ seconds = seconds + Number(timeArray[2]);
+ } else if (timeArray.lenght === 2) {
+ // minutes
+ seconds = seconds + (Number(timeArray[0]) * 60);
+ // seconds
+ seconds = seconds + Number(timeArray[1]);
+ }
+ return Number(seconds);
+ }
+
+ function formatNumber (n, format) {
+ var negP = false,
+ optDec = false,
+ abbr = '',
+ bytes = '',
+ ord = '',
+ abs = Math.abs(n._n);
+
+ // check if number is zero and a custom zero format has been set
+ if (n._n === 0 && zeroFormat !== null) {
+ return zeroFormat;
+ } else {
+ // see if we should use parentheses for negative number
+ if (format.indexOf('(') > -1) {
+ negP = true;
+ format = format.slice(1, -1);
+ }
+
+ // see if abbreviation is wanted
+ if (format.indexOf('a') > -1) {
+ // check for space before abbreviation
+ if (format.indexOf(' a') > -1) {
+ abbr = ' ';
+ format = format.replace(' a', '');
+ } else {
+ format = format.replace('a', '');
+ }
+
+ if (abs >= Math.pow(10, 12)) {
+ // trillion
+ abbr = abbr + languages[currentLanguage].abbreviations.trillion;
+ n._n = n._n / Math.pow(10, 12);
+ } else if (abs < Math.pow(10, 12) && abs >= Math.pow(10, 9)) {
+ // billion
+ abbr = abbr + languages[currentLanguage].abbreviations.billion;
+ n._n = n._n / Math.pow(10, 9);
+ } else if (abs < Math.pow(10, 9) && abs >= Math.pow(10, 6)) {
+ // million
+ abbr = abbr + languages[currentLanguage].abbreviations.million;
+ n._n = n._n / Math.pow(10, 6);
+ } else if (abs < Math.pow(10, 6) && abs >= Math.pow(10, 3)) {
+ // thousand
+ abbr = abbr + languages[currentLanguage].abbreviations.thousand;
+ n._n = n._n / Math.pow(10, 3);
+ }
+ }
+
+ // see if we are formatting bytes
+ if (format.indexOf('b') > -1) {
+ // check for space before
+ if (format.indexOf(' b') > -1) {
+ bytes = ' ';
+ format = format.replace(' b', '');
+ } else {
+ format = format.replace('b', '');
+ }
+
+ var prefixes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
+ min,
+ max;
+
+ for (var power = 0; power <= prefixes.length; power++) {
+ min = Math.pow(1024, power);
+ max = Math.pow(1024, power+1);
+
+ if (n._n >= min && n._n < max) {
+ bytes = bytes + prefixes[power];
+ if (min > 0) {
+ n._n = n._n / min;
+ }
+ break;
+ }
+ }
+ }
+
+ // see if ordinal is wanted
+ if (format.indexOf('o') > -1) {
+ // check for space before
+ if (format.indexOf(' o') > -1) {
+ ord = ' ';
+ format = format.replace(' o', '');
+ } else {
+ format = format.replace('o', '');
+ }
+
+ ord = ord + languages[currentLanguage].ordinal(n._n);
+ }
+
+ if (format.indexOf('[.]') > -1) {
+ optDec = true;
+ format = format.replace('[.]', '.');
+ }
+
+ var w = n._n.toString().split('.')[0],
+ precision = format.split('.')[1],
+ thousands = format.indexOf(','),
+ d = '',
+ neg = false;
+
+ if (precision) {
+ if (precision.indexOf('[') > -1) {
+ precision = precision.replace(']', '');
+ precision = precision.split('[');
+ d = toFixed(n._n, (precision[0].length + precision[1].length), precision[1].length);
+ } else {
+ d = toFixed(n._n, precision.length);
+ }
+
+ w = d.split('.')[0];
+
+ if (d.split('.')[1].length) {
+ d = languages[currentLanguage].delimiters.decimal + d.split('.')[1];
+ } else {
+ d = '';
+ }
+
+ if (optDec && Number(d) === 0) {
+ d = '';
+ }
+ } else {
+ w = toFixed(n._n, null);
+ }
+
+ // format number
+ if (w.indexOf('-') > -1) {
+ w = w.slice(1);
+ neg = true;
+ }
+
+ if (thousands > -1) {
+ w = w.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + languages[currentLanguage].delimiters.thousands);
+ }
+
+ if (format.indexOf('.') === 0) {
+ w = '';
+ }
+
+ return ((negP && neg) ? '(' : '') + ((!negP && neg) ? '-' : '') + w + d + ((ord) ? ord : '') + ((abbr) ? abbr : '') + ((bytes) ? bytes : '') + ((negP && neg) ? ')' : '');
+ }
+ }
+
+ /************************************
+ Top Level Functions
+ ************************************/
+
+ numeral = function (input) {
+ if (numeral.isNumeral(input)) {
+ input = input.value();
+ } else if (!Number(input)) {
+ input = 0;
+ }
+
+ return new Numeral(Number(input));
+ };
+
+ // version number
+ numeral.version = VERSION;
+
+ // compare numeral object
+ numeral.isNumeral = function (obj) {
+ return obj instanceof Numeral;
+ };
+
+ // This function will load languages and then set the global language. If
+ // no arguments are passed in, it will simply return the current global
+ // language key.
+ numeral.language = function (key, values) {
+ if (!key) {
+ return currentLanguage;
+ }
+
+ if (key && !values) {
+ currentLanguage = key;
+ }
+
+ if (values || !languages[key]) {
+ loadLanguage(key, values);
+ }
+
+ return numeral;
+ };
+
+ numeral.language('en', {
+ delimiters: {
+ thousands: ',',
+ decimal: '.'
+ },
+ abbreviations: {
+ thousand: 'k',
+ million: 'm',
+ billion: 'b',
+ trillion: 't'
+ },
+ ordinal: function (number) {
+ var b = number % 10;
+ return (~~ (number % 100 / 10) === 1) ? 'th' :
+ (b === 1) ? 'st' :
+ (b === 2) ? 'nd' :
+ (b === 3) ? 'rd' : 'th';
+ },
+ currency: {
+ symbol: '$'
+ }
+ });
+
+ numeral.zeroFormat = function (format) {
+ if (typeof(format) === 'string') {
+ zeroFormat = format;
+ } else {
+ zeroFormat = null;
+ }
+ };
+
+ /************************************
+ Helpers
+ ************************************/
+
+ function loadLanguage(key, values) {
+ languages[key] = values;
+ }
+
+
+ /************************************
+ Numeral Prototype
+ ************************************/
+
+
+ numeral.fn = Numeral.prototype = {
+
+ clone : function () {
+ return numeral(this);
+ },
+
+ format : function (inputString) {
+ return formatNumeral(this, inputString ? inputString : numeral.defaultFormat);
+ },
+
+ unformat : function (inputString) {
+ return unformatNumeral(this, inputString ? inputString : numeral.defaultFormat);
+ },
+
+ value : function () {
+ return this._n;
+ },
+
+ valueOf : function () {
+ return this._n;
+ },
+
+ set : function (value) {
+ this._n = Number(value);
+ return this;
+ },
+
+ add : function (value) {
+ this._n = this._n + Number(value);
+ return this;
+ },
+
+ subtract : function (value) {
+ this._n = this._n - Number(value);
+ return this;
+ },
+
+ multiply : function (value) {
+ this._n = this._n * Number(value);
+ return this;
+ },
+
+ divide : function (value) {
+ this._n = this._n / Number(value);
+ return this;
+ },
+
+ difference : function (value) {
+ var difference = this._n - Number(value);
+
+ if (difference < 0) {
+ difference = -difference;
+ }
+
+ return difference;
+ }
+
+ };
+
+ /************************************
+ Exposing Numeral
+ ************************************/
+
+ // CommonJS module is defined
+ if (hasModule) {
+ module.exports = numeral;
+ }
+
+ /*global ender:false */
+ if (typeof ender === 'undefined') {
+ // here, `this` means `window` in the browser, or `global` on the server
+ // add `numeral` as a global object via a string identifier,
+ // for Closure Compiler 'advanced' mode
+ this['numeral'] = numeral;
+ }
+
+ /*global define:false */
+ if (typeof define === 'function' && define.amd) {
+ define([], function () {
+ return numeral;
+ });
+ }
+}).call(this);
diff --git a/modules/backend/formwidgets/datagrid/partials/_datagrid.htm b/modules/backend/formwidgets/datagrid/partials/_datagrid.htm
index f53c12f86..33d16d8bc 100644
--- a/modules/backend/formwidgets/datagrid/partials/_datagrid.htm
+++ b/modules/backend/formwidgets/datagrid/partials/_datagrid.htm
@@ -9,8 +9,16 @@
style="width:100%"
class="control-datagrid"
data-control="datagrid"
+ data-data-locker="#= $this->getId('datalocker') ?>"
data-autocomplete-handler="= $this->getEventHandler('onAutocomplete') ?>"
>
+
+