}, vnode.attrs.value)
},
oncreate: function(vnode) {
- $(vnode.dom).selectize({
+ this.selectized = $(vnode.dom).selectize({
labelField: 'value',
valueField: 'value',
searchField: 'value',
sortField: 'value',
maxItems: 1,
+ placeholder: vnode.attrs.placeholder,
create: vnode.attrs.create ? function(input) {
return {value: input}
} : false,
return {value: option}
}),
onChange: function(val) {
- vnode.attrs.value(val)
+ if (val != '') {
+ vnode.attrs.value(val)
+ }
}
})
+ if (vnode.attrs.setFocus) {
+ this.selectized[0].selectize.focus()
+ }
}
}
window.TagEditorRow = {
view: function(vnode) {
+ // Name options list
+ var nameOpts = Object.keys(vnode.attrs.vocabulary().tags)
+ if (vnode.attrs.name() != '' && !(vnode.attrs.name() in vnode.attrs.vocabulary().tags)) {
+ nameOpts.push(vnode.attrs.name())
+ }
// Value options list
- valueOpts = []
- if (vnode.attrs.name() in vnode.attrs.vocabulary().types &&
- 'options' in vnode.attrs.vocabulary().types[vnode.attrs.name()]) {
- valueOpts = vnode.attrs.vocabulary().types[vnode.attrs.name()].options
+ var valueOpts = []
+ if (vnode.attrs.name() in vnode.attrs.vocabulary().tags &&
+ 'values' in vnode.attrs.vocabulary().tags[vnode.attrs.name()]) {
+ valueOpts = vnode.attrs.vocabulary().tags[vnode.attrs.name()].values
+ }
+ if (vnode.attrs.value() != '') {
+ valueOpts.push(vnode.attrs.value())
}
- valueOpts.push(vnode.attrs.value())
-
return m("tr", [
// Erase tag
- m("td",
- vnode.attrs.editMode &&
+ m("td", [
+ vnode.attrs.editMode &&
m('div.text-center', m('a.btn.btn-default.btn-sm', {
style: {
align: 'center'
},
onclick: function(e) { vnode.attrs.removeTag() }
- }, m('i.fa.fa-fw.fa-trash-o'))),
- ),
+ }, m('i.fa.fa-fw.fa-trash-o')))
+ ]),
// Tag name
- m("td",
- vnode.attrs.editMode ?
- m("div", {key: 'name-'+vnode.attrs.name()},[m(SelectOrAutocomplete, {
- options: (vnode.attrs.name() in vnode.attrs.vocabulary().types)
- ? Object.keys(vnode.attrs.vocabulary().types)
- : Object.keys(vnode.attrs.vocabulary().types).concat(vnode.attrs.name()),
- value: vnode.attrs.name,
- create: vnode.attrs.vocabulary().strict
- })])
- : vnode.attrs.name),
+ m("td", [
+ vnode.attrs.editMode ?
+ m("div", {key: 'name-'+vnode.attrs.name()},[
+ m(SelectOrAutocomplete, {
+ options: nameOpts,
+ value: vnode.attrs.name,
+ // Allow any tag name unless "strict" is set to true.
+ create: !vnode.attrs.vocabulary().strict,
+ placeholder: 'new tag',
+ // Focus on tag name field when adding a new tag that's
+ // not the first one.
+ setFocus: !vnode.attrs.firstRow && vnode.attrs.name() === ''
+ })
+ ])
+ : vnode.attrs.name
+ ]),
// Tag value
- m("td",
- vnode.attrs.editMode ?
- m("div", {key: 'value-'+vnode.attrs.name()}, [m(SelectOrAutocomplete, {
- options: valueOpts,
- value: vnode.attrs.value,
- create: (vnode.attrs.name() in vnode.attrs.vocabulary().types)
- ? (vnode.attrs.vocabulary().types[vnode.attrs.name()].type == 'text') ||
- vnode.attrs.vocabulary().types[vnode.attrs.name()].overridable || false
- : true, // If tag not in vocabulary, we should accept any value
- })
+ m("td", [
+ vnode.attrs.editMode ?
+ m("div", {key: 'value-'+vnode.attrs.name()}, [
+ m(SelectOrAutocomplete, {
+ options: valueOpts,
+ value: vnode.attrs.value,
+ placeholder: 'new value',
+ // Allow any value on tags not listed on the vocabulary.
+ // Allow any value on tags without values, or the ones
+ // that aren't explicitly declared to be strict.
+ create: !(vnode.attrs.name() in vnode.attrs.vocabulary().tags)
+ || !vnode.attrs.vocabulary().tags[vnode.attrs.name()].values
+ || vnode.attrs.vocabulary().tags[vnode.attrs.name()].values.length === 0
+ || !vnode.attrs.vocabulary().tags[vnode.attrs.name()].strict,
+ // Focus on tag value field when new tag name is set
+ setFocus: vnode.attrs.name() !== '' && vnode.attrs.value() === ''
+ })
+ ])
+ : vnode.attrs.value
])
- : vnode.attrs.value)
])
}
}
window.TagEditorTable = {
view: function(vnode) {
- return m("table.table.table-condensed", {
- border: "1"
- }, [
+ return m("table.table.table-condensed", [
m("colgroup", [
m("col", {width:"5%"}),
m("col", {width:"25%"}),
vnode.attrs.dirty(true)
},
editMode: vnode.attrs.editMode,
+ firstRow: vnode.attrs.tags.length === 1,
name: tag.name,
value: tag.value,
vocabulary: vnode.attrs.vocabulary
})
})
- : m("tr", m("td[colspan=3]", m("center","(no tags)")))
+ : m("tr", m("td[colspan=3]", m("center","loading tags...")))
]),
])
}
window.TagEditorApp = {
appendTag: function(vnode, name, value) {
var tag = {name: m.stream(name), value: m.stream(value)}
- tag.name.map(vnode.state.dirty)
- tag.value.map(vnode.state.dirty)
- tag.name.map(m.redraw)
vnode.state.tags.push(tag)
+ // Set dirty flag when any of name/value changes to non empty string
+ tag.name.map(function(v) {
+ if (v !== '') {
+ vnode.state.dirty(true)
+ }
+ })
+ tag.value.map(function(v) {
+ if (v !== '') {
+ vnode.state.dirty(true)
+ }
+ })
+ tag.name.map(m.redraw)
},
oninit: function(vnode) {
vnode.state.sessionDB = new SessionDB()
// Get vocabulary
- vnode.state.vocabulary = m.stream({"strict":false, "types":{}})
+ vnode.state.vocabulary = m.stream({"strict":false, "tags":{}})
m.request('/vocabulary.json').then(vnode.state.vocabulary)
vnode.state.editMode = vnode.attrs.targetEditable
vnode.state.tags = []
})
// Data synced with server, so dirty state should be false
vnode.state.dirty(false)
+ // Add new tag row when the last one is completed
+ vnode.state.dirty.map(function() {
+ if (!vnode.state.editMode) { return }
+ lastTag = vnode.state.tags.slice(-1).pop()
+ if (lastTag === undefined || (lastTag.name() !== '' && lastTag.value() !== '')) {
+ vnode.state.appendTag(vnode, '', '')
+ }
+ })
}
}
)
onclick: function(e) {
var tags = {}
vnode.state.tags.forEach(function(t) {
- tags[t.name()] = t.value()
+ if (t.name() != '' && t.value() != '') {
+ tags[t.name()] = t.value()
+ }
})
vnode.state.sessionDB.request(
vnode.state.sessionDB.loadLocal(),
tags: vnode.state.tags,
vocabulary: vnode.state.vocabulary,
dirty: vnode.state.dirty
- }),
- vnode.state.editMode &&
- m("div.pull-left", [
- // Add tag button
- m("a.btn.btn-primary.btn-sm", {
- onclick: function(e) {
- vnode.state.appendTag(vnode, 'new tag', 'new value')
- }
- }, [
- m("i.glyphicon.glyphicon-plus"),
- " Add new tag "
- ])
- ])
+ })
]
},
}
\ No newline at end of file