From 5d0d7c56c2456ef83dbc060982160f1e136fa26d Mon Sep 17 00:00:00 2001 From: Manuel Date: Thu, 26 Jun 2014 16:33:16 +0200 Subject: [PATCH] Bumped backgrid.js to latest version (0.3.5) from https://www.npmjs.org/package/backgrid --- ajax/libs/backgrid.js/0.3.5/backgrid.css | 240 ++ ajax/libs/backgrid.js/0.3.5/backgrid.js | 2883 ++++++++++++++++++ ajax/libs/backgrid.js/0.3.5/backgrid.min.css | 1 + ajax/libs/backgrid.js/0.3.5/backgrid.min.js | 8 + ajax/libs/backgrid.js/package.json | 2 +- 5 files changed, 3133 insertions(+), 1 deletion(-) create mode 100644 ajax/libs/backgrid.js/0.3.5/backgrid.css create mode 100644 ajax/libs/backgrid.js/0.3.5/backgrid.js create mode 100644 ajax/libs/backgrid.js/0.3.5/backgrid.min.css create mode 100644 ajax/libs/backgrid.js/0.3.5/backgrid.min.js diff --git a/ajax/libs/backgrid.js/0.3.5/backgrid.css b/ajax/libs/backgrid.js/0.3.5/backgrid.css new file mode 100644 index 000000000..7eb59697f --- /dev/null +++ b/ajax/libs/backgrid.js/0.3.5/backgrid.css @@ -0,0 +1,240 @@ +/* + backgrid + http://github.com/wyuenho/backgrid + + Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors + Licensed under the MIT license. +*/ + +.backgrid-container { + position: relative; + display: block; + width: 100%; + height: 465px; + padding: 0; + overflow: auto; + border: 0; +} + +.backgrid { + width: 100%; + max-width: 100%; + background-color: transparent; + border-collapse: collapse; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.backgrid th, +.backgrid td { + display: none; + height: 20px; + max-width: 250px; + padding: 4px 5px; + overflow: hidden; + line-height: 20px; + text-align: left; + text-overflow: ellipsis; + white-space: nowrap; + vertical-align: middle; + border-bottom: 1px solid #DDD; +} + +.backgrid th.renderable, +.backgrid td.renderable { + display: table-cell; +} + +.backgrid th { + font-weight: bold; + text-align: center; +} + +.backgrid th.sortable a { + text-decoration: none; + white-space: nowrap; + cursor: pointer; +} + +.backgrid thead th { + vertical-align: bottom; + background-color: #f9f9f9; +} + +.backgrid thead th a { + display: block; +} + +.backgrid.backgrid-striped tbody tr:nth-child(even) { + background-color: #f9f9f9; +} + +.backgrid tbody tr.empty { + font-style: italic; + color: gray; +} + +.backgrid tbody tr.empty td { + display: inherit; + text-align: center; +} + +.backgrid td.editor { + padding: 0; +} + +.backgrid td.editor, +.backgrid tbody tr:nth-child(odd) td.editor { + background-color: rgba(82, 168, 236, 0.1); + outline: 1px solid rgba(82, 168, 236, 0.8); + outline-offset: -1px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition-duration: 200ms; + -moz-transition-duration: 200ms; + -o-transition-duration: 200ms; + transition-duration: 200ms; + -webkit-transition-property: width, outline, background-color; + -moz-transition-property: width, outline, background-color; + -o-transition-property: width, outline, background-color; + transition-property: width, outline, background-color; + -webkit-transition-timing-function: ease-in-out; + -moz-transition-timing-function: ease-in-out; + -o-transition-timing-function: ease-in-out; + transition-timing-function: ease-in-out; +} + +.backgrid td.editor input[type=text] { + display: block; + width: 100%; + height: 100%; + padding: 0 5px; + margin: 0; + background-color: transparent; + border: 0; + outline: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-appearance: none; + -moz-appearance: none; +} + +.backgrid td.editor input[type=text]::-ms-clear { + display: none; +} + +.backgrid td.error, +.backgrid tbody tr:nth-child(odd) td.error { + background-color: rgba(255, 210, 77, 0.1); + outline: 1px solid #ffd24d; +} + +.backgrid td.editor :focus, +.backgrid th.editor :focus { + outline: 0; +} + +.backgrid .sort-caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 0.3em; + border: 0; + content: ""; +} + +.backgrid .ascending .sort-caret { + vertical-align: baseline; + border-top: none; + border-right: 4px solid transparent; + border-bottom: 4px solid #000000; + border-left: 4px solid transparent; +} + +.backgrid .descending .sort-caret { + vertical-align: super; + border-top: 4px solid #000000; + border-right: 4px solid transparent; + border-bottom: none; + border-left: 4px solid transparent; +} + +.backgrid .string-cell, +.backgrid .uri-cell, +.backgrid .email-cell, +.backgrid .string-cell.editor input[type=text], +.backgrid .uri-cell.editor input[type=text], +.backgrid .email-cell.editor input[type=text] { + text-align: left; +} + +.backgrid .date-cell, +.backgrid .time-cell, +.backgrid .datetime-cell, +.backgrid .number-cell, +.backgrid .integer-cell, +.backgrid .percent-cell, +.backgrid .date-cell.editor input[type=text], +.backgrid .time-cell.editor input[type=text], +.backgrid .datetime-cell.editor input[type=text], +.backgrid .number-cell.editor input[type=text], +.backgrid .integer-cell.editor input[type=text], +.backgrid .percent-cell.editor input[type=text] { + text-align: right; +} + +.backgrid .boolean-cell, +.backgrid .boolean-cell.editor input[type=checkbox] { + text-align: center; +} + +.backgrid .select-cell { + text-align: center; +} + +.backgrid .select-cell.editor { + padding: 0; +} + +.backgrid .select-cell.editor select { + display: block; + width: 100%; + height: 28px; + padding: 4px 5px; + margin: 0; + line-height: 28px; + vertical-align: middle; + background-color: white; + border: 0; + outline: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.backgrid .select-cell.editor select[multiple] { + height: auto; +} + +.backgrid .select-cell.editor :focus { + border: 0; + outline: 0; +} + +.backgrid .select-cell.editor select::-moz-focus-inner, +.backgrid .select-cell.editor optgroup::-moz-focus-inner, +.backgrid .select-cell.editor option::-moz-focus-inner, +.backgrid .select-cell.editor select::-o-focus-inner, +.backgrid .select-cell.editor optgroup::-o-focus-inner, +.backgrid .select-cell.editor option::-o-focus-inner { + border: 0; +} \ No newline at end of file diff --git a/ajax/libs/backgrid.js/0.3.5/backgrid.js b/ajax/libs/backgrid.js/0.3.5/backgrid.js new file mode 100644 index 000000000..6f8da79e5 --- /dev/null +++ b/ajax/libs/backgrid.js/0.3.5/backgrid.js @@ -0,0 +1,2883 @@ +/*! + backgrid + http://github.com/wyuenho/backgrid + + Copyright (c) 2014 Jimmy Yuen Ho Wong and contributors + Licensed under the MIT license. +*/ + +(function (factory) { + + // CommonJS + if (typeof exports == "object") { + module.exports = factory(module.exports, + require("underscore"), + require("backbone")); + } + // Browser + else factory(this, this._, this.Backbone); +}(function (root, _, Backbone) { + + "use strict"; + +/* + backgrid + http://github.com/wyuenho/backgrid + + Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors + Licensed under the MIT license. +*/ + +// Copyright 2009, 2010 Kristopher Michael Kowal +// https://github.com/kriskowal/es5-shim +// ES5 15.5.4.20 +// http://es5.github.com/#x15.5.4.20 +var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" + + "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" + + "\u2029\uFEFF"; +if (!String.prototype.trim || ws.trim()) { + // http://blog.stevenlevithan.com/archives/faster-trim-javascript + // http://perfectionkills.com/whitespace-deviations/ + ws = "[" + ws + "]"; + var trimBeginRegexp = new RegExp("^" + ws + ws + "*"), + trimEndRegexp = new RegExp(ws + ws + "*$"); + String.prototype.trim = function trim() { + if (this === undefined || this === null) { + throw new TypeError("can't convert " + this + " to object"); + } + return String(this) + .replace(trimBeginRegexp, "") + .replace(trimEndRegexp, ""); + }; +} + +function lpad(str, length, padstr) { + var paddingLen = length - (str + '').length; + paddingLen = paddingLen < 0 ? 0 : paddingLen; + var padding = ''; + for (var i = 0; i < paddingLen; i++) { + padding = padding + padstr; + } + return padding + str; +} + +var $ = Backbone.$; + +var Backgrid = root.Backgrid = { + + Extension: {}, + + resolveNameToClass: function (name, suffix) { + if (_.isString(name)) { + var key = _.map(name.split('-'), function (e) { + return e.slice(0, 1).toUpperCase() + e.slice(1); + }).join('') + suffix; + var klass = Backgrid[key] || Backgrid.Extension[key]; + if (_.isUndefined(klass)) { + throw new ReferenceError("Class '" + key + "' not found"); + } + return klass; + } + + return name; + }, + + callByNeed: function () { + var value = arguments[0]; + if (!_.isFunction(value)) return value; + + var context = arguments[1]; + var args = [].slice.call(arguments, 2); + return value.apply(context, !!(args + '') ? args : []); + } + +}; +_.extend(Backgrid, Backbone.Events); + +/** + Command translates a DOM Event into commands that Backgrid + recognizes. Interested parties can listen on selected Backgrid events that + come with an instance of this class and act on the commands. + + It is also possible to globally rebind the keyboard shortcuts by replacing + the methods in this class' prototype. + + @class Backgrid.Command + @constructor + */ +var Command = Backgrid.Command = function (evt) { + _.extend(this, { + altKey: !!evt.altKey, + "char": evt["char"], + charCode: evt.charCode, + ctrlKey: !!evt.ctrlKey, + key: evt.key, + keyCode: evt.keyCode, + locale: evt.locale, + location: evt.location, + metaKey: !!evt.metaKey, + repeat: !!evt.repeat, + shiftKey: !!evt.shiftKey, + which: evt.which + }); +}; +_.extend(Command.prototype, { + /** + Up Arrow + + @member Backgrid.Command + */ + moveUp: function () { return this.keyCode == 38; }, + /** + Down Arrow + + @member Backgrid.Command + */ + moveDown: function () { return this.keyCode === 40; }, + /** + Shift Tab + + @member Backgrid.Command + */ + moveLeft: function () { return this.shiftKey && this.keyCode === 9; }, + /** + Tab + + @member Backgrid.Command + */ + moveRight: function () { return !this.shiftKey && this.keyCode === 9; }, + /** + Enter + + @member Backgrid.Command + */ + save: function () { return this.keyCode === 13; }, + /** + Esc + + @member Backgrid.Command + */ + cancel: function () { return this.keyCode === 27; }, + /** + None of the above. + + @member Backgrid.Command + */ + passThru: function () { + return !(this.moveUp() || this.moveDown() || this.moveLeft() || + this.moveRight() || this.save() || this.cancel()); + } +}); + +/* + backgrid + http://github.com/wyuenho/backgrid + + Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors + Licensed under the MIT license. +*/ + +/** + Just a convenient class for interested parties to subclass. + + The default Cell classes don't require the formatter to be a subclass of + Formatter as long as the fromRaw(rawData) and toRaw(formattedData) methods + are defined. + + @abstract + @class Backgrid.CellFormatter + @constructor +*/ +var CellFormatter = Backgrid.CellFormatter = function () {}; +_.extend(CellFormatter.prototype, { + + /** + Takes a raw value from a model and returns an optionally formatted string + for display. The default implementation simply returns the supplied value + as is without any type conversion. + + @member Backgrid.CellFormatter + @param {*} rawData + @param {Backbone.Model} model Used for more complicated formatting + @return {*} + */ + fromRaw: function (rawData, model) { + return rawData; + }, + + /** + Takes a formatted string, usually from user input, and returns a + appropriately typed value for persistence in the model. + + If the user input is invalid or unable to be converted to a raw value + suitable for persistence in the model, toRaw must return `undefined`. + + @member Backgrid.CellFormatter + @param {string} formattedData + @param {Backbone.Model} model Used for more complicated formatting + @return {*|undefined} + */ + toRaw: function (formattedData, model) { + return formattedData; + } + +}); + +/** + A floating point number formatter. Doesn't understand scientific notation at + the moment. + + @class Backgrid.NumberFormatter + @extends Backgrid.CellFormatter + @constructor + @throws {RangeError} If decimals < 0 or > 20. +*/ +var NumberFormatter = Backgrid.NumberFormatter = function (options) { + _.extend(this, this.defaults, options || {}); + + if (this.decimals < 0 || this.decimals > 20) { + throw new RangeError("decimals must be between 0 and 20"); + } +}; +NumberFormatter.prototype = new CellFormatter(); +_.extend(NumberFormatter.prototype, { + + /** + @member Backgrid.NumberFormatter + @cfg {Object} options + + @cfg {number} [options.decimals=2] Number of decimals to display. Must be an integer. + + @cfg {string} [options.decimalSeparator='.'] The separator to use when + displaying decimals. + + @cfg {string} [options.orderSeparator=','] The separator to use to + separator thousands. May be an empty string. + */ + defaults: { + decimals: 2, + decimalSeparator: '.', + orderSeparator: ',' + }, + + HUMANIZED_NUM_RE: /(\d)(?=(?:\d{3})+$)/g, + + /** + Takes a floating point number and convert it to a formatted string where + every thousand is separated by `orderSeparator`, with a `decimal` number of + decimals separated by `decimalSeparator`. The number returned is rounded + the usual way. + + @member Backgrid.NumberFormatter + @param {number} number + @param {Backbone.Model} model Used for more complicated formatting + @return {string} + */ + fromRaw: function (number, model) { + if (_.isNull(number) || _.isUndefined(number)) return ''; + + number = number.toFixed(~~this.decimals); + + var parts = number.split('.'); + var integerPart = parts[0]; + var decimalPart = parts[1] ? (this.decimalSeparator || '.') + parts[1] : ''; + + return integerPart.replace(this.HUMANIZED_NUM_RE, '$1' + this.orderSeparator) + decimalPart; + }, + + /** + Takes a string, possibly formatted with `orderSeparator` and/or + `decimalSeparator`, and convert it back to a number. + + @member Backgrid.NumberFormatter + @param {string} formattedData + @param {Backbone.Model} model Used for more complicated formatting + @return {number|undefined} Undefined if the string cannot be converted to + a number. + */ + toRaw: function (formattedData, model) { + formattedData = formattedData.trim(); + + if (formattedData === '') return null; + + var rawData = ''; + + var thousands = formattedData.split(this.orderSeparator); + for (var i = 0; i < thousands.length; i++) { + rawData += thousands[i]; + } + + var decimalParts = rawData.split(this.decimalSeparator); + rawData = ''; + for (var i = 0; i < decimalParts.length; i++) { + rawData = rawData + decimalParts[i] + '.'; + } + + if (rawData[rawData.length - 1] === '.') { + rawData = rawData.slice(0, rawData.length - 1); + } + + var result = (rawData * 1).toFixed(~~this.decimals) * 1; + if (_.isNumber(result) && !_.isNaN(result)) return result; + } + +}); + +/** + A number formatter that converts a floating point number, optionally + multiplied by a multiplier, to a percentage string and vice versa. + + @class Backgrid.PercentFormatter + @extends Backgrid.NumberFormatter + @constructor + @throws {RangeError} If decimals < 0 or > 20. + */ +var PercentFormatter = Backgrid.PercentFormatter = function () { + Backgrid.NumberFormatter.apply(this, arguments); +}; + +PercentFormatter.prototype = new Backgrid.NumberFormatter(), + +_.extend(PercentFormatter.prototype, { + + /** + @member Backgrid.PercentFormatter + @cfg {Object} options + + @cfg {number} [options.multiplier=1] The number used to multiply the model + value for display. + + @cfg {string} [options.symbol='%'] The symbol to append to the percentage + string. + */ + defaults: _.extend({}, NumberFormatter.prototype.defaults, { + multiplier: 1, + symbol: "%" + }), + + /** + Takes a floating point number, where the number is first multiplied by + `multiplier`, then converted to a formatted string like + NumberFormatter#fromRaw, then finally append `symbol` to the end. + + @member Backgrid.PercentFormatter + @param {number} rawValue + @param {Backbone.Model} model Used for more complicated formatting + @return {string} + */ + fromRaw: function (number, model) { + var args = [].slice.call(arguments, 1); + args.unshift(number * this.multiplier); + return (NumberFormatter.prototype.fromRaw.apply(this, args) || "0") + this.symbol; + }, + + /** + Takes a string, possibly appended with `symbol` and/or `decimalSeparator`, + and convert it back to a number for the model like NumberFormatter#toRaw, + and then dividing it by `multiplier`. + + @member Backgrid.PercentFormatter + @param {string} formattedData + @param {Backbone.Model} model Used for more complicated formatting + @return {number|undefined} Undefined if the string cannot be converted to + a number. + */ + toRaw: function (formattedValue, model) { + var tokens = formattedValue.split(this.symbol); + if (tokens && tokens[0] && tokens[1] === "" || tokens[1] == null) { + var rawValue = NumberFormatter.prototype.toRaw.call(this, tokens[0]); + if (_.isUndefined(rawValue)) return rawValue; + return rawValue / this.multiplier; + } + } + +}); + +/** + Formatter to converts between various datetime formats. + + This class only understands ISO-8601 formatted datetime strings and UNIX + offset (number of milliseconds since UNIX Epoch). See + Backgrid.Extension.MomentFormatter if you need a much more flexible datetime + formatter. + + @class Backgrid.DatetimeFormatter + @extends Backgrid.CellFormatter + @constructor + @throws {Error} If both `includeDate` and `includeTime` are false. +*/ +var DatetimeFormatter = Backgrid.DatetimeFormatter = function (options) { + _.extend(this, this.defaults, options || {}); + + if (!this.includeDate && !this.includeTime) { + throw new Error("Either includeDate or includeTime must be true"); + } +}; +DatetimeFormatter.prototype = new CellFormatter(); +_.extend(DatetimeFormatter.prototype, { + + /** + @member Backgrid.DatetimeFormatter + + @cfg {Object} options + + @cfg {boolean} [options.includeDate=true] Whether the values include the + date part. + + @cfg {boolean} [options.includeTime=true] Whether the values include the + time part. + + @cfg {boolean} [options.includeMilli=false] If `includeTime` is true, + whether to include the millisecond part, if it exists. + */ + defaults: { + includeDate: true, + includeTime: true, + includeMilli: false + }, + + DATE_RE: /^([+\-]?\d{4})-(\d{2})-(\d{2})$/, + TIME_RE: /^(\d{2}):(\d{2}):(\d{2})(\.(\d{3}))?$/, + ISO_SPLITTER_RE: /T|Z| +/, + + _convert: function (data, validate) { + if ((data + '').trim() === '') return null; + + var date, time = null; + if (_.isNumber(data)) { + var jsDate = new Date(data); + date = lpad(jsDate.getUTCFullYear(), 4, 0) + '-' + lpad(jsDate.getUTCMonth() + 1, 2, 0) + '-' + lpad(jsDate.getUTCDate(), 2, 0); + time = lpad(jsDate.getUTCHours(), 2, 0) + ':' + lpad(jsDate.getUTCMinutes(), 2, 0) + ':' + lpad(jsDate.getUTCSeconds(), 2, 0); + } + else { + data = data.trim(); + var parts = data.split(this.ISO_SPLITTER_RE) || []; + date = this.DATE_RE.test(parts[0]) ? parts[0] : ''; + time = date && parts[1] ? parts[1] : this.TIME_RE.test(parts[0]) ? parts[0] : ''; + } + + var YYYYMMDD = this.DATE_RE.exec(date) || []; + var HHmmssSSS = this.TIME_RE.exec(time) || []; + + if (validate) { + if (this.includeDate && _.isUndefined(YYYYMMDD[0])) return; + if (this.includeTime && _.isUndefined(HHmmssSSS[0])) return; + if (!this.includeDate && date) return; + if (!this.includeTime && time) return; + } + + var jsDate = new Date(Date.UTC(YYYYMMDD[1] * 1 || 0, + YYYYMMDD[2] * 1 - 1 || 0, + YYYYMMDD[3] * 1 || 0, + HHmmssSSS[1] * 1 || null, + HHmmssSSS[2] * 1 || null, + HHmmssSSS[3] * 1 || null, + HHmmssSSS[5] * 1 || null)); + + var result = ''; + + if (this.includeDate) { + result = lpad(jsDate.getUTCFullYear(), 4, 0) + '-' + lpad(jsDate.getUTCMonth() + 1, 2, 0) + '-' + lpad(jsDate.getUTCDate(), 2, 0); + } + + if (this.includeTime) { + result = result + (this.includeDate ? 'T' : '') + lpad(jsDate.getUTCHours(), 2, 0) + ':' + lpad(jsDate.getUTCMinutes(), 2, 0) + ':' + lpad(jsDate.getUTCSeconds(), 2, 0); + + if (this.includeMilli) { + result = result + '.' + lpad(jsDate.getUTCMilliseconds(), 3, 0); + } + } + + if (this.includeDate && this.includeTime) { + result += "Z"; + } + + return result; + }, + + /** + Converts an ISO-8601 formatted datetime string to a datetime string, date + string or a time string. The timezone is ignored if supplied. + + @member Backgrid.DatetimeFormatter + @param {string} rawData + @param {Backbone.Model} model Used for more complicated formatting + @return {string|null|undefined} ISO-8601 string in UTC. Null and undefined + values are returned as is. + */ + fromRaw: function (rawData, model) { + if (_.isNull(rawData) || _.isUndefined(rawData)) return ''; + return this._convert(rawData); + }, + + /** + Converts an ISO-8601 formatted datetime string to a datetime string, date + string or a time string. The timezone is ignored if supplied. This method + parses the input values exactly the same way as + Backgrid.Extension.MomentFormatter#fromRaw(), in addition to doing some + sanity checks. + + @member Backgrid.DatetimeFormatter + @param {string} formattedData + @param {Backbone.Model} model Used for more complicated formatting + @return {string|undefined} ISO-8601 string in UTC. Undefined if a date is + found when `includeDate` is false, or a time is found when `includeTime` is + false, or if `includeDate` is true and a date is not found, or if + `includeTime` is true and a time is not found. + */ + toRaw: function (formattedData, model) { + return this._convert(formattedData, true); + } + +}); + +/** + Formatter to convert any value to string. + + @class Backgrid.StringFormatter + @extends Backgrid.CellFormatter + @constructor + */ +var StringFormatter = Backgrid.StringFormatter = function () {}; +StringFormatter.prototype = new CellFormatter(); +_.extend(StringFormatter.prototype, { + /** + Converts any value to a string using Ecmascript's implicit type + conversion. If the given value is `null` or `undefined`, an empty string is + returned instead. + + @member Backgrid.StringFormatter + @param {*} rawValue + @param {Backbone.Model} model Used for more complicated formatting + @return {string} + */ + fromRaw: function (rawValue, model) { + if (_.isUndefined(rawValue) || _.isNull(rawValue)) return ''; + return rawValue + ''; + } +}); + +/** + Simple email validation formatter. + + @class Backgrid.EmailFormatter + @extends Backgrid.CellFormatter + @constructor + */ +var EmailFormatter = Backgrid.EmailFormatter = function () {}; +EmailFormatter.prototype = new CellFormatter(); +_.extend(EmailFormatter.prototype, { + /** + Return the input if it is a string that contains an '@' character and if + the strings before and after '@' are non-empty. If the input does not + validate, `undefined` is returned. + + @member Backgrid.EmailFormatter + @param {*} formattedData + @param {Backbone.Model} model Used for more complicated formatting + @return {string|undefined} + */ + toRaw: function (formattedData, model) { + var parts = formattedData.trim().split("@"); + if (parts.length === 2 && _.all(parts)) { + return formattedData; + } + } +}); + +/** + Formatter for SelectCell. + + If the type of a model value is not a string, it is expected that a subclass + of this formatter is provided to the SelectCell, with #toRaw overridden to + convert the string value returned from the DOM back to whatever value is + expected in the model. + + @class Backgrid.SelectFormatter + @extends Backgrid.CellFormatter + @constructor +*/ +var SelectFormatter = Backgrid.SelectFormatter = function () {}; +SelectFormatter.prototype = new CellFormatter(); +_.extend(SelectFormatter.prototype, { + + /** + Normalizes raw scalar or array values to an array. + + @member Backgrid.SelectFormatter + @param {*} rawValue + @param {Backbone.Model} model Used for more complicated formatting + @return {Array.<*>} + */ + fromRaw: function (rawValue, model) { + return _.isArray(rawValue) ? rawValue : rawValue != null ? [rawValue] : []; + } +}); + +/* + backgrid + http://github.com/wyuenho/backgrid + + Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors + Licensed under the MIT license. +*/ + +/** + Generic cell editor base class. Only defines an initializer for a number of + required parameters. + + @abstract + @class Backgrid.CellEditor + @extends Backbone.View +*/ +var CellEditor = Backgrid.CellEditor = Backbone.View.extend({ + + /** + Initializer. + + @param {Object} options + @param {Backgrid.CellFormatter} options.formatter + @param {Backgrid.Column} options.column + @param {Backbone.Model} options.model + + @throws {TypeError} If `formatter` is not a formatter instance, or when + `model` or `column` are undefined. + */ + initialize: function (options) { + this.formatter = options.formatter; + this.column = options.column; + if (!(this.column instanceof Column)) { + this.column = new Column(this.column); + } + + this.listenTo(this.model, "backgrid:editing", this.postRender); + }, + + /** + Post-rendering setup and initialization. Focuses the cell editor's `el` in + this default implementation. **Should** be called by Cell classes after + calling Backgrid.CellEditor#render. + */ + postRender: function (model, column) { + if (column == null || column.get("name") == this.column.get("name")) { + this.$el.focus(); + } + return this; + } + +}); + +/** + InputCellEditor the cell editor type used by most core cell types. This cell + editor renders a text input box as its editor. The input will render a + placeholder if the value is empty on supported browsers. + + @class Backgrid.InputCellEditor + @extends Backgrid.CellEditor +*/ +var InputCellEditor = Backgrid.InputCellEditor = CellEditor.extend({ + + /** @property */ + tagName: "input", + + /** @property */ + attributes: { + type: "text" + }, + + /** @property */ + events: { + "blur": "saveOrCancel", + "keydown": "saveOrCancel" + }, + + /** + Initializer. Removes this `el` from the DOM when a `done` event is + triggered. + + @param {Object} options + @param {Backgrid.CellFormatter} options.formatter + @param {Backgrid.Column} options.column + @param {Backbone.Model} options.model + @param {string} [options.placeholder] + */ + initialize: function (options) { + InputCellEditor.__super__.initialize.apply(this, arguments); + + if (options.placeholder) { + this.$el.attr("placeholder", options.placeholder); + } + }, + + /** + Renders a text input with the cell value formatted for display, if it + exists. + */ + render: function () { + var model = this.model; + this.$el.val(this.formatter.fromRaw(model.get(this.column.get("name")), model)); + return this; + }, + + /** + If the key pressed is `enter`, `tab`, `up`, or `down`, converts the value + in the editor to a raw value for saving into the model using the formatter. + + If the key pressed is `esc` the changes are undone. + + If the editor goes out of focus (`blur`) but the value is invalid, the + event is intercepted and cancelled so the cell remains in focus pending for + further action. The changes are saved otherwise. + + Triggers a Backbone `backgrid:edited` event from the model when successful, + and `backgrid:error` if the value cannot be converted. Classes listening to + the `error` event, usually the Cell classes, should respond appropriately, + usually by rendering some kind of error feedback. + + @param {Event} e + */ + saveOrCancel: function (e) { + + var formatter = this.formatter; + var model = this.model; + var column = this.column; + + var command = new Command(e); + var blurred = e.type === "blur"; + + if (command.moveUp() || command.moveDown() || command.moveLeft() || command.moveRight() || + command.save() || blurred) { + + e.preventDefault(); + e.stopPropagation(); + + var val = this.$el.val(); + var newValue = formatter.toRaw(val, model); + if (_.isUndefined(newValue)) { + model.trigger("backgrid:error", model, column, val); + } + else { + model.set(column.get("name"), newValue); + model.trigger("backgrid:edited", model, column, command); + } + } + // esc + else if (command.cancel()) { + // undo + e.stopPropagation(); + model.trigger("backgrid:edited", model, column, command); + } + }, + + postRender: function (model, column) { + if (column == null || column.get("name") == this.column.get("name")) { + // move the cursor to the end on firefox if text is right aligned + if (this.$el.css("text-align") === "right") { + var val = this.$el.val(); + this.$el.focus().val(null).val(val); + } + else this.$el.focus(); + } + return this; + } + +}); + +/** + The super-class for all Cell types. By default, this class renders a plain + table cell with the model value converted to a string using the + formatter. The table cell is clickable, upon which the cell will go into + editor mode, which is rendered by a Backgrid.InputCellEditor instance by + default. Upon encountering any formatting errors, this class will add an + `error` CSS class to the table cell. + + @abstract + @class Backgrid.Cell + @extends Backbone.View +*/ +var Cell = Backgrid.Cell = Backbone.View.extend({ + + /** @property */ + tagName: "td", + + /** + @property {Backgrid.CellFormatter|Object|string} [formatter=CellFormatter] + */ + formatter: CellFormatter, + + /** + @property {Backgrid.CellEditor} [editor=Backgrid.InputCellEditor] The + default editor for all cell instances of this class. This value must be a + class, it will be automatically instantiated upon entering edit mode. + + See Backgrid.CellEditor + */ + editor: InputCellEditor, + + /** @property */ + events: { + "click": "enterEditMode" + }, + + /** + Initializer. + + @param {Object} options + @param {Backbone.Model} options.model + @param {Backgrid.Column} options.column + + @throws {ReferenceError} If formatter is a string but a formatter class of + said name cannot be found in the Backgrid module. + */ + initialize: function (options) { + this.column = options.column; + if (!(this.column instanceof Column)) { + this.column = new Column(this.column); + } + + var column = this.column, model = this.model, $el = this.$el; + + var formatter = Backgrid.resolveNameToClass(column.get("formatter") || + this.formatter, "Formatter"); + + if (!_.isFunction(formatter.fromRaw) && !_.isFunction(formatter.toRaw)) { + formatter = new formatter(); + } + + this.formatter = formatter; + + this.editor = Backgrid.resolveNameToClass(this.editor, "CellEditor"); + + this.listenTo(model, "change:" + column.get("name"), function () { + if (!$el.hasClass("editor")) this.render(); + }); + + this.listenTo(model, "backgrid:error", this.renderError); + + this.listenTo(column, "change:editable change:sortable change:renderable", + function (column) { + var changed = column.changedAttributes(); + for (var key in changed) { + if (changed.hasOwnProperty(key)) { + $el.toggleClass(key, changed[key]); + } + } + }); + + if (Backgrid.callByNeed(column.editable(), column, model)) $el.addClass("editable"); + if (Backgrid.callByNeed(column.sortable(), column, model)) $el.addClass("sortable"); + if (Backgrid.callByNeed(column.renderable(), column, model)) $el.addClass("renderable"); + }, + + /** + Render a text string in a table cell. The text is converted from the + model's raw value for this cell's column. + */ + render: function () { + this.$el.empty(); + var model = this.model; + this.$el.text(this.formatter.fromRaw(model.get(this.column.get("name")), model)); + this.delegateEvents(); + return this; + }, + + /** + If this column is editable, a new CellEditor instance is instantiated with + its required parameters. An `editor` CSS class is added to the cell upon + entering edit mode. + + This method triggers a Backbone `backgrid:edit` event from the model when + the cell is entering edit mode and an editor instance has been constructed, + but before it is rendered and inserted into the DOM. The cell and the + constructed cell editor instance are sent as event parameters when this + event is triggered. + + When this cell has finished switching to edit mode, a Backbone + `backgrid:editing` event is triggered from the model. The cell and the + constructed cell instance are also sent as parameters in the event. + + When the model triggers a `backgrid:error` event, it means the editor is + unable to convert the current user input to an apprpriate value for the + model's column, and an `error` CSS class is added to the cell accordingly. + */ + enterEditMode: function () { + var model = this.model; + var column = this.column; + + var editable = Backgrid.callByNeed(column.editable(), column, model); + if (editable) { + + this.currentEditor = new this.editor({ + column: this.column, + model: this.model, + formatter: this.formatter + }); + + model.trigger("backgrid:edit", model, column, this, this.currentEditor); + + // Need to redundantly undelegate events for Firefox + this.undelegateEvents(); + this.$el.empty(); + this.$el.append(this.currentEditor.$el); + this.currentEditor.render(); + this.$el.addClass("editor"); + + model.trigger("backgrid:editing", model, column, this, this.currentEditor); + } + }, + + /** + Put an `error` CSS class on the table cell. + */ + renderError: function (model, column) { + if (column == null || column.get("name") == this.column.get("name")) { + this.$el.addClass("error"); + } + }, + + /** + Removes the editor and re-render in display mode. + */ + exitEditMode: function () { + this.$el.removeClass("error"); + this.currentEditor.remove(); + this.stopListening(this.currentEditor); + delete this.currentEditor; + this.$el.removeClass("editor"); + this.render(); + }, + + /** + Clean up this cell. + + @chainable + */ + remove: function () { + if (this.currentEditor) { + this.currentEditor.remove.apply(this.currentEditor, arguments); + delete this.currentEditor; + } + return Cell.__super__.remove.apply(this, arguments); + } + +}); + +/** + StringCell displays HTML escaped strings and accepts anything typed in. + + @class Backgrid.StringCell + @extends Backgrid.Cell +*/ +var StringCell = Backgrid.StringCell = Cell.extend({ + + /** @property */ + className: "string-cell", + + formatter: StringFormatter + +}); + +/** + UriCell renders an HTML `` anchor for the value and accepts URIs as user + input values. No type conversion or URL validation is done by the formatter + of this cell. Users who need URL validation are encourage to subclass UriCell + to take advantage of the parsing capabilities of the HTMLAnchorElement + available on HTML5-capable browsers or using a third-party library like + [URI.js](https://github.com/medialize/URI.js). + + @class Backgrid.UriCell + @extends Backgrid.Cell +*/ +var UriCell = Backgrid.UriCell = Cell.extend({ + + /** @property */ + className: "uri-cell", + + /** + @property {string} [title] The title attribute of the generated anchor. It + uses the display value formatted by the `formatter.fromRaw` by default. + */ + title: null, + + /** + @property {string} [target="_blank"] The target attribute of the generated + anchor. + */ + target: "_blank", + + initialize: function (options) { + UriCell.__super__.initialize.apply(this, arguments); + this.title = options.title || this.title; + this.target = options.target || this.target; + }, + + render: function () { + this.$el.empty(); + var rawValue = this.model.get(this.column.get("name")); + var formattedValue = this.formatter.fromRaw(rawValue, this.model); + this.$el.append($("", { + tabIndex: -1, + href: rawValue, + title: this.title || formattedValue, + target: this.target + }).text(formattedValue)); + this.delegateEvents(); + return this; + } + +}); + +/** + Like Backgrid.UriCell, EmailCell renders an HTML `` anchor for the + value. The `href` in the anchor is prefixed with `mailto:`. EmailCell will + complain if the user enters a string that doesn't contain the `@` sign. + + @class Backgrid.EmailCell + @extends Backgrid.StringCell +*/ +var EmailCell = Backgrid.EmailCell = StringCell.extend({ + + /** @property */ + className: "email-cell", + + formatter: EmailFormatter, + + render: function () { + this.$el.empty(); + var model = this.model; + var formattedValue = this.formatter.fromRaw(model.get(this.column.get("name")), model); + this.$el.append($("", { + tabIndex: -1, + href: "mailto:" + formattedValue, + title: formattedValue + }).text(formattedValue)); + this.delegateEvents(); + return this; + } + +}); + +/** + NumberCell is a generic cell that renders all numbers. Numbers are formatted + using a Backgrid.NumberFormatter. + + @class Backgrid.NumberCell + @extends Backgrid.Cell +*/ +var NumberCell = Backgrid.NumberCell = Cell.extend({ + + /** @property */ + className: "number-cell", + + /** + @property {number} [decimals=2] Must be an integer. + */ + decimals: NumberFormatter.prototype.defaults.decimals, + + /** @property {string} [decimalSeparator='.'] */ + decimalSeparator: NumberFormatter.prototype.defaults.decimalSeparator, + + /** @property {string} [orderSeparator=','] */ + orderSeparator: NumberFormatter.prototype.defaults.orderSeparator, + + /** @property {Backgrid.CellFormatter} [formatter=Backgrid.NumberFormatter] */ + formatter: NumberFormatter, + + /** + Initializes this cell and the number formatter. + + @param {Object} options + @param {Backbone.Model} options.model + @param {Backgrid.Column} options.column + */ + initialize: function (options) { + NumberCell.__super__.initialize.apply(this, arguments); + var formatter = this.formatter; + formatter.decimals = this.decimals; + formatter.decimalSeparator = this.decimalSeparator; + formatter.orderSeparator = this.orderSeparator; + } + +}); + +/** + An IntegerCell is just a Backgrid.NumberCell with 0 decimals. If a floating + point number is supplied, the number is simply rounded the usual way when + displayed. + + @class Backgrid.IntegerCell + @extends Backgrid.NumberCell +*/ +var IntegerCell = Backgrid.IntegerCell = NumberCell.extend({ + + /** @property */ + className: "integer-cell", + + /** + @property {number} decimals Must be an integer. + */ + decimals: 0 +}); + +/** + A PercentCell is another Backgrid.NumberCell that takes a floating number, + optionally multiplied by a multiplier and display it as a percentage. + + @class Backgrid.PercentCell + @extends Backgrid.NumberCell + */ +var PercentCell = Backgrid.PercentCell = NumberCell.extend({ + + /** @property */ + className: "percent-cell", + + /** @property {number} [multiplier=1] */ + multiplier: PercentFormatter.prototype.defaults.multiplier, + + /** @property {string} [symbol='%'] */ + symbol: PercentFormatter.prototype.defaults.symbol, + + /** @property {Backgrid.CellFormatter} [formatter=Backgrid.PercentFormatter] */ + formatter: PercentFormatter, + + /** + Initializes this cell and the percent formatter. + + @param {Object} options + @param {Backbone.Model} options.model + @param {Backgrid.Column} options.column + */ + initialize: function () { + PercentCell.__super__.initialize.apply(this, arguments); + var formatter = this.formatter; + formatter.multiplier = this.multiplier; + formatter.symbol = this.symbol; + } + +}); + +/** + DatetimeCell is a basic cell that accepts datetime string values in RFC-2822 + or W3C's subset of ISO-8601 and displays them in ISO-8601 format. For a much + more sophisticated date time cell with better datetime formatting, take a + look at the Backgrid.Extension.MomentCell extension. + + @class Backgrid.DatetimeCell + @extends Backgrid.Cell + + See: + + - Backgrid.Extension.MomentCell + - Backgrid.DatetimeFormatter +*/ +var DatetimeCell = Backgrid.DatetimeCell = Cell.extend({ + + /** @property */ + className: "datetime-cell", + + /** + @property {boolean} [includeDate=true] + */ + includeDate: DatetimeFormatter.prototype.defaults.includeDate, + + /** + @property {boolean} [includeTime=true] + */ + includeTime: DatetimeFormatter.prototype.defaults.includeTime, + + /** + @property {boolean} [includeMilli=false] + */ + includeMilli: DatetimeFormatter.prototype.defaults.includeMilli, + + /** @property {Backgrid.CellFormatter} [formatter=Backgrid.DatetimeFormatter] */ + formatter: DatetimeFormatter, + + /** + Initializes this cell and the datetime formatter. + + @param {Object} options + @param {Backbone.Model} options.model + @param {Backgrid.Column} options.column + */ + initialize: function (options) { + DatetimeCell.__super__.initialize.apply(this, arguments); + var formatter = this.formatter; + formatter.includeDate = this.includeDate; + formatter.includeTime = this.includeTime; + formatter.includeMilli = this.includeMilli; + + var placeholder = this.includeDate ? "YYYY-MM-DD" : ""; + placeholder += (this.includeDate && this.includeTime) ? "T" : ""; + placeholder += this.includeTime ? "HH:mm:ss" : ""; + placeholder += (this.includeTime && this.includeMilli) ? ".SSS" : ""; + + this.editor = this.editor.extend({ + attributes: _.extend({}, this.editor.prototype.attributes, this.editor.attributes, { + placeholder: placeholder + }) + }); + } + +}); + +/** + DateCell is a Backgrid.DatetimeCell without the time part. + + @class Backgrid.DateCell + @extends Backgrid.DatetimeCell +*/ +var DateCell = Backgrid.DateCell = DatetimeCell.extend({ + + /** @property */ + className: "date-cell", + + /** @property */ + includeTime: false + +}); + +/** + TimeCell is a Backgrid.DatetimeCell without the date part. + + @class Backgrid.TimeCell + @extends Backgrid.DatetimeCell +*/ +var TimeCell = Backgrid.TimeCell = DatetimeCell.extend({ + + /** @property */ + className: "time-cell", + + /** @property */ + includeDate: false + +}); + +/** + BooleanCellEditor renders a checkbox as its editor. + + @class Backgrid.BooleanCellEditor + @extends Backgrid.CellEditor +*/ +var BooleanCellEditor = Backgrid.BooleanCellEditor = CellEditor.extend({ + + /** @property */ + tagName: "input", + + /** @property */ + attributes: { + tabIndex: -1, + type: "checkbox" + }, + + /** @property */ + events: { + "mousedown": function () { + this.mouseDown = true; + }, + "blur": "enterOrExitEditMode", + "mouseup": function () { + this.mouseDown = false; + }, + "change": "saveOrCancel", + "keydown": "saveOrCancel" + }, + + /** + Renders a checkbox and check it if the model value of this column is true, + uncheck otherwise. + */ + render: function () { + var model = this.model; + var val = this.formatter.fromRaw(model.get(this.column.get("name")), model); + this.$el.prop("checked", val); + return this; + }, + + /** + Event handler. Hack to deal with the case where `blur` is fired before + `change` and `click` on a checkbox. + */ + enterOrExitEditMode: function (e) { + if (!this.mouseDown) { + var model = this.model; + model.trigger("backgrid:edited", model, this.column, new Command(e)); + } + }, + + /** + Event handler. Save the value into the model if the event is `change` or + one of the keyboard navigation key presses. Exit edit mode without saving + if `escape` was pressed. + */ + saveOrCancel: function (e) { + var model = this.model; + var column = this.column; + var formatter = this.formatter; + var command = new Command(e); + // skip ahead to `change` when space is pressed + if (command.passThru() && e.type != "change") return true; + if (command.cancel()) { + e.stopPropagation(); + model.trigger("backgrid:edited", model, column, command); + } + + var $el = this.$el; + if (command.save() || command.moveLeft() || command.moveRight() || command.moveUp() || + command.moveDown()) { + e.preventDefault(); + e.stopPropagation(); + var val = formatter.toRaw($el.prop("checked"), model); + model.set(column.get("name"), val); + model.trigger("backgrid:edited", model, column, command); + } + else if (e.type == "change") { + var val = formatter.toRaw($el.prop("checked"), model); + model.set(column.get("name"), val); + $el.focus(); + } + } + +}); + +/** + BooleanCell renders a checkbox both during display mode and edit mode. The + checkbox is checked if the model value is true, unchecked otherwise. + + @class Backgrid.BooleanCell + @extends Backgrid.Cell +*/ +var BooleanCell = Backgrid.BooleanCell = Cell.extend({ + + /** @property */ + className: "boolean-cell", + + /** @property */ + editor: BooleanCellEditor, + + /** @property */ + events: { + "click": "enterEditMode" + }, + + /** + Renders a checkbox and check it if the model value of this column is true, + uncheck otherwise. + */ + render: function () { + this.$el.empty(); + var model = this.model, column = this.column; + var editable = Backgrid.callByNeed(column.editable(), column, model); + this.$el.append($("", { + tabIndex: -1, + type: "checkbox", + checked: this.formatter.fromRaw(model.get(column.get("name")), model), + disabled: !editable + })); + this.delegateEvents(); + return this; + } + +}); + +/** + SelectCellEditor renders an HTML `",{tabIndex:-1,type:"checkbox",checked:this.formatter.fromRaw(a.get(b.get("name")),a),disabled:!c})),this.delegateEvents(),this}}),i.SelectCellEditor=r.extend({tagName:"select",events:{change:"save",blur:"close",keydown:"close"},template:b.template('',null,{variable:null}),setOptionValues:function(a){this.optionValues=a,this.optionValues=b.result(this,"optionValues")},setMultiple:function(a){this.multiple=a,this.$el.prop("multiple",a)},_renderOptions:function(a,c){for(var d="",e=0;e-1});return d},render:function(){this.$el.empty();var a=b.result(this,"optionValues"),c=this.model,d=this.formatter.fromRaw(c.get(this.column.get("name")),c);if(!b.isArray(a))throw new TypeError("optionValues must be an array");for(var e=null,f=null,e=null,g=null,i=null,j=0;j-1}));else{if(!b.isObject(e))throw new TypeError("optionValues elements must be a name-value pair or an object hash of { name: 'optgroup label', value: [option name-value pairs] }");g=e.name,i=h("",{label:g}),i.append(this._renderOptions.call(this,e.values,d)),this.$el.append(i)}}return this.delegateEvents(),this},save:function(){var a=this.model,b=this.column;a.set(b.get("name"),this.formatter.toRaw(this.$el.val(),a))},close:function(a){var b=this.model,c=this.column,d=new j(a);d.cancel()?(a.stopPropagation(),b.trigger("backgrid:edited",b,c,new j(a))):(d.save()||d.moveLeft()||d.moveRight()||d.moveUp()||d.moveDown()||"blur"==a.type)&&(a.preventDefault(),a.stopPropagation(),this.save(a),b.trigger("backgrid:edited",b,c,new j(a)))}})),B=i.SelectCell=t.extend({className:"select-cell",editor:A,multiple:!1,formatter:q,optionValues:void 0,delimiter:", ",initialize:function(){B.__super__.initialize.apply(this,arguments),this.listenTo(this.model,"backgrid:edit",function(a,b,c,d){b.get("name")==this.column.get("name")&&(d.setOptionValues(this.optionValues),d.setMultiple(this.multiple))})},render:function(){this.$el.empty();var a=b.result(this,"optionValues"),c=this.model,d=this.formatter.fromRaw(c.get(this.column.get("name")),c),e=[];try{if(!b.isArray(a)||b.isEmpty(a))throw new TypeError;for(var f=0;f|Array.<{name: string, values: Array.}>}");throw n}return this.delegateEvents(),this}}),C=i.Column=c.Model.extend({defaults:{name:void 0,label:void 0,sortable:!0,editable:!0,renderable:!0,formatter:void 0,sortType:"cycle",sortValue:void 0,direction:null,cell:void 0,headerCell:void 0},initialize:function(){this.has("label")||this.set({label:this.get("name")},{silent:!0});var a=i.resolveNameToClass(this.get("headerCell"),"HeaderCell"),b=i.resolveNameToClass(this.get("cell"),"Cell");this.set({cell:b,headerCell:a},{silent:!0})},sortValue:function(){var a=this.get("sortValue");return b.isString(a)?this[a]:b.isFunction(a)?a:function(a,b){return a.get(b)}}});b.each(["sortable","renderable","editable"],function(a){C.prototype[a]=function(){var c=this.get(a);return b.isString(c)?this[c]:b.isFunction(c)?c:!!c}});{var D=i.Columns=c.Collection.extend({model:C}),E=i.Row=c.View.extend({tagName:"tr",initialize:function(a){var b=this.columns=a.columns;b instanceof c.Collection||(b=this.columns=new D(b));for(var d=this.cells=[],e=0;e").text(b.get("label")).append(""):document.createTextNode(b.get("label")),this.$el.append(a),this.$el.addClass(b.get("name")),this.$el.addClass(b.get("direction")),this.delegateEvents(),this}}),H=(i.HeaderRow=i.Row.extend({requiredOptions:["columns","collection"],initialize:function(){i.Row.prototype.initialize.apply(this,arguments)},makeCell:function(a,b){var c=a.get("headerCell")||b.headerCell||G;return c=new c({column:a,collection:this.collection})}}),i.Header=c.View.extend({tagName:"thead",initialize:function(a){this.columns=a.columns,this.columns instanceof c.Collection||(this.columns=new D(this.columns)),this.row=new i.HeaderRow({columns:this.columns,collection:this.collection})},render:function(){return this.$el.append(this.row.render().$el),this.delegateEvents(),this},remove:function(){return this.row.remove.apply(this.row,arguments),c.View.prototype.remove.apply(this,arguments)}})),I=i.Body=c.View.extend({tagName:"tbody",initialize:function(a){this.columns=a.columns,this.columns instanceof c.Collection||(this.columns=new D(this.columns)),this.row=a.row||E,this.rows=this.collection.map(function(a){var b=new this.row({columns:this.columns,model:a});return b},this),this.emptyText=a.emptyText,this._unshiftEmptyRowMayBe();var b=this.collection;this.listenTo(b,"add",this.insertRow),this.listenTo(b,"remove",this.removeRow),this.listenTo(b,"sort",this.refresh),this.listenTo(b,"reset",this.refresh),this.listenTo(b,"backgrid:sort",this.sort),this.listenTo(b,"backgrid:edited",this.moveToNextCell)},_unshiftEmptyRowMayBe:function(){0===this.rows.length&&null!=this.emptyText&&this.rows.unshift(new F({emptyText:this.emptyText,columns:this.columns}))},insertRow:function(a,b,d){if(this.rows[0]instanceof F&&this.rows.pop().remove(),!(b instanceof c.Collection||d))return void this.collection.add(a,d=b);var e=new this.row({columns:this.columns,model:a}),f=b.indexOf(a);this.rows.splice(f,0,e);var g=this.$el,h=g.children(),i=e.render().$el;return f>=h.length?g.append(i):h.eq(f).before(i),this},removeRow:function(a,c,d){return d?((b.isUndefined(d.render)||d.render)&&this.rows[d.index].remove(),this.rows.splice(d.index,1),this._unshiftEmptyRowMayBe(),this):(this.collection.remove(a,d=c),void this._unshiftEmptyRowMayBe())},refresh:function(){for(var a=0;ag?-1:1}},moveToNextCell:function(a,b,c){var d,e,f,g,h,j=this.collection.indexOf(a),k=this.columns.indexOf(b);if(this.rows[j].cells[k].exitEditMode(),c.moveUp()||c.moveDown()||c.moveLeft()||c.moveRight()||c.save()){var l=this.columns.length,m=l*this.collection.length;if(c.moveUp()||c.moveDown()){g=j+(c.moveUp()?-1:1);var n=this.rows[g];n?(d=n.cells[k],i.callByNeed(d.column.editable(),d.column,a)&&(d.enterEditMode(),a.trigger("backgrid:next",g,k,!1))):a.trigger("backgrid:next",g,k,!0)}else if(c.moveLeft()||c.moveRight()){for(var o=c.moveRight(),p=j*l+k+(o?1:-1);p>=0&&m>p;o?p++:p--)if(g=~~(p/l),h=p-g*l,d=this.rows[g].cells[h],e=i.callByNeed(d.column.renderable(),d.column,d.model),f=i.callByNeed(d.column.editable(),d.column,a),e&&f){d.enterEditMode(),a.trigger("backgrid:next",g,h,!1);break}p==m&&a.trigger("backgrid:next",~~(p/l),p-g*l,!0)}}return this}});i.Footer=c.View.extend({tagName:"tfoot",initialize:function(a){this.columns=a.columns,this.columns instanceof c.Collection||(this.columns=new i.Columns(this.columns))}}),i.Grid=c.View.extend({tagName:"table",className:"backgrid",header:H,body:I,footer:null,initialize:function(a){a.columns instanceof c.Collection||(a.columns=new D(a.columns)),this.columns=a.columns;var d=b.omit(a,["el","id","attributes","className","tagName","events"]);this.body=a.body||this.body,this.body=new this.body(d),this.header=a.header||this.header,this.header&&(this.header=new this.header(d)),this.footer=a.footer||this.footer,this.footer&&(this.footer=new this.footer(d)),this.listenTo(this.columns,"reset",function(){this.header&&(this.header=new(this.header.remove().constructor)(d)),this.body=new(this.body.remove().constructor)(d),this.footer&&(this.footer=new(this.footer.remove().constructor)(d)),this.render()})},insertRow:function(){return this.body.insertRow.apply(this.body,arguments),this},removeRow:function(){return this.body.removeRow.apply(this.body,arguments),this},insertColumn:function(){return this.columns.add.apply(this.columns,arguments),this},removeColumn:function(){return this.columns.remove.apply(this.columns,arguments),this},sort:function(){return this.body.sort.apply(this.body,arguments),this},render:function(){return this.$el.empty(),this.header&&this.$el.append(this.header.render().$el),this.footer&&this.$el.append(this.footer.render().$el),this.$el.append(this.body.render().$el),this.delegateEvents(),this.trigger("backgrid:rendered",this),this},remove:function(){return this.header&&this.header.remove.apply(this.header,arguments),this.body.remove.apply(this.body,arguments),this.footer&&this.footer.remove.apply(this.footer,arguments),c.View.prototype.remove.apply(this,arguments)}})}return i}); \ No newline at end of file diff --git a/ajax/libs/backgrid.js/package.json b/ajax/libs/backgrid.js/package.json index d406dd692..d938d35e6 100644 --- a/ajax/libs/backgrid.js/package.json +++ b/ajax/libs/backgrid.js/package.json @@ -1,7 +1,7 @@ { "name": "backgrid.js", "filename": "backgrid.js", - "version": "0.2.6", + "version": "0.3.5", "description": "Backgrid.js is a set of components for building semantic and easily stylable data grid widgets. It offers a simple, intuitive programming interface that makes easy things easy, but hard things possible when dealing with tabular data.", "homepage": "http://backgridjs.com/", "keywords": [