Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
[#381](https://github.com/nextcloud/cookbook/pull/381) @thembeat
- Changing category name for all recipes in a category
[#555](https://github.com/nextcloud/cookbook/pull/555/) @seyfeb

- Functionality to reference other recipes by id in description, tools, ingredients, and instructions
[#562](https://github.com/nextcloud/cookbook/pull/562/) @seyfeb

### Changed
- Using computed property in recipe view
[#522](https://github.com/nextcloud/cookbook/pull/522/) @seyfeb
Expand Down
2 changes: 1 addition & 1 deletion src/components/AppNavi.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<AppNavigationCaption :title="t('cookbook', 'Categories')" >
<template slot="actions">
<ActionButton icon="icon-rename" @click="toggleCategoryRenaming">
Enable editing
{{ t('cookbook', 'Toggle editing') }}
</ActionButton>
</template>
</AppNavigationCaption>
Expand Down
119 changes: 112 additions & 7 deletions src/components/EditInputField.vue
Original file line number Diff line number Diff line change
@@ -1,21 +1,41 @@
<template>
<fieldset>
<fieldset @keyup="keyPressed">
<label>
{{ fieldLabel }}
</label>
<markdown-editor class='editor' v-if="fieldType==='markdown'" :type="textarea" v-model="content" @input="handleInput" toolbar='' />
<input v-else-if="fieldType!=='textarea'" :type="fieldType" v-model="content" @input="handleInput" />
<textarea v-else-if="fieldType==='textarea'" v-model="content" @input="handleInput" />
<markdown-editor ref="inputField" class='editor' v-if="fieldType==='markdown'" v-model="content" @input="handleInput" toolbar='' />
<input ref="inputField" v-else-if="fieldType!=='textarea'" :type="fieldType" v-model="content" @input="handleInput" />
<textarea ref="inputField" v-if="fieldType==='textarea'" v-model="content" @input="handleInput" />
</fieldset>
</template>

<script>

export default {
name: "EditInputField",
props: ['value','fieldType','fieldLabel'],
props: {
fieldLabel: {
type: String,
default: ''
},
fieldType: {
type: String,
default: ''
},
referencePopupEnabled: {
type: Boolean,
default: false
},
// Value (passed in v-model)
value: {
default: '',
required: true
}
},
data () {
return {
content: ''
content: '',
lastCursorPosition: -1
}
},
watch: {
Expand All @@ -27,6 +47,90 @@ export default {
handleInput (e) {
this.$emit('input', this.content)
},
/**
* Catches # key down presses and opens recipe-references dialog
*/
keyPressed(e) {
// Using keyup for trigger will prevent repeat triggering if key is held down
if (this.referencePopupEnabled && e.keyCode === 51) {
e.preventDefault()
// Check if the letter before the hash
if (this.fieldType === 'markdown') {
// for reference: https://codemirror.net/doc/manual.html#api
let cursorPos = JSON.parse(JSON.stringify(this.$refs.inputField.editor.getCursor('start')))
let prevChar = this.$refs.inputField.editor.getRange(
{line: cursorPos.line, ch: cursorPos.ch-2},
{line: cursorPos.line, ch: cursorPos.ch-1})
if (cursorPos.ch === 1 || prevChar === ' ' || prevChar === '\n' || prevChar === '\r') {
// beginning of line
this.$parent.$emit('showRecipeReferencesPopup', {context: this})
this.lastCursorPosition = cursorPos
}
} else {
this.$refs['inputField'].selectionStart
let content = this.$refs['inputField'].value
let prevChar = cursorPos > 1 ? content.charAt(cursorPos-2) : ''
if (cursorPos === 1 || prevChar === ' ' || prevChar === '\n' || prevChar === '\r') {
// Show dialog to select recipe
this.$parent.$emit('showRecipeReferencesPopup', {context: this})
this.lastCursorPosition = cursorPos
}
}

}
},
pasteCanceled() {
// set cursor to position after pasted string
this.$nextTick(function() {
let field = this.$refs['inputField']
if (this.fieldType === 'markdown') {
field.editor.setCursor(this.lastCursorPosition)
field.editor.focus()
} else {
field.focus()
field.setSelectionRange (this.lastCursorPosition, this.lastCursorPosition)
}
})
},
/**
* Paste string at the last saved cursor position
*/
pasteString(str) {
let field = this.$refs['inputField']

if (this.fieldType == 'markdown') {
// insert at last cursor position
field.editor.replaceRange(str,
{line: this.lastCursorPosition.line, ch: this.lastCursorPosition.ch}
)
this.$emit('input', this.content)
this.$nextTick(() => {
this.$nextTick(() => {
field.editor.focus()
field.editor.setCursor({line: this.lastCursorPosition.line, ch: this.lastCursorPosition.ch + str.length})
})
})

} else {
// insert str
this.content = this.content.slice(0, this.lastCursorPosition)
+ str + this.content.slice(this.lastCursorPosition)
this.$emit('input', this.content)

// set cursor to position after pasted string. Waiting two ticks is necessary for
// the data to be updated in the field
this.$nextTick(() => {
this.$nextTick(() => {
field.focus()
let newCursorPos = this.lastCursorPosition + str.length
field.setSelectionRange( newCursorPos, newCursorPos)
})
})
}

}
},
mounted() {
}
}
</script>
Expand Down Expand Up @@ -72,11 +176,12 @@ fieldset > .editor {
fieldset > .editor {
min-height: 10em;
resize: vertical;
radius: 2;
border-radius: 2;
}

@media(max-width:1199px) { fieldset > input, fieldset > textarea, fieldset > .editor {
width: 100%;
}}


</style>
85 changes: 77 additions & 8 deletions src/components/EditInputGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<li :class="fieldType" v-for="(entry,idx) in buffer" :key="fieldName+idx">
<div v-if="showStepNumber" class="step-number">{{ parseInt(idx) + 1 }}</div>
<input v-if="fieldType==='text'" type="text" ref="list-field" v-model="buffer[idx]" @keyup="keyPressed" v-on:input="handleInput" @paste="handlePaste" />
<textarea v-else-if="fieldType==='textarea'" ref="list-field" v-model="buffer[idx]" v-on:input="handleInput" @paste="handlePaste"></textarea>
<textarea v-else-if="fieldType==='textarea'" ref="list-field" v-model="buffer[idx]" @keyup="keyPressed" v-on:input="handleInput" @paste="handlePaste"></textarea>
<div class="controls">
<button class="icon-arrow-up" @click="moveEntryUp(idx)"></button>
<button class="icon-arrow-down" @click="moveEntryDown(idx)"></button>
Expand All @@ -18,6 +18,7 @@
</template>

<script>

export default {
name: "EditInputGroup",
props: {
Expand All @@ -26,7 +27,10 @@ export default {
default: []
},
fieldType: String,
fieldName: String,
fieldName: {
type: String,
default: ''
},
showStepNumber: {
type: Boolean,
default: false
Expand All @@ -37,13 +41,20 @@ export default {
type: Boolean,
default: false
},
referencePopupEnabled: {
type: Boolean,
default: false
}
},
data () {
return {
// helper variables
buffer: this.value.slice(),
contentPasted: false,
singleLinePasted: false
singleLinePasted: false,
lastFocusedFieldIndex: null,
lastCursorPosition: -1,
ignoreNextKeyUp: false
}
},
watch: {
Expand Down Expand Up @@ -156,17 +167,42 @@ export default {
* Catches enter and key down presses and either adds a new row or focuses the one below
*/
keyPressed(e) {
// If, e.g., enter has been pressed in the multiselect popup to select an option,
// ignore the following keyup event
if(this.ignoreNextKeyUp) {
this.ignoreNextKeyUp = false
return
}
// Using keyup for trigger will prevent repeat triggering if key is held down
if (e.keyCode === 13 || e.keyCode === 10) {
if (e.keyCode === 13 ||
e.keyCode === 10 ||
(this.referencePopupEnabled && e.keyCode === 51)) {
e.preventDefault()
let $li = e.currentTarget.closest('li')
let $ul = $li.closest('ul')
let $pressed_li_index = Array.prototype.indexOf.call($ul.childNodes, $li)

if ($pressed_li_index >= this.$refs['list-field'].length - 1) {
this.addNewEntry ()
} else {
$ul.children[$pressed_li_index+1].getElementsByTagName('input')[0].focus()
if (e.keyCode === 13 || e.keyCode === 10) {
if ($pressed_li_index >= this.$refs['list-field'].length - 1) {
this.addNewEntry ()
} else {
$ul.children[$pressed_li_index+1].getElementsByTagName('input')[0].focus()
}
}
else if (this.referencePopupEnabled && e.keyCode === 51) {
e.preventDefault()
let elm = this.$refs['list-field'][$pressed_li_index]
// Check if the letter before the hash
let cursorPos = elm.selectionStart
let content = elm.value
let prevChar = cursorPos > 1 ? content.charAt(cursorPos-2) : ''

if (cursorPos === 1 || prevChar === ' ' || prevChar === '\n' || prevChar === '\r') {
// Show dialog to select recipe
this.$parent.$emit('showRecipeReferencesPopup', {context: this})
this.lastFocusedFieldIndex = $pressed_li_index
this.lastCursorPosition = cursorPos
}
}
}
},
Expand All @@ -192,6 +228,39 @@ export default {
this.buffer.splice(index - 1, 0, entry)
this.$emit('input', this.buffer)
},
pasteCanceled() {
let field = this.$refs['list-field'][this.lastFocusedFieldIndex]
// set cursor back to previous position
this.$nextTick(function() {
field.focus()
field.setSelectionRange (this.lastCursorPosition, this.lastCursorPosition)
})
},
/**
* Paste string at the last saved cursor position
*/
pasteString(str, ignoreKeyup=true) {
let field = this.$refs['list-field'][this.lastFocusedFieldIndex]

// insert str
let content = field.value
let updatedContent = content.slice(0, this.lastCursorPosition)
+ str
+ content.slice(this.lastCursorPosition)
this.buffer[this.lastFocusedFieldIndex] = updatedContent
this.$emit('input', this.buffer)

// set cursor to position after pasted string. Waiting two ticks is necessary for
// the data to be updated in the field
this.$nextTick(function() {
this.$nextTick(function() {
this.ignoreNextKeyUp = ignoreKeyup
field.focus()
let newCursorPos = this.lastCursorPosition + str.length
field.setSelectionRange (newCursorPos, newCursorPos)
})
})
}
},
}
</script>
Expand Down
Loading