@quartic/bokehjs
Version:
Interactive, novel data visualization
283 lines (206 loc) • 6.69 kB
text/coffeescript
import * as $ from "jquery"
import "jquery-ui/autocomplete"
import "jquery-ui/spinner"
import * as p from "core/properties"
import {BokehView} from "core/bokeh_view"
import {Model} from "../../model"
import {JQueryable} from "./jqueryable"
export class CellEditorView extends BokehView
extends JQueryable
className: "bk-cell-editor"
input: null
emptyValue: null
defaultValue: null
initialize: (options) ->
= options
= .column.editor
super(options)
render: () ->
super()
@$el.appendTo(.container)
@$input = $()
@$el.append(@$input)
return @
renderEditor: () ->
disableNavigation: () ->
@$input.keydown (event) =>
stop = () -> event.stopImmediatePropagation()
switch event.keyCode
when $.ui.keyCode.LEFT then stop()
when $.ui.keyCode.RIGHT then stop()
when $.ui.keyCode.UP then stop()
when $.ui.keyCode.DOWN then stop()
when $.ui.keyCode.PAGE_UP then stop()
when $.ui.keyCode.PAGE_DOWN then stop()
destroy: () ->
focus: () -> @$input.focus()
show: () ->
hide: () ->
position: () ->
getValue: () -> return @$input.val()
setValue: (val) -> @$input.val(val)
serializeValue: () -> return
isValueChanged: () -> return not ( == "" and not ?) and ( != )
applyValue: (item, state) ->
# XXX: In perfect world this would be `item[.column.field] = state`.
.grid.getData().setField(item.index, .column.field, state)
loadValue: (item) ->
value = item[.column.field]
= if value? then value else
validateValue: (value) ->
if .column.validator
result = .column.validator(value)
if !result.valid
return result
return { valid: true, msg: null }
validate: () -> return
export class CellEditor extends Model
type: "CellEditor"
default_view: CellEditorView
export class StringEditorView extends CellEditorView
emptyValue: ""
input: '<input type="text" />'
renderEditor: () ->
completions = .completions
if completions.length != 0
@$input.autocomplete(source: completions)
@$input.autocomplete("widget").addClass("bk-cell-editor-completion")
@$input.focus().select()
loadValue: (item) ->
super(item)
@$input[0].defaultValue =
@$input.select()
export class StringEditor extends CellEditor
type: 'StringEditor'
default_view: StringEditorView
{
completions: [ p.Array, [] ]
}
export class TextEditorView extends CellEditorView
export class TextEditor extends CellEditor
type: 'TextEditor'
default_view: TextEditorView
export class SelectEditorView extends CellEditorView
input: '<select />'
renderEditor: () ->
for option in .options
@$input.append($('<option>').attr(value: option).text(option))
loadValue: (item) ->
super(item)
@$input.select()
export class SelectEditor extends CellEditor
type: 'SelectEditor'
default_view: SelectEditorView
{
options: [ p.Array, [] ]
}
export class PercentEditorView extends CellEditorView
export class PercentEditor extends CellEditor
type: 'PercentEditor'
default_view: PercentEditorView
export class CheckboxEditorView extends CellEditorView
input: '<input type="checkbox" value="true" />'
renderEditor: () ->
loadValue: (item) ->
= !!item[.column.field]
@$input.prop('checked', )
serializeValue: () ->
return @$input.prop('checked')
export class CheckboxEditor extends CellEditor
type: 'CheckboxEditor'
default_view: CheckboxEditorView
export class IntEditorView extends CellEditorView
input: '<input type="text" />'
renderEditor: () ->
@$input.spinner(step: .step)
@$input.focus().select()
remove: () ->
@$input.spinner("destroy")
super()
serializeValue: () ->
return parseInt(, 10) || 0
loadValue: (item) ->
super(item)
@$input[0].defaultValue =
@$input.select()
validateValue: (value) ->
if isNaN(value)
return { valid: false, msg: "Please enter a valid integer" }
else
return super(value)
export class IntEditor extends CellEditor
type: 'IntEditor'
default_view: IntEditorView
{
step: [ p.Number, 1 ]
}
export class NumberEditorView extends CellEditorView
input: '<input type="text" />'
renderEditor: () ->
@$input.spinner(step: .step)
@$input.focus().select()
remove: () ->
@$input.spinner("destroy")
super()
serializeValue: () ->
return parseFloat() || 0.0
loadValue: (item) ->
super(item)
@$input[0].defaultValue =
@$input.select()
validateValue: (value) ->
if isNaN(value)
return { valid: false, msg: "Please enter a valid number" }
else
return super(value)
export class NumberEditor extends CellEditor
type: 'NumberEditor'
default_view: NumberEditorView
{
step: [ p.Number, 0.01 ]
}
export class TimeEditorView extends CellEditorView
export class TimeEditor extends CellEditor
type: 'TimeEditor'
default_view: TimeEditorView
export class DateEditorView extends CellEditorView
emptyValue: new Date()
input: '<input type="text" />'
renderEditor: () ->
= false
@$input.datepicker
showOn: "button"
buttonImageOnly: true
beforeShow: () => = true
onClose: () => = false
@$input.siblings(".bk-ui-datepicker-trigger").css("vertical-align": "middle")
@$input.width(@$input.width() - (14 + 2*4 + 4)) # img width + margins + edge distance
@$input.focus().select()
destroy: () ->
$.datepicker.dpDiv.stop(true, true)
@$input.datepicker("hide")
@$input.datepicker("destroy")
super()
show: () ->
if
$.datepicker.dpDiv.stop(true, true).show()
super()
hide: () ->
if
$.datepicker.dpDiv.stop(true, true).hide()
super()
position: (position) ->
if
$.datepicker.dpDiv.css(top: position.top + 30, left: position.left)
super()
getValue: () -> return @$input.datepicker("getDate").getTime()
setValue: (val) -> @$input.datepicker("setDate", new Date(val))
export class DateEditor extends CellEditor
type: 'DateEditor'
default_view: DateEditorView