/ *
backgrid
http : //github.com/wyuenho/backgrid
Copyright ( c ) 2013 Jimmy Yuen Ho Wong and contributors
Licensed under the MIT @ license .
* /
( 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 .
* /
var window = root ;
// 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 capitalize ( s ) {
return s . charAt ( 0 ) . toUpperCase ( ) + s . slice ( 1 ) ;
// return String.fromCharCode(s.charCodeAt(0) - 32) + s.slice(1);
}
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 Backgrid = root . Backgrid = {
VERSION : "0.2.6" ,
Extension : { } ,
requireOptions : function ( options , requireOptionKeys ) {
for ( var i = 0 ; i < requireOptionKeys . length ; i ++ ) {
var key = requireOptionKeys [ i ] ;
if ( _ . isUndefined ( options [ key ] ) ) {
throw new TypeError ( "'" + key + "' is required" ) ;
}
}
} ,
resolveNameToClass : function ( name , suffix ) {
if ( _ . isString ( name ) ) {
var key = _ . map ( name . split ( '-' ) , function ( e ) { return capitalize ( e ) ; } ) . join ( '' ) + suffix ;
var klass = Backgrid [ key ] || Backgrid . Extension [ key ] ;
if ( _ . isUndefined ( klass ) ) {
throw new ReferenceError ( "Class '" + key + "' not found" ) ;
}
return klass ;
}
return name ;
}
} ;
_ . 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
@ return { * }
* /
fromRaw : function ( rawData ) {
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
@ return { * | undefined }
* /
toRaw : function ( formattedData ) {
return formattedData ;
}
} ) ;
/ * *
A floating point number formatter . Doesn ' t understand notation at the moment .
@ class Backgrid . NumberFormatter
@ extends Backgrid . CellFormatter
@ constructor
@ throws { RangeError } If decimals < 0 or > 20.
* /
var NumberFormatter = Backgrid . NumberFormatter = function ( options ) {
options = options ? _ . clone ( 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
@ return { string }
* /
fromRaw : function ( number ) {
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
@ return { number | undefined } Undefined if the string cannot be converted to
a number .
* /
toRaw : function ( formattedData ) {
var rawData = '' ;
var thousands = formattedData . trim ( ) . 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 ;
}
} ) ;
/ * *
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 ) {
options = options ? _ . clone ( 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 ) {
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
@ return { string | null | undefined } ISO - 8601 string in UTC . Null and undefined
values are returned as is .
* /
fromRaw : function ( rawData ) {
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
@ 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 ) {
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
@ return { string }
* /
fromRaw : function ( rawValue ) {
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
@ return { string | undefined }
* /
toRaw : function ( formattedData ) {
var parts = formattedData . trim ( ) . split ( "@" ) ;
if ( parts . length === 2 && _ . all ( parts ) ) {
return formattedData ;
}
}
} ) ;
/ * *
Formatter for SelectCell .
@ 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
@ return { Array . < * > }
* /
fromRaw : function ( rawValue ) {
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 ) {
Backgrid . requireOptions ( options , [ "formatter" , "column" , "model" ] ) ;
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 ) {
CellEditor . prototype . 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 ( ) {
this . $el . val ( this . formatter . fromRaw ( this . model . get ( this . column . get ( "name" ) ) ) ) ;
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 ) ;
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 = new CellFormatter ( ) ]
* /
formatter : new 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 ) {
Backgrid . requireOptions ( options , [ "model" , "column" ] ) ;
this . column = options . column ;
if ( ! ( this . column instanceof Column ) ) {
this . column = new Column ( this . column ) ;
}
this . formatter = Backgrid . resolveNameToClass ( this . column . get ( "formatter" ) || this . formatter , "Formatter" ) ;
this . editor = Backgrid . resolveNameToClass ( this . editor , "CellEditor" ) ;
this . listenTo ( this . model , "change:" + this . column . get ( "name" ) , function ( ) {
if ( ! this . $el . hasClass ( "editor" ) ) this . render ( ) ;
} ) ;
this . listenTo ( this . model , "backgrid:error" , this . renderError ) ;
} ,
/ * *
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 ( ) ;
this . $el . text ( this . formatter . fromRaw ( this . model . get ( this . column . get ( "name" ) ) ) ) ;
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 ;
if ( column . get ( "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 , arguments ) ;
delete this . currentEditor ;
}
return Backbone . View . prototype . 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 : new StringFormatter ( )
} ) ;
/ * *
UriCell renders an HTML ` <a> ` 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" ,
render : function ( ) {
this . $el . empty ( ) ;
var formattedValue = this . formatter . fromRaw ( this . model . get ( this . column . get ( "name" ) ) ) ;
this . $el . append ( $ ( "<a>" , {
tabIndex : - 1 ,
href : formattedValue ,
title : formattedValue ,
target : "_blank"
} ) . text ( formattedValue ) ) ;
this . delegateEvents ( ) ;
return this ;
}
} ) ;
/ * *
Like Backgrid . UriCell , EmailCell renders an HTML ` <a> ` 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 : new EmailFormatter ( ) ,
render : function ( ) {
this . $el . empty ( ) ;
var formattedValue = this . formatter . fromRaw ( this . model . get ( this . column . get ( "name" ) ) ) ;
this . $el . append ( $ ( "<a>" , {
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 ) {
Cell . prototype . initialize . apply ( this , arguments ) ;
this . formatter = new this . formatter ( {
decimals : this . decimals ,
decimalSeparator : this . decimalSeparator ,
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
} ) ;
/ * *
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 ) {
Cell . prototype . initialize . apply ( this , arguments ) ;
this . formatter = new this . formatter ( {
includeDate : this . includeDate ,
includeTime : this . includeTime ,
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 val = this . formatter . fromRaw ( this . model . get ( this . column . get ( "name" ) ) ) ;
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 . 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 . 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 ( ) ;
this . $el . append ( $ ( "<input>" , {
tabIndex : - 1 ,
type : "checkbox" ,
checked : this . formatter . fromRaw ( this . model . get ( this . column . get ( "name" ) ) )
} ) ) ;
this . delegateEvents ( ) ;
return this ;
}
} ) ;
/ * *
SelectCellEditor renders an HTML ` <select> ` fragment as the editor .
@ class Backgrid . SelectCellEditor
@ extends Backgrid . CellEditor
* /
var SelectCellEditor = Backgrid . SelectCellEditor = CellEditor . extend ( {
/** @property */
tagName : "select" ,
/** @property */
events : {
"change" : "save" ,
"blur" : "close" ,
"keydown" : "close"
} ,
/** @property {function(Object, ?Object=): string} template */
template : _ . template ( '<option value="<%- value %>" <%= selected ? \'selected="selected"\' : "" %>><%- text %></option>' ) ,
setOptionValues : function ( optionValues ) {
this . optionValues = optionValues ;
} ,
setMultiple : function ( multiple ) {
this . multiple = multiple ;
this . $el . prop ( "multiple" , multiple ) ;
} ,
_renderOptions : function ( nvps , selectedValues ) {
var options = '' ;
for ( var i = 0 ; i < nvps . length ; i ++ ) {
options = options + this . template ( {
text : nvps [ i ] [ 0 ] ,
value : nvps [ i ] [ 1 ] ,
selected : selectedValues . indexOf ( nvps [ i ] [ 1 ] ) > - 1
} ) ;
}
return options ;
} ,
/ * *
Renders the options if ` optionValues ` is a list of name - value pairs . The
options are contained inside option groups if ` optionValues ` is a list of
object hashes . The name is rendered at the option text and the value is the
option value . If ` optionValues ` is a function , it is called without a
parameter .
* /
render : function ( ) {
this . $el . empty ( ) ;
var optionValues = _ . result ( this , "optionValues" ) ;
var selectedValues = this . formatter . fromRaw ( this . model . get ( this . column . get ( "name" ) ) ) ;
if ( ! _ . isArray ( optionValues ) ) throw TypeError ( "optionValues must be an array" ) ;
var optionValue = null ;
var optionText = null ;
var optionValue = null ;
var optgroupName = null ;
var optgroup = null ;
for ( var i = 0 ; i < optionValues . length ; i ++ ) {
var optionValue = optionValues [ i ] ;
if ( _ . isArray ( optionValue ) ) {
optionText = optionValue [ 0 ] ;
optionValue = optionValue [ 1 ] ;
this . $el . append ( this . template ( {
text : optionText ,
value : optionValue ,
selected : selectedValues . indexOf ( optionValue ) > - 1
} ) ) ;
}
else if ( _ . isObject ( optionValue ) ) {
optgroupName = optionValue . name ;
optgroup = $ ( "<optgroup></optgroup>" , { label : optgroupName } ) ;
optgroup . append ( this . _renderOptions ( optionValue . values , selectedValues ) ) ;
this . $el . append ( optgroup ) ;
}
else {
throw TypeError ( "optionValues elements must be a name-value pair or an object hash of { name: 'optgroup label', value: [option name-value pairs] }" ) ;
}
}
this . delegateEvents ( ) ;
return this ;
} ,
/ * *
Saves the value of the selected option to the model attribute . Triggers a
` backgrid:edited ` Backbone event from the model .
* /
save : function ( e ) {
var model = this . model ;
var column = this . column ;
model . set ( column . get ( "name" ) , this . formatter . toRaw ( this . $el . val ( ) ) ) ;
model . trigger ( "backgrid:edited" , model , column , new Command ( e ) ) ;
} ,
/ * *
Triggers a ` backgrid:edited ` event from the model so the body can close
this editor .
* /
close : function ( e ) {
var model = this . model ;
var column = this . column ;
var command = new Command ( e ) ;
if ( command . cancel ( ) ) {
e . stopPropagation ( ) ;
model . trigger ( "backgrid:edited" , model , column , new Command ( e ) ) ;
}
else if ( command . save ( ) || command . moveLeft ( ) || command . moveRight ( ) ||
command . moveUp ( ) || command . moveDown ( ) || e . type == "blur" ) {
e . preventDefault ( ) ;
e . stopPropagation ( ) ;
if ( e . type == "blur" && this . $el . find ( "option" ) . length === 1 ) {
model . set ( column . get ( "name" ) , this . formatter . toRaw ( this . $el . val ( ) ) ) ;
}
model . trigger ( "backgrid:edited" , model , column , new Command ( e ) ) ;
}
}
} ) ;
/ * *
SelectCell is also a different kind of cell in that upon going into edit mode
the cell renders a list of options to pick from , as opposed to an input box .
SelectCell cannot be referenced by its string name when used in a column
definition because it requires an ` optionValues ` class attribute to be
defined . ` optionValues ` can either be a list of name - value pairs , to be
rendered as options , or a list of object hashes which consist of a key * name *
which is the option group name , and a key * values * which is a list of
name - value pairs to be rendered as options under that option group .
In addition , ` optionValues ` can also be a parameter - less function that
returns one of the above . If the options are static , it is recommended the
returned values to be memoized . ` _.memoize() ` is a good function to help with
that .
During display mode , the default formatter will normalize the raw model value
to an array of values whether the raw model value is a scalar or an
array . Each value is compared with the ` optionValues ` values using
Ecmascript ' s implicit type conversion rules . When exiting edit mode , no type
conversion is performed when saving into the model . This behavior is not
always desirable when the value type is anything other than string . To
control type conversion on the client - side , you should subclass SelectCell to
provide a custom formatter or provide the formatter to your column
definition .
See :
[ $ . fn . val ( ) ] ( http : //api.jquery.com/val/)
@ class Backgrid . SelectCell
@ extends Backgrid . Cell
* /
var SelectCell = Backgrid . SelectCell = Cell . extend ( {
/** @property */
className : "select-cell" ,
/** @property */
editor : SelectCellEditor ,
/** @property */
multiple : false ,
/** @property */
formatter : new SelectFormatter ( ) ,
/ * *
@ property { Array . < Array > | Array . < { name : string , values : Array . < Array > } > } optionValues
* /
optionValues : undefined ,
/** @property */
delimiter : ', ' ,
/ * *
Initializer .
@ param { Object } options
@ param { Backbone . Model } options . model
@ param { Backgrid . Column } options . column
@ throws { TypeError } If ` optionsValues ` is undefined .
* /
initialize : function ( options ) {
Cell . prototype . initialize . apply ( this , arguments ) ;
Backgrid . requireOptions ( this , [ "optionValues" ] ) ;
this . listenTo ( this . model , "backgrid:edit" , function ( model , column , cell , editor ) {
if ( column . get ( "name" ) == this . column . get ( "name" ) ) {
editor . setOptionValues ( this . optionValues ) ;
editor . setMultiple ( this . multiple ) ;
}
} ) ;
} ,
/ * *
Renders the label using the raw value as key to look up from ` optionValues ` .
@ throws { TypeError } If ` optionValues ` is malformed .
* /
render : function ( ) {
this . $el . empty ( ) ;
var optionValues = this . optionValues ;
var rawData = this . formatter . fromRaw ( this . model . get ( this . column . get ( "name" ) ) ) ;
var selectedText = [ ] ;
try {
if ( ! _ . isArray ( optionValues ) || _ . isEmpty ( optionValues ) ) throw new TypeError ;
for ( var k = 0 ; k < rawData . length ; k ++ ) {
var rawDatum = rawData [ k ] ;
for ( var i = 0 ; i < optionValues . length ; i ++ ) {
var optionValue = optionValues [ i ] ;
if ( _ . isArray ( optionValue ) ) {
var optionText = optionValue [ 0 ] ;
var optionValue = optionValue [ 1 ] ;
if ( optionValue == rawDatum ) selectedText . push ( optionText ) ;
}
else if ( _ . isObject ( optionValue ) ) {
var optionGroupValues = optionValue . values ;
for ( var j = 0 ; j < optionGroupValues . length ; j ++ ) {
var optionGroupValue = optionGroupValues [ j ] ;
if ( optionGroupValue [ 1 ] == rawDatum ) {
selectedText . push ( optionGroupValue [ 0 ] ) ;
}
}
}
else {
throw new TypeError ;
}
}
}
this . $el . append ( selectedText . join ( this . delimiter ) ) ;
}
catch ( ex ) {
if ( ex instanceof TypeError ) {
throw TypeError ( "'optionValues' must be of type {Array.<Array>|Array.<{name: string, values: Array.<Array>}>}" ) ;
}
throw ex ;
}
this . delegateEvents ( ) ;
return this ;
}
} ) ;
/ *
backgrid
http : //github.com/wyuenho/backgrid
Copyright ( c ) 2013 Jimmy Yuen Ho Wong and contributors
Licensed under the MIT @ license .
* /
/ * *
A Column is a placeholder for column metadata .
You usually don ' t need to create an instance of this class yourself as a
collection of column instances will be created for you from a list of column
attributes in the Backgrid . js view class constructors .
@ class Backgrid . Column
@ extends Backbone . Model
* /
var Column = Backgrid . Column = Backbone . Model . extend ( {
defaults : {
name : undefined ,
label : undefined ,
sortable : true ,
editable : true ,
renderable : true ,
formatter : undefined ,
cell : undefined ,
headerCell : undefined
} ,
/ * *
Initializes this Column instance .
@ param { Object } attrs Column attributes .
@ param { string } attrs . name The name of the model attribute .
@ param { string | Backgrid . Cell } attrs . cell The cell type .
If this is a string , the capitalized form will be used to look up a
cell class in Backbone , i . e . : string => StringCell . If a Cell subclass
is supplied , it is initialized with a hash of parameters . If a Cell
instance is supplied , it is used directly .
@ param { string | Backgrid . HeaderCell } [ attrs . headerCell ] The header cell type .
@ param { string } [ attrs . label ] The label to show in the header .
@ param { boolean } [ attrs . sortable = true ]
@ param { boolean } [ attrs . editable = true ]
@ param { boolean } [ attrs . renderable = true ]
@ param { Backgrid . CellFormatter | Object | string } [ attrs . formatter ] The
formatter to use to convert between raw model values and user input .
@ throws { TypeError } If attrs . cell or attrs . options are not supplied .
@ throws { ReferenceError } If attrs . cell is a string but a cell class of
said name cannot be found in the Backgrid module .
See :
- Backgrid . Cell
- Backgrid . CellFormatter
* /
initialize : function ( attrs ) {
Backgrid . requireOptions ( attrs , [ "cell" , "name" ] ) ;
if ( ! this . has ( "label" ) ) {
this . set ( { label : this . get ( "name" ) } , { silent : true } ) ;
}
var headerCell = Backgrid . resolveNameToClass ( this . get ( "headerCell" ) , "HeaderCell" ) ;
var cell = Backgrid . resolveNameToClass ( this . get ( "cell" ) , "Cell" ) ;
this . set ( { cell : cell , headerCell : headerCell } , { silent : true } ) ;
}
} ) ;
/ * *
A Backbone collection of Column instances .
@ class Backgrid . Columns
@ extends Backbone . Collection
* /
var Columns = Backgrid . Columns = Backbone . Collection . extend ( {
/ * *
@ property { Backgrid . Column } model
* /
model : Column
} ) ;
/ *
backgrid
http : //github.com/wyuenho/backgrid
Copyright ( c ) 2013 Jimmy Yuen Ho Wong and contributors
Licensed under the MIT @ license .
* /
/ * *
Row is a simple container view that takes a model instance and a list of
column metadata describing how each of the model ' s attribute is to be
rendered , and apply the appropriate cell to each attribute .
@ class Backgrid . Row
@ extends Backbone . View
* /
var Row = Backgrid . Row = Backbone . View . extend ( {
/** @property */
tagName : "tr" ,
requiredOptions : [ "columns" , "model" ] ,
/ * *
Initializes a row view instance .
@ param { Object } options
@ param { Backbone . Collection . < Backgrid . Column > | Array . < Backgrid . Column > | Array . < Object > } options . columns Column metadata .
@ param { Backbone . Model } options . model The model instance to render .
@ throws { TypeError } If options . columns or options . model is undefined .
* /
initialize : function ( options ) {
Backgrid . requireOptions ( options , this . requiredOptions ) ;
var columns = this . columns = options . columns ;
if ( ! ( columns instanceof Backbone . Collection ) ) {
columns = this . columns = new Columns ( columns ) ;
}
var cells = this . cells = [ ] ;
for ( var i = 0 ; i < columns . length ; i ++ ) {
cells . push ( this . makeCell ( columns . at ( i ) , options ) ) ;
}
this . listenTo ( columns , "change:renderable" , function ( column , renderable ) {
for ( var i = 0 ; i < cells . length ; i ++ ) {
var cell = cells [ i ] ;
if ( cell . column . get ( "name" ) == column . get ( "name" ) ) {
if ( renderable ) cell . $el . show ( ) ; else cell . $el . hide ( ) ;
}
}
} ) ;
this . listenTo ( columns , "add" , function ( column , columns ) {
var i = columns . indexOf ( column ) ;
var cell = this . makeCell ( column , options ) ;
cells . splice ( i , 0 , cell ) ;
if ( ! cell . column . get ( "renderable" ) ) cell . $el . hide ( ) ;
var $el = this . $el ;
if ( i === 0 ) {
$el . prepend ( cell . render ( ) . $el ) ;
}
else if ( i === columns . length - 1 ) {
$el . append ( cell . render ( ) . $el ) ;
}
else {
$el . children ( ) . eq ( i ) . before ( cell . render ( ) . $el ) ;
}
} ) ;
this . listenTo ( columns , "remove" , function ( column , columns , opts ) {
cells [ opts . index ] . remove ( ) ;
cells . splice ( opts . index , 1 ) ;
} ) ;
} ,
/ * *
Factory method for making a cell . Used by # initialize internally . Override
this to provide an appropriate cell instance for a custom Row subclass .
@ protected
@ param { Backgrid . Column } column
@ param { Object } options The options passed to # initialize .
@ return { Backgrid . Cell }
* /
makeCell : function ( column ) {
return new ( column . get ( "cell" ) ) ( {
column : column ,
model : this . model
} ) ;
} ,
/ * *
Renders a row of cells for this row ' s model .
* /
render : function ( ) {
this . $el . empty ( ) ;
var fragment = document . createDocumentFragment ( ) ;
for ( var i = 0 ; i < this . cells . length ; i ++ ) {
var cell = this . cells [ i ] ;
fragment . appendChild ( cell . render ( ) . el ) ;
if ( ! cell . column . get ( "renderable" ) ) cell . $el . hide ( ) ;
}
this . el . appendChild ( fragment ) ;
this . delegateEvents ( ) ;
return this ;
} ,
/ * *
Clean up this row and its cells .
@ chainable
* /
remove : function ( ) {
for ( var i = 0 ; i < this . cells . length ; i ++ ) {
var cell = this . cells [ i ] ;
cell . remove . apply ( cell , arguments ) ;
}
return Backbone . View . prototype . remove . apply ( this , arguments ) ;
}
} ) ;
/ * *
EmptyRow is a simple container view that takes a list of column and render a
row with a single column .
@ class Backgrid . EmptyRow
@ extends Backbone . View
* /
var EmptyRow = Backgrid . EmptyRow = Backbone . View . extend ( {
/** @property */
tagName : "tr" ,
/** @property */
emptyText : null ,
/ * *
Initializer .
@ param { Object } options
@ param { string } options . emptyText
@ param { Backbone . Collection . < Backgrid . Column > | Array . < Backgrid . Column > | Array . < Object > } options . columns Column metadata .
* /
initialize : function ( options ) {
Backgrid . requireOptions ( options , [ "emptyText" , "columns" ] ) ;
this . emptyText = options . emptyText ;
this . columns = options . columns ;
} ,
/ * *
Renders an empty row .
* /
render : function ( ) {
this . $el . empty ( ) ;
var td = document . createElement ( "td" ) ;
td . setAttribute ( "colspan" , this . columns . length ) ;
td . textContent = this . emptyText ;
this . el . setAttribute ( "class" , "empty" ) ;
this . el . appendChild ( td ) ;
return this ;
}
} ) ;
/ *
backgrid
http : //github.com/wyuenho/backgrid
Copyright ( c ) 2013 Jimmy Yuen Ho Wong and contributors
Licensed under the MIT @ license .
* /
/ * *
HeaderCell is a special cell class that renders a column header cell . If the
column is sortable , a sorter is also rendered and will trigger a table
refresh after sorting .
@ class Backgrid . HeaderCell
@ extends Backbone . View
* /
var HeaderCell = Backgrid . HeaderCell = Backbone . View . extend ( {
/** @property */
tagName : "th" ,
/** @property */
events : {
"click a" : "onClick"
} ,
/ * *
@ property { null | "ascending" | "descending" } _direction The current sorting
direction of this column .
* /
_direction : null ,
/ * *
Initializer .
@ param { Object } options
@ param { Backgrid . Column | Object } options . column
@ throws { TypeError } If options . column or options . collection is undefined .
* /
initialize : function ( options ) {
Backgrid . requireOptions ( options , [ "column" , "collection" ] ) ;
this . column = options . column ;
if ( ! ( this . column instanceof Column ) ) {
this . column = new Column ( this . column ) ;
}
this . listenTo ( this . collection , "backgrid:sort" , this . _resetCellDirection ) ;
} ,
/ * *
Gets or sets the direction of this cell . If called directly without
parameters , returns the current direction of this cell , otherwise sets
it . If a ` null ` is given , sets this cell back to the default order .
@ param { null | "ascending" | "descending" } dir
@ return { null | string } The current direction or the changed direction .
* /
direction : function ( dir ) {
if ( arguments . length ) {
if ( this . _direction ) this . $el . removeClass ( this . _direction ) ;
if ( dir ) this . $el . addClass ( dir ) ;
this . _direction = dir ;
}
return this . _direction ;
} ,
/ * *
Event handler for the Backbone ` backgrid:sort ` event . Resets this cell ' s
direction to default if sorting is being done on another column .
@ private
* /
_resetCellDirection : function ( sortByColName , direction , comparator , collection ) {
if ( collection == this . collection ) {
if ( sortByColName !== this . column . get ( "name" ) ) this . direction ( null ) ;
else this . direction ( direction ) ;
}
} ,
/ * *
Event handler for the ` click ` event on the cell ' s anchor . If the column is
sortable , clicking on the anchor will cycle through 3 sorting orderings -
` ascending ` , ` descending ` , and default .
* /
onClick : function ( e ) {
e . preventDefault ( ) ;
var columnName = this . column . get ( "name" ) ;
if ( this . column . get ( "sortable" ) ) {
if ( this . direction ( ) === "ascending" ) {
this . sort ( columnName , "descending" , function ( left , right ) {
var leftVal = left . get ( columnName ) ;
var rightVal = right . get ( columnName ) ;
if ( leftVal === rightVal ) {
return 0 ;
}
else if ( leftVal > rightVal ) { return - 1 ; }
return 1 ;
} ) ;
}
else if ( this . direction ( ) === "descending" ) {
this . sort ( columnName , null ) ;
}
else {
this . sort ( columnName , "ascending" , function ( left , right ) {
var leftVal = left . get ( columnName ) ;
var rightVal = right . get ( columnName ) ;
if ( leftVal === rightVal ) {
return 0 ;
}
else if ( leftVal < rightVal ) { return - 1 ; }
return 1 ;
} ) ;
}
}
} ,
/ * *
If the underlying collection is a Backbone . PageableCollection in
server - mode or infinite - mode , a page of models is fetched after sorting is
done on the server .
If the underlying collection is a Backbone . PageableCollection in
client - mode , or any
[ Backbone . Collection ] ( http : //backbonejs.org/#Collection) instance, sorting
is done on the client side . If the collection is an instance of a
Backbone . PageableCollection , sorting will be done globally on all the pages
and the current page will then be returned .
Triggers a Backbone ` backgrid:sort ` event from the collection when done
with the column name , direction , comparator and a reference to the
collection .
@ param { string } columnName
@ param { null | "ascending" | "descending" } direction
@ param { function ( * , * ) : number } [ comparator ]
See [ Backbone . Collection # comparator ] ( http : //backbonejs.org/#Collection-comparator)
* /
sort : function ( columnName , direction , comparator ) {
comparator = comparator || this . _cidComparator ;
var collection = this . collection ;
if ( Backbone . PageableCollection && collection instanceof Backbone . PageableCollection ) {
var order ;
if ( direction === "ascending" ) order = - 1 ;
else if ( direction === "descending" ) order = 1 ;
else order = null ;
collection . setSorting ( order ? columnName : null , order ) ;
if ( collection . mode == "client" ) {
if ( ! collection . fullCollection . comparator ) {
collection . fullCollection . comparator = comparator ;
}
collection . fullCollection . sort ( ) ;
}
else collection . fetch ( { reset : true } ) ;
}
else {
collection . comparator = comparator ;
collection . sort ( ) ;
}
this . collection . trigger ( "backgrid:sort" , columnName , direction , comparator , this . collection ) ;
} ,
/ * *
Default comparator for Backbone . Collections . Sorts cids in ascending
order . The cids of the models are assumed to be in insertion order .
@ private
@ param { * } left
@ param { * } right
* /
_cidComparator : function ( left , right ) {
var lcid = left . cid , rcid = right . cid ;
if ( ! _ . isUndefined ( lcid ) && ! _ . isUndefined ( rcid ) ) {
lcid = lcid . slice ( 1 ) * 1 , rcid = rcid . slice ( 1 ) * 1 ;
if ( lcid < rcid ) return - 1 ;
else if ( lcid > rcid ) return 1 ;
}
return 0 ;
} ,
/ * *
Renders a header cell with a sorter and a label .
* /
render : function ( ) {
this . $el . empty ( ) ;
var $label = $ ( "<a>" ) . text ( this . column . get ( "label" ) ) . append ( "<b class='sort-caret'></b>" ) ;
this . $el . append ( $label ) ;
this . delegateEvents ( ) ;
return this ;
}
} ) ;
/ * *
HeaderRow is a controller for a row of header cells .
@ class Backgrid . HeaderRow
@ extends Backgrid . Row
* /
var HeaderRow = Backgrid . HeaderRow = Backgrid . Row . extend ( {
requiredOptions : [ "columns" , "collection" ] ,
/ * *
Initializer .
@ param { Object } options
@ param { Backbone . Collection . < Backgrid . Column > | Array . < Backgrid . Column > | Array . < Object > } options . columns
@ param { Backgrid . HeaderCell } [ options . headerCell ] Customized default
HeaderCell for all the columns . Supply a HeaderCell class or instance to a
the ` headerCell ` key in a column definition for column - specific header
rendering .
@ throws { TypeError } If options . columns or options . collection is undefined .
* /
initialize : function ( ) {
Backgrid . Row . prototype . initialize . apply ( this , arguments ) ;
} ,
makeCell : function ( column , options ) {
var headerCell = column . get ( "headerCell" ) || options . headerCell || HeaderCell ;
headerCell = new headerCell ( {
column : column ,
collection : this . collection
} ) ;
return headerCell ;
}
} ) ;
/ * *
Header is a special structural view class that renders a table head with a
single row of header cells .
@ class Backgrid . Header
@ extends Backbone . View
* /
var Header = Backgrid . Header = Backbone . View . extend ( {
/** @property */
tagName : "thead" ,
/ * *
Initializer . Initializes this table head view to contain a single header
row view .
@ param { Object } options
@ param { Backbone . Collection . < Backgrid . Column > | Array . < Backgrid . Column > | Array . < Object > } options . columns Column metadata .
@ param { Backbone . Model } options . model The model instance to render .
@ throws { TypeError } If options . columns or options . model is undefined .
* /
initialize : function ( options ) {
Backgrid . requireOptions ( options , [ "columns" , "collection" ] ) ;
this . columns = options . columns ;
if ( ! ( this . columns instanceof Backbone . Collection ) ) {
this . columns = new Columns ( this . columns ) ;
}
this . row = new Backgrid . HeaderRow ( {
columns : this . columns ,
collection : this . collection
} ) ;
} ,
/ * *
Renders this table head with a single row of header cells .
* /
render : function ( ) {
this . $el . append ( this . row . render ( ) . $el ) ;
this . delegateEvents ( ) ;
return this ;
} ,
/ * *
Clean up this header and its row .
@ chainable
* /
remove : function ( ) {
this . row . remove . apply ( this . row , arguments ) ;
return Backbone . View . prototype . remove . apply ( this , arguments ) ;
}
} ) ;
/ *
backgrid
http : //github.com/wyuenho/backgrid
Copyright ( c ) 2013 Jimmy Yuen Ho Wong and contributors
Licensed under the MIT @ license .
* /
/ * *
Body is the table body which contains the rows inside a table . Body is
responsible for refreshing the rows after sorting , insertion and removal .
@ class Backgrid . Body
@ extends Backbone . View
* /
var Body = Backgrid . Body = Backbone . View . extend ( {
/** @property */
tagName : "tbody" ,
/ * *
Initializer .
@ param { Object } options
@ param { Backbone . Collection } options . collection
@ param { Backbone . Collection . < Backgrid . Column > | Array . < Backgrid . Column > | Array . < Object > } options . columns
Column metadata .
@ param { Backgrid . Row } [ options . row = Backgrid . Row ] The Row class to use .
@ param { string } [ options . emptyText ] The text to display in the empty row .
@ throws { TypeError } If options . columns or options . collection is undefined .
See Backgrid . Row .
* /
initialize : function ( options ) {
Backgrid . requireOptions ( options , [ "columns" , "collection" ] ) ;
this . columns = options . columns ;
if ( ! ( this . columns instanceof Backbone . Collection ) ) {
this . columns = new Columns ( this . columns ) ;
}
this . row = options . row || Row ;
this . rows = this . collection . map ( function ( model ) {
var row = new this . row ( {
columns : this . columns ,
model : model
} ) ;
return row ;
} , this ) ;
this . emptyText = options . emptyText ;
this . _unshiftEmptyRowMayBe ( ) ;
var collection = this . collection ;
this . listenTo ( collection , "add" , this . insertRow ) ;
this . listenTo ( collection , "remove" , this . removeRow ) ;
this . listenTo ( collection , "sort" , this . refresh ) ;
this . listenTo ( collection , "reset" , this . refresh ) ;
this . listenTo ( collection , "backgrid:edited" , this . moveToNextCell ) ;
} ,
_unshiftEmptyRowMayBe : function ( ) {
if ( this . rows . length === 0 && this . emptyText != null ) {
this . rows . unshift ( new EmptyRow ( {
emptyText : this . emptyText ,
columns : this . columns
} ) ) ;
}
} ,
/ * *
This method can be called either directly or as a callback to a
[ Backbone . Collecton # add ] ( http : //backbonejs.org/#Collection-add) event.
When called directly , it accepts a model or an array of models and an
option hash just like
[ Backbone . Collection # add ] ( http : //backbonejs.org/#Collection-add) and
delegates to it . Once the model is added , a new row is inserted into the
body and automatically rendered .
When called as a callback of an ` add ` event , splices a new row into the
body and renders it .
@ param { Backbone . Model } model The model to render as a row .
@ param { Backbone . Collection } collection When called directly , this
parameter is actually the options to
[ Backbone . Collection # add ] ( http : //backbonejs.org/#Collection-add).
@ param { Object } options When called directly , this must be null .
See :
- [ Backbone . Collection # add ] ( http : //backbonejs.org/#Collection-add)
* /
insertRow : function ( model , collection , options ) {
if ( this . rows [ 0 ] instanceof EmptyRow ) this . rows . pop ( ) . remove ( ) ;
// insertRow() is called directly
if ( ! ( collection instanceof Backbone . Collection ) && ! options ) {
this . collection . add ( model , ( options = collection ) ) ;
return ;
}
options = _ . extend ( { render : true } , options || { } ) ;
var row = new this . row ( {
columns : this . columns ,
model : model
} ) ;
var index = collection . indexOf ( model ) ;
this . rows . splice ( index , 0 , row ) ;
var $el = this . $el ;
var $children = $el . children ( ) ;
var $rowEl = row . render ( ) . $el ;
if ( options . render ) {
if ( index >= $children . length ) {
$el . append ( $rowEl ) ;
}
else {
$children . eq ( index ) . before ( $rowEl ) ;
}
}
} ,
/ * *
The method can be called either directly or as a callback to a
[ Backbone . Collection # remove ] ( http : //backbonejs.org/#Collection-remove)
event .
When called directly , it accepts a model or an array of models and an
option hash just like
[ Backbone . Collection # remove ] ( http : //backbonejs.org/#Collection-remove) and
delegates to it . Once the model is removed , a corresponding row is removed
from the body .
When called as a callback of a ` remove ` event , splices into the rows and
removes the row responsible for rendering the model .
@ param { Backbone . Model } model The model to remove from the body .
@ param { Backbone . Collection } collection When called directly , this
parameter is actually the options to
[ Backbone . Collection # remove ] ( http : //backbonejs.org/#Collection-remove).
@ param { Object } options When called directly , this must be null .
See :
- [ Backbone . Collection # remove ] ( http : //backbonejs.org/#Collection-remove)
* /
removeRow : function ( model , collection , options ) {
// removeRow() is called directly
if ( ! options ) {
this . collection . remove ( model , ( options = collection ) ) ;
this . _unshiftEmptyRowMayBe ( ) ;
return ;
}
if ( _ . isUndefined ( options . render ) || options . render ) {
this . rows [ options . index ] . remove ( ) ;
}
this . rows . splice ( options . index , 1 ) ;
this . _unshiftEmptyRowMayBe ( ) ;
} ,
/ * *
Reinitialize all the rows inside the body and re - render them . Triggers a
Backbone ` backgrid:refresh ` event from the collection along with the body
instance as its sole parameter when done .
* /
refresh : function ( ) {
for ( var i = 0 ; i < this . rows . length ; i ++ ) {
this . rows [ i ] . remove ( ) ;
}
this . rows = this . collection . map ( function ( model ) {
var row = new this . row ( {
columns : this . columns ,
model : model
} ) ;
return row ;
} , this ) ;
this . _unshiftEmptyRowMayBe ( ) ;
this . render ( ) ;
this . collection . trigger ( "backgrid:refresh" , this ) ;
return this ;
} ,
/ * *
Renders all the rows inside this body . If the collection is empty and
` options.emptyText ` is defined and not null in the constructor , an empty
row is rendered , otherwise no row is rendered .
* /
render : function ( ) {
this . $el . empty ( ) ;
var fragment = document . createDocumentFragment ( ) ;
for ( var i = 0 ; i < this . rows . length ; i ++ ) {
var row = this . rows [ i ] ;
fragment . appendChild ( row . render ( ) . el ) ;
}
this . el . appendChild ( fragment ) ;
this . delegateEvents ( ) ;
return this ;
} ,
/ * *
Clean up this body and it ' s rows .
@ chainable
* /
remove : function ( ) {
for ( var i = 0 ; i < this . rows . length ; i ++ ) {
var row = this . rows [ i ] ;
row . remove . apply ( row , arguments ) ;
}
return Backbone . View . prototype . remove . apply ( this , arguments ) ;
} ,
/ * *
Moves focus to the next renderable and editable cell and return the
currently editing cell to display mode .
@ param { Backbone . Model } model The originating model
@ param { Backgrid . Column } column The originating model column
@ param { Backgrid . Command } command The Command object constructed from a DOM
Event
* /
moveToNextCell : function ( model , column , command ) {
var i = this . collection . indexOf ( model ) ;
var j = this . columns . indexOf ( column ) ;
if ( command . moveUp ( ) || command . moveDown ( ) || command . moveLeft ( ) ||
command . moveRight ( ) || command . save ( ) ) {
var l = this . columns . length ;
var maxOffset = l * this . collection . length ;
if ( command . moveUp ( ) || command . moveDown ( ) ) {
var row = this . rows [ i + ( command . moveUp ( ) ? - 1 : 1 ) ] ;
if ( row ) row . cells [ j ] . enterEditMode ( ) ;
}
else if ( command . moveLeft ( ) || command . moveRight ( ) ) {
var right = command . moveRight ( ) ;
for ( var offset = i * l + j + ( right ? 1 : - 1 ) ;
offset >= 0 && offset < maxOffset ;
right ? offset ++ : offset -- ) {
var m = ~ ~ ( offset / l ) ;
var n = offset - m * l ;
var cell = this . rows [ m ] . cells [ n ] ;
if ( cell . column . get ( "renderable" ) && cell . column . get ( "editable" ) ) {
cell . enterEditMode ( ) ;
break ;
}
}
}
}
this . rows [ i ] . cells [ j ] . exitEditMode ( ) ;
}
} ) ;
/ *
backgrid
http : //github.com/wyuenho/backgrid
Copyright ( c ) 2013 Jimmy Yuen Ho Wong and contributors
Licensed under the MIT @ license .
* /
/ * *
A Footer is a generic class that only defines a default tag ` tfoot ` and
number of required parameters in the initializer .
@ abstract
@ class Backgrid . Footer
@ extends Backbone . View
* /
var Footer = Backgrid . Footer = Backbone . View . extend ( {
/** @property */
tagName : "tfoot" ,
/ * *
Initializer .
@ param { Object } options
@ param { * } options . parent The parent view class of this footer .
@ param { Backbone . Collection . < Backgrid . Column > | Array . < Backgrid . Column > | Array . < Object > } options . columns
Column metadata .
@ param { Backbone . Collection } options . collection
@ throws { TypeError } If options . columns or options . collection is undefined .
* /
initialize : function ( options ) {
Backgrid . requireOptions ( options , [ "columns" , "collection" ] ) ;
this . columns = options . columns ;
if ( ! ( this . columns instanceof Backbone . Collection ) ) {
this . columns = new Backgrid . Columns ( this . columns ) ;
}
}
} ) ;
/ *
backgrid
http : //github.com/wyuenho/backgrid
Copyright ( c ) 2013 Jimmy Yuen Ho Wong and contributors
Licensed under the MIT @ license .
* /
/ * *
Grid represents a data grid that has a header , body and an optional footer .
By default , a Grid treats each model in a collection as a row , and each
attribute in a model as a column . To render a grid you must provide a list of
column metadata and a collection to the Grid constructor . Just like any
Backbone . View class , the grid is rendered as a DOM node fragment when you
call render ( ) .
var grid = Backgrid . Grid ( {
columns : [ { name : "id" , label : "ID" , type : "string" } ,
// ...
] ,
collections : books
} ) ;
$ ( "#table-container" ) . append ( grid . render ( ) . el ) ;
Optionally , if you want to customize the rendering of the grid ' s header and
footer , you may choose to extend Backgrid . Header and Backgrid . Footer , and
then supply that class or an instance of that class to the Grid constructor .
See the documentation for Header and Footer for further details .
var grid = Backgrid . Grid ( {
columns : [ { name : "id" , label : "ID" , type : "string" } ] ,
collections : books ,
header : Backgrid . Header . extend ( {
//...
} ) ,
footer : Backgrid . Paginator
} ) ;
Finally , if you want to override how the rows are rendered in the table body ,
you can supply a Body subclass as the ` body ` attribute that uses a different
Row class .
@ class Backgrid . Grid
@ extends Backbone . View
See :
- Backgrid . Column
- Backgrid . Header
- Backgrid . Body
- Backgrid . Row
- Backgrid . Footer
* /
var Grid = Backgrid . Grid = Backbone . View . extend ( {
/** @property */
tagName : "table" ,
/** @property */
className : "backgrid" ,
/** @property */
header : Header ,
/** @property */
body : Body ,
/** @property */
footer : null ,
/ * *
Initializes a Grid instance .
@ param { Object } options
@ param { Backbone . Collection . < Backgrid . Column > | Array . < Backgrid . Column > | Array . < Object > } options . columns Column metadata .
@ param { Backbone . Collection } options . collection The collection of tabular model data to display .
@ param { Backgrid . Header } [ options . header = Backgrid . Header ] An optional Header class to override the default .
@ param { Backgrid . Body } [ options . body = Backgrid . Body ] An optional Body class to override the default .
@ param { Backgrid . Row } [ options . row = Backgrid . Row ] An optional Row class to override the default .
@ param { Backgrid . Footer } [ options . footer = Backgrid . Footer ] An optional Footer class .
* /
initialize : function ( options ) {
Backgrid . requireOptions ( options , [ "columns" , "collection" ] ) ;
// Convert the list of column objects here first so the subviews don't have
// to.
if ( ! ( options . columns instanceof Backbone . Collection ) ) {
options . columns = new Columns ( options . columns ) ;
}
this . columns = options . columns ;
var passedThruOptions = _ . omit ( options , [ "el" , "id" , "attributes" ,
"className" , "tagName" , "events" ] ) ;
this . header = options . header || this . header ;
this . header = new this . header ( passedThruOptions ) ;
this . body = options . body || this . body ;
this . body = new this . body ( passedThruOptions ) ;
this . footer = options . footer || this . footer ;
if ( this . footer ) {
this . footer = new this . footer ( passedThruOptions ) ;
}
this . listenTo ( this . columns , "reset" , function ( ) {
this . header = new ( this . header . remove ( ) . constructor ) ( passedThruOptions ) ;
this . body = new ( this . body . remove ( ) . constructor ) ( passedThruOptions ) ;
if ( this . footer ) {
this . footer = new ( this . footer . remove ( ) . constructor ) ( passedThruOptions ) ;
}
this . render ( ) ;
} ) ;
} ,
/ * *
Delegates to Backgrid . Body # insertRow .
* /
insertRow : function ( model , collection , options ) {
return this . body . insertRow ( model , collection , options ) ;
} ,
/ * *
Delegates to Backgrid . Body # removeRow .
* /
removeRow : function ( model , collection , options ) {
return this . body . removeRow ( model , collection , options ) ;
} ,
/ * *
Delegates to Backgrid . Columns # add for adding a column . Subviews can listen
to the ` add ` event from their internal ` columns ` if rerendering needs to
happen .
@ param { Object } [ options ] Options for ` Backgrid.Columns#add ` .
@ param { boolean } [ options . render = true ] Whether to render the column
immediately after insertion .
@ chainable
* /
insertColumn : function ( column , options ) {
options = options || { render : true } ;
this . columns . add ( column , options ) ;
return this ;
} ,
/ * *
Delegates to Backgrid . Columns # remove for removing a column . Subviews can
listen to the ` remove ` event from the internal ` columns ` if rerendering
needs to happen .
@ param { Object } [ options ] Options for ` Backgrid.Columns#remove ` .
@ chainable
* /
removeColumn : function ( column , options ) {
this . columns . remove ( column , options ) ;
return this ;
} ,
/ * *
Renders the grid ' s header , then footer , then finally the body . Triggers a
Backbone ` backgrid:rendered ` event along with a reference to the grid when
the it has successfully been rendered .
* /
render : function ( ) {
this . $el . empty ( ) ;
this . $el . append ( this . header . render ( ) . $el ) ;
if ( this . footer ) {
this . $el . append ( this . footer . render ( ) . $el ) ;
}
this . $el . append ( this . body . render ( ) . $el ) ;
this . delegateEvents ( ) ;
this . trigger ( "backgrid:rendered" , this ) ;
return this ;
} ,
/ * *
Clean up this grid and its subviews .
@ chainable
* /
remove : function ( ) {
this . header . remove . apply ( this . header , arguments ) ;
this . body . remove . apply ( this . body , arguments ) ;
this . footer && this . footer . remove . apply ( this . footer , arguments ) ;
return Backbone . View . prototype . remove . apply ( this , arguments ) ;
}
} ) ;
} ( this , jQuery , _ , Backbone ) ) ;