@@ -14,29 +14,41 @@ JSON table is a minimal, yet flexible HTML table editor, where you can attach fo
14
14
var COLUMN_WIDTH = 16
15
15
var BORDER_WIDTH = 1
16
16
var DEFAULTOPTIONS = {
17
- formatOptions : [ {
18
- type : 'button' ,
19
- name : 'bold' ,
20
- innerHTML : 'Bold'
21
- } ,
22
- {
23
- type : 'button' ,
24
- name : 'italic' ,
25
- innerHTML : 'Italic'
26
- } ,
27
- {
28
- type : 'radio' ,
29
- name : 'align' ,
30
- options : [ 'left' , 'center' , 'right' ]
31
- }
17
+ formatOptions : [
18
+ {
19
+ type : 'button' ,
20
+ name : 'bold' ,
21
+ innerHTML : 'Bold'
22
+ } ,
23
+ {
24
+ type : 'button' ,
25
+ name : 'italic' ,
26
+ innerHTML : 'Italic'
27
+ } ,
28
+ {
29
+ type : 'radio' ,
30
+ name : 'align' ,
31
+ options : [ 'left' , 'center' , 'right' ]
32
+ }
32
33
] ,
33
34
gridColumns : 10 ,
34
35
gridRows : 10 ,
35
36
selectorWrongMsg : 'Can\'t find html element with given selector.' ,
37
+ metaFieldsId : 'jt-meta-fields' ,
36
38
formatOptionsId : 'jt-format-options' ,
37
39
colBtnId : 'jt-col-btn' ,
38
40
rowBtnId : 'jt-row-btn' ,
39
- tableMainClass : 'js-main-table'
41
+ tableMainClass : 'js-main-table' ,
42
+ metaFields : [
43
+ {
44
+ type : 'string' ,
45
+ name : 'name'
46
+ } ,
47
+ {
48
+ type : 'string' ,
49
+ name : 'description'
50
+ }
51
+ ]
40
52
}
41
53
42
54
function Grid ( el , callback , rows , columns ) {
@@ -157,23 +169,72 @@ Grid.prototype = {
157
169
}
158
170
}
159
171
160
- function JSONTableView ( container , formatOptions ) {
161
- return this . init ( container , formatOptions )
172
+ function JSONTableKeyboardShortcuts ( view , model ) {
173
+ return this . init ( view , model )
174
+ }
175
+
176
+ JSONTableKeyboardShortcuts . prototype = {
177
+ init : function ( view , model ) {
178
+ this . view = view
179
+ this . model = model
180
+ this . bindUpKey ( )
181
+ this . bindDownKey ( )
182
+ this . bindUndoKey ( )
183
+ this . bindRedoKey ( )
184
+ } ,
185
+
186
+ bindUpKey : function ( ) {
187
+ var self = this ;
188
+ this . view . container . addEventListener ( 'keydown' , function ( event ) {
189
+ if ( event . keyCode === 38 && self . model . currentCell ) {
190
+ self . moveArrowUpDown ( - 1 )
191
+ }
192
+ } )
193
+ } ,
194
+
195
+ bindDownKey : function ( ) {
196
+ var self = this ;
197
+ this . view . container . addEventListener ( 'keydown' , function ( event ) {
198
+ if ( event . keyCode === 40 && self . model . currentCell ) {
199
+ self . moveArrowUpDown ( 1 )
200
+ }
201
+ } )
202
+ } ,
203
+
204
+ moveArrowUpDown : function ( direction , keyCode ) {
205
+ var currentCell = Object . assign ( { } , this . model . currentCell )
206
+ currentCell . row = ( Number ( currentCell . row ) + direction + this . model . meta . rows ) % this . model . meta . rows
207
+ this . view . focusCurrentCell ( currentCell )
208
+ } ,
209
+
210
+ bindUndoKey : function ( ) {
211
+
212
+ } ,
213
+
214
+ bindRedoKey : function ( ) {
215
+
216
+ }
217
+ }
218
+
219
+ function JSONTableView ( container , formatOptions , metaFields ) {
220
+ return this . init ( container , formatOptions , metaFields )
162
221
}
163
222
164
223
JSONTableView . prototype = {
165
- init : function ( container , formatOptions ) {
224
+ init : function ( container , formatOptions , metaFields ) {
166
225
this . table = document . createElement ( 'table' )
167
226
this . table . setAttribute ( 'class' , DEFAULTOPTIONS . tableMainClass )
168
227
this . cellTag = 'td'
169
228
this . container = container
170
229
this . formatOptions = formatOptions
230
+ this . metaFields = metaFields
231
+ this . metaFieldsId = DEFAULTOPTIONS . metaFieldsId
171
232
this . formatOptionsId = DEFAULTOPTIONS . formatOptionsId
172
233
this . colBtnId = DEFAULTOPTIONS . colBtnId
173
234
this . rowBtnId = DEFAULTOPTIONS . rowBtnId
174
235
} ,
175
236
176
- insert : function ( ) {
237
+ insert : function ( model ) {
177
238
var container = this . container
178
239
if ( container . firstChild ) {
179
240
container . replaceChild ( this . table , container . childNodes [ 0 ] )
@@ -182,6 +243,8 @@ JSONTableView.prototype = {
182
243
}
183
244
container . insertAdjacentHTML ( 'afterbegin' , this . formatOptionsContainer ( ) )
184
245
this . updateFormatOptions ( )
246
+ container . insertAdjacentHTML ( 'afterbegin' , this . metaFieldsContainer ( ) )
247
+ this . updateMetaFields ( model )
185
248
container . insertAdjacentHTML ( 'beforeend' , this . utilButtons ( ) )
186
249
} ,
187
250
@@ -241,6 +304,28 @@ JSONTableView.prototype = {
241
304
return html
242
305
} ,
243
306
307
+ updateMetaFields : function ( model ) {
308
+ var html = '' ;
309
+ for ( var i = 0 ; i < this . metaFields . length ; i ++ ) {
310
+ var field = this . metaFields [ i ]
311
+ if ( field . type === "string" ) {
312
+ html += field . name + ":" + '<input type="text" name="' + field . name + '" data-metakey="' + field . name + '" value="' + JSONTable . orEmpty ( model . meta [ field . name ] ) + '"><br>'
313
+ } else if ( field . type === "integer" ) {
314
+ html += field . name + ":" + '<input type="number" name="' + field . name + '" data-metakey="' + field . name + '" value="' + JSONTable . orEmpty ( model . meta [ field . name ] ) + '"><br>'
315
+ } else if ( field . type === "select" ) {
316
+ html += field . name + ":" + '<select' + ' data-metakey="' + field . name + '">'
317
+ for ( var j = 0 ; j < field . options . length ; j ++ ) {
318
+ html += '<option value="' + field . options [ j ] + '"'
319
+ html += ( model . meta [ field . name ] === field . options [ j ] ? ' selected' : '' )
320
+ html += '>' + field . options [ j ] + '</option>'
321
+ }
322
+ html += '</select><br>'
323
+ }
324
+ }
325
+ var metaFieldsContainer = JSONTable . qs ( '#' + this . metaFieldsId , this . container )
326
+ metaFieldsContainer . innerHTML = html
327
+ } ,
328
+
244
329
focusCurrentCell : function ( currentCell ) {
245
330
var selector = "[data-row='" + String ( currentCell . row ) + "'][data-col='" + String ( currentCell . col ) + "']"
246
331
var cell = JSONTable . qs ( selector , this . container )
@@ -250,6 +335,12 @@ JSONTableView.prototype = {
250
335
}
251
336
} ,
252
337
338
+ metaFieldsContainer : function ( ) {
339
+ var html = '<div class="jt-meta-fields" id="' + this . metaFieldsId + '">'
340
+ html += '</div>'
341
+ return html
342
+ } ,
343
+
253
344
formatOptionsContainer : function ( ) {
254
345
var html = '<div class="jt-format-options" id="' + this . formatOptionsId + '">'
255
346
html += '</div>'
@@ -352,6 +443,10 @@ JSONTableModel.prototype = {
352
443
this . data [ row ] [ column ] . content = event . target . innerHTML
353
444
} ,
354
445
446
+ updateMetaContent : function ( event ) {
447
+ this . meta [ event . target . dataset . metakey ] = event . target . value
448
+ } ,
449
+
355
450
addARow : function ( ) {
356
451
this . meta . rows += 1
357
452
this . updateDataAddRemoveExtraRowColumn ( )
@@ -444,6 +539,7 @@ JSONTableController.prototype = {
444
539
self . handleCellBlur ( e )
445
540
} )
446
541
this . bindEventOnFormatingOptions ( )
542
+ this . bindEventOnMetaFields ( )
447
543
} ,
448
544
449
545
bindEventOnCell : function ( type , handler ) {
@@ -465,6 +561,18 @@ JSONTableController.prototype = {
465
561
}
466
562
} ,
467
563
564
+ bindEventOnMetaFields : function ( ) {
565
+ var self = this
566
+ JSONTable . delegate (
567
+ JSONTable . qs ( '#' + this . view . metaFieldsId , this . view . container ) ,
568
+ 'input, select' ,
569
+ 'change' ,
570
+ function ( e ) {
571
+ self . handleMetaChange ( e )
572
+ }
573
+ )
574
+ } ,
575
+
468
576
handleCellFocus : function ( event ) {
469
577
var self = this
470
578
this . model . setCurrentCell ( event . target . dataset )
@@ -486,6 +594,11 @@ JSONTableController.prototype = {
486
594
} , 15 )
487
595
} ,
488
596
597
+ handleMetaChange : function ( event ) {
598
+ this . model . updateMetaContent ( event )
599
+ this . view . container . dispatchEvent ( this . model . data_changed_event )
600
+ } ,
601
+
489
602
handleBtnClick : function ( event ) {
490
603
this . blur_created_by_button_click = true
491
604
event . preventDefault ( )
@@ -510,7 +623,7 @@ JSONTableController.prototype = {
510
623
}
511
624
}
512
625
513
- function JSONTable ( selector , tableData , options ) {
626
+ function JSONTable ( selector , options , tableData ) {
514
627
return this . init ( selector , tableData , options )
515
628
}
516
629
@@ -522,12 +635,13 @@ JSONTable.prototype = {
522
635
this . gridRows = options . gridRows || DEFAULTOPTIONS . gridRows
523
636
this . gridColumns = options . gridColumns || DEFAULTOPTIONS . gridColumns
524
637
this . formatOptions = options . formatOptions || DEFAULTOPTIONS . formatOptions
638
+ this . metaFields = options . metaFields || DEFAULTOPTIONS . metaFields
525
639
this . container = JSONTable . qs ( selector )
526
640
if ( ! this . container ) {
527
641
throw DEFAULTOPTIONS . selectorWrongMsg
528
642
}
529
643
this . model = new JSONTableModel ( tableData )
530
- this . view = new JSONTableView ( this . container , this . formatOptions )
644
+ this . view = new JSONTableView ( this . container , this . formatOptions , this . metaFields )
531
645
this . controller = new JSONTableController ( this . view , this . model )
532
646
this . setupTable ( )
533
647
} ,
@@ -549,9 +663,10 @@ JSONTable.prototype = {
549
663
} ,
550
664
551
665
initTable : function ( ) {
552
- this . view . insert ( )
666
+ this . view . insert ( this . model )
553
667
this . view . update ( this . model )
554
668
this . controller . bindEvents ( )
669
+ this . keyboardHandler = new JSONTableKeyboardShortcuts ( this . view , this . model )
555
670
}
556
671
}
557
672
@@ -602,5 +717,40 @@ JSONTable.prototype = {
602
717
}
603
718
}
604
719
720
+ JSONTable . orEmpty = function ( entity ) {
721
+ return entity || ""
722
+ }
723
+
724
+ // polyfill for Object.assign
725
+ if ( typeof Object . assign != 'function' ) {
726
+ // Must be writable: true, enumerable: false, configurable: true
727
+ Object . defineProperty ( Object , "assign" , {
728
+ value : function assign ( target , varArgs ) { // .length of function is 2
729
+ 'use strict' ;
730
+ if ( target == null ) { // TypeError if undefined or null
731
+ throw new TypeError ( 'Cannot convert undefined or null to object' ) ;
732
+ }
733
+
734
+ var to = Object ( target ) ;
735
+
736
+ for ( var index = 1 ; index < arguments . length ; index ++ ) {
737
+ var nextSource = arguments [ index ] ;
738
+
739
+ if ( nextSource != null ) { // Skip over if undefined or null
740
+ for ( var nextKey in nextSource ) {
741
+ // Avoid bugs when hasOwnProperty is shadowed
742
+ if ( Object . prototype . hasOwnProperty . call ( nextSource , nextKey ) ) {
743
+ to [ nextKey ] = nextSource [ nextKey ] ;
744
+ }
745
+ }
746
+ }
747
+ }
748
+ return to ;
749
+ } ,
750
+ writable : true ,
751
+ configurable : true
752
+ } ) ;
753
+ }
754
+
605
755
window . JSONTableEditor = JSONTable
606
756
} ) ( )
0 commit comments