mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-10-09 13:28:53 +08:00
Merge pull request #4215 from aignatov-bio/ai-sci-6939-fix-smart-annotation-in-new-steps
Fix smart annotation for step editing [SCI-6939]
This commit is contained in:
commit
fa623a9f19
8 changed files with 73 additions and 48 deletions
|
@ -5,28 +5,21 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
width: calc(100% + 16px);
|
width: calc(100% + 16px);
|
||||||
|
|
||||||
.action-container {
|
|
||||||
cursor: pointer;
|
|
||||||
height: 100%;
|
|
||||||
left: 0;
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 100;
|
|
||||||
|
|
||||||
.buttons-container {
|
.buttons-container {
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
90deg,
|
90deg,
|
||||||
transparent 0%,
|
transparent 0%,
|
||||||
$color-concrete 25%,
|
$color-concrete 25%,
|
||||||
$color-concrete 100%
|
$color-concrete 100%
|
||||||
);
|
);
|
||||||
display: none;
|
display: none;
|
||||||
padding-left: 2em;
|
padding-left: 2em;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.element-grip {
|
.element-grip {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: $color-silver-chalice;
|
color: $color-silver-chalice;
|
||||||
|
@ -66,7 +59,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&.edit {
|
&.edit {
|
||||||
.action-container {
|
.buttons-container,
|
||||||
|
.element-grip {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -298,14 +298,14 @@
|
||||||
let index = this.elements.findIndex((e) => e.id === element.id);
|
let index = this.elements.findIndex((e) => e.id === element.id);
|
||||||
|
|
||||||
if (skipRequest) {
|
if (skipRequest) {
|
||||||
this.elements[index].orderable = element;
|
this.elements[index].attributes.orderable = element.attributes.orderable;
|
||||||
} else {
|
} else {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: element.attributes.orderable.urls.update_url,
|
url: element.attributes.orderable.urls.update_url,
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
data: element.attributes.orderable,
|
data: element.attributes.orderable,
|
||||||
success: (result) => {
|
success: (result) => {
|
||||||
this.elements[index].orderable = result;
|
this.elements[index].attributes.orderable = result.data.attributes;
|
||||||
}
|
}
|
||||||
}).error(() => {
|
}).error(() => {
|
||||||
HelperModule.flashAlertMsg(this.i18n.t('errors.general'), 'danger');
|
HelperModule.flashAlertMsg(this.i18n.t('errors.general'), 'danger');
|
||||||
|
|
|
@ -8,10 +8,12 @@
|
||||||
<InlineEdit
|
<InlineEdit
|
||||||
v-if="element.attributes.orderable.urls.update_url"
|
v-if="element.attributes.orderable.urls.update_url"
|
||||||
:value="element.attributes.orderable.name"
|
:value="element.attributes.orderable.name"
|
||||||
|
:sa_value="element.attributes.orderable.sa_name"
|
||||||
:characterLimit="255"
|
:characterLimit="255"
|
||||||
:placeholder="''"
|
:placeholder="''"
|
||||||
:allowBlank="false"
|
:allowBlank="false"
|
||||||
:autofocus="editingName"
|
:autofocus="editingName"
|
||||||
|
:smartAnnotation="true"
|
||||||
:attributeName="`${i18n.t('Checklist')} ${i18n.t('name')}`"
|
:attributeName="`${i18n.t('Checklist')} ${i18n.t('name')}`"
|
||||||
@editingEnabled="editingName = true"
|
@editingEnabled="editingName = true"
|
||||||
@editingDisabled="editingName = false"
|
@editingDisabled="editingName = false"
|
||||||
|
@ -149,13 +151,16 @@
|
||||||
},
|
},
|
||||||
saveItem(item) {
|
saveItem(item) {
|
||||||
if (item.attributes.id) {
|
if (item.attributes.id) {
|
||||||
this.checklistItems.splice(
|
|
||||||
item.attributes.position, 1, item
|
|
||||||
);
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: item.attributes.urls.update_url,
|
url: item.attributes.urls.update_url,
|
||||||
type: 'PATCH',
|
type: 'PATCH',
|
||||||
data: item,
|
data: item,
|
||||||
|
success: (result) => {
|
||||||
|
let updatedItem = this.checklistItems[item.attributes.position]
|
||||||
|
updatedItem.attributes = result.data.attributes
|
||||||
|
updatedItem.attributes.id = item.attributes.id
|
||||||
|
this.$set(this.checklistItems, item.attributes.position, updatedItem)
|
||||||
|
},
|
||||||
error: () => HelperModule.flashAlertMsg(this.i18n.t('errors.general'), 'danger')
|
error: () => HelperModule.flashAlertMsg(this.i18n.t('errors.general'), 'danger')
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,12 +17,14 @@
|
||||||
<InlineEdit
|
<InlineEdit
|
||||||
v-if="!checklistItem.attributes.urls || updateUrl"
|
v-if="!checklistItem.attributes.urls || updateUrl"
|
||||||
:value="checklistItem.attributes.text"
|
:value="checklistItem.attributes.text"
|
||||||
|
:sa_value="checklistItem.attributes.sa_text"
|
||||||
:characterLimit="10000"
|
:characterLimit="10000"
|
||||||
:placeholder="''"
|
:placeholder="''"
|
||||||
:allowBlank="true"
|
:allowBlank="true"
|
||||||
:autofocus="editingText"
|
:autofocus="editingText"
|
||||||
:attributeName="`${i18n.t('ChecklistItem')} ${i18n.t('name')}`"
|
:attributeName="`${i18n.t('ChecklistItem')} ${i18n.t('name')}`"
|
||||||
:multilinePaste="true"
|
:multilinePaste="true"
|
||||||
|
:smartAnnotation="true"
|
||||||
@editingEnabled="enableTextEdit"
|
@editingEnabled="enableTextEdit"
|
||||||
@editingDisabled="disableTextEdit"
|
@editingDisabled="disableTextEdit"
|
||||||
@update="updateText"
|
@update="updateText"
|
||||||
|
|
|
@ -1,21 +1,18 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="step-text-container" :class="{ 'edit': inEditMode }" @keyup.enter="enableEditMode($event)" tabindex="0">
|
<div class="step-text-container" :class="{ 'edit': inEditMode }" @keyup.enter="enableEditMode($event)" tabindex="0">
|
||||||
<div ref="actionContainer" class="action-container" @click="enableEditMode($event)">
|
<div v-if="reorderElementUrl" class="element-grip" @click="$emit('reorder')">
|
||||||
<div v-if="reorderElementUrl" class="element-grip" @click="$emit('reorder')">
|
<i class="fas fa-grip-vertical"></i>
|
||||||
<i class="fas fa-grip-vertical"></i>
|
</div>
|
||||||
</div>
|
<div class="buttons-container">
|
||||||
<div class="buttons-container">
|
<button v-if="element.attributes.orderable.urls.update_url" class="btn icon-btn btn-light" tabindex="-1" @click="enableEditMode($event)">
|
||||||
<button v-if="element.attributes.orderable.urls.update_url" class="btn icon-btn btn-light" tabindex="-1">
|
<i class="fas fa-pen"></i>
|
||||||
<i class="fas fa-pen"></i>
|
</button>
|
||||||
</button>
|
<button v-if="element.attributes.orderable.urls.delete_url" class="btn icon-btn btn-light" @click="showDeleteModal" tabindex="-1">
|
||||||
<button v-if="element.attributes.orderable.urls.delete_url" class="btn icon-btn btn-light" @click="showDeleteModal" tabindex="-1">
|
<i class="fas fa-trash"></i>
|
||||||
<i class="fas fa-trash"></i>
|
</button>
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<Tinymce
|
<Tinymce
|
||||||
v-if="element.attributes.orderable.urls.update_url"
|
v-if="element.attributes.orderable.urls.update_url"
|
||||||
:inEditMode="inEditMode"
|
|
||||||
:value="element.attributes.orderable.text"
|
:value="element.attributes.orderable.text"
|
||||||
:value_html="element.attributes.orderable.text_view"
|
:value_html="element.attributes.orderable.text_view"
|
||||||
:placeholder="i18n.t('protocols.steps.text.placeholder')"
|
:placeholder="i18n.t('protocols.steps.text.placeholder')"
|
||||||
|
@ -26,6 +23,7 @@
|
||||||
:lastUpdated="element.attributes.orderable.updated_at"
|
:lastUpdated="element.attributes.orderable.updated_at"
|
||||||
@update="update"
|
@update="update"
|
||||||
@editingDisabled="disableEditMode"
|
@editingDisabled="disableEditMode"
|
||||||
|
@editingEnabled="enableEditMode"
|
||||||
/>
|
/>
|
||||||
<div v-else v-html="element.attributes.orderable.text_view"></div>
|
<div v-else v-html="element.attributes.orderable.text_view"></div>
|
||||||
<deleteElementModal v-if="confirmingDelete" @confirm="deleteElement($event)" @cancel="closeDeleteModal"/>
|
<deleteElementModal v-if="confirmingDelete" @confirm="deleteElement($event)" @cancel="closeDeleteModal"/>
|
||||||
|
@ -70,10 +68,6 @@
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
enableEditMode() {
|
enableEditMode() {
|
||||||
if (
|
|
||||||
$(this.$refs.actionContainer).hasClass('fas fa-grip-vertical') ||
|
|
||||||
$(this.$refs.actionContainer).hasClass('element-grip')
|
|
||||||
) return
|
|
||||||
if (!this.element.attributes.orderable.urls.update_url) return
|
if (!this.element.attributes.orderable.urls.update_url) return
|
||||||
if (this.inEditMode == true) return
|
if (this.inEditMode == true) return
|
||||||
this.inEditMode = true
|
this.inEditMode = true
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="sci-inline-edit" :class="{ 'editing': editing }" tabindex="0" @keyup.enter="enableEdit">
|
<div class="sci-inline-edit" :class="{ 'editing': editing }" tabindex="0" @keyup.enter="enableEdit($event)">
|
||||||
<div class="sci-inline-edit__content">
|
<div class="sci-inline-edit__content">
|
||||||
<textarea
|
<textarea
|
||||||
ref="input"
|
ref="input"
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
@paste="handlePaste"
|
@paste="handlePaste"
|
||||||
@blur="handleBlur"
|
@blur="handleBlur"
|
||||||
></textarea>
|
></textarea>
|
||||||
<div v-else @click="enableEdit" class="sci-inline-edit__view" :class="{ 'blank': isBlank }">{{ value || placeholder }}</div>
|
<div v-else @click="enableEdit($event)" class="sci-inline-edit__view" v-html="sa_value || value || placeholder" :class="{ 'blank': isBlank }"></div>
|
||||||
<div v-if="editing && error" class="sci-inline-edit__error">
|
<div v-if="editing && error" class="sci-inline-edit__error">
|
||||||
{{ error }}
|
{{ error }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,12 +34,14 @@
|
||||||
name: 'InlineEdit',
|
name: 'InlineEdit',
|
||||||
props: {
|
props: {
|
||||||
value: { type: String, default: '' },
|
value: { type: String, default: '' },
|
||||||
|
sa_value: { type: String},
|
||||||
allowBlank: { type: Boolean, default: true },
|
allowBlank: { type: Boolean, default: true },
|
||||||
attributeName: { type: String, required: true },
|
attributeName: { type: String, required: true },
|
||||||
characterLimit: { type: Number },
|
characterLimit: { type: Number },
|
||||||
placeholder: { type: String },
|
placeholder: { type: String },
|
||||||
autofocus: { type: Boolean, default: false },
|
autofocus: { type: Boolean, default: false },
|
||||||
multilinePaste: { type: Boolean, default: false },
|
multilinePaste: { type: Boolean, default: false },
|
||||||
|
smartAnnotation: { type: Boolean, default: false },
|
||||||
editOnload: { type: Boolean, default: false }
|
editOnload: { type: Boolean, default: false }
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -89,6 +91,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleBlur() {
|
handleBlur() {
|
||||||
|
if ($('.atwho-view:visible').length) return;
|
||||||
|
|
||||||
if (this.allowBlank || !this.isBlank) {
|
if (this.allowBlank || !this.isBlank) {
|
||||||
this.$nextTick(this.update);
|
this.$nextTick(this.update);
|
||||||
} else {
|
} else {
|
||||||
|
@ -103,9 +107,15 @@
|
||||||
this.resize();
|
this.resize();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
enableEdit() {
|
enableEdit(e) {
|
||||||
|
if (e && $(e.target).hasClass('atwho-user-popover')) return
|
||||||
this.editing = true;
|
this.editing = true;
|
||||||
this.focus();
|
this.focus();
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.smartAnnotation) {
|
||||||
|
SmartAnnotation.init($(this.$refs.input));
|
||||||
|
}
|
||||||
|
})
|
||||||
this.$emit('editingEnabled');
|
this.$emit('editingEnabled');
|
||||||
},
|
},
|
||||||
cancelEdit() {
|
cancelEdit() {
|
||||||
|
@ -145,7 +155,7 @@
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if(!this.allowBlank && this.isBlank) return;
|
if(!this.allowBlank && this.isBlank) return;
|
||||||
if(!this.editing) return;
|
if(!this.editing) return;
|
||||||
|
this.newValue = this.$refs.input.value // Fix for smart annotation
|
||||||
this.newValue = this.newValue.trim();
|
this.newValue = this.newValue.trim();
|
||||||
this.editing = false;
|
this.editing = false;
|
||||||
this.$emit('editingDisabled');
|
this.$emit('editingDisabled');
|
||||||
|
|
|
@ -3,8 +3,18 @@
|
||||||
class ChecklistItemSerializer < ActiveModel::Serializer
|
class ChecklistItemSerializer < ActiveModel::Serializer
|
||||||
include Canaid::Helpers::PermissionsHelper
|
include Canaid::Helpers::PermissionsHelper
|
||||||
include Rails.application.routes.url_helpers
|
include Rails.application.routes.url_helpers
|
||||||
|
include ApplicationHelper
|
||||||
|
include ActionView::Helpers::TextHelper
|
||||||
|
|
||||||
attributes :id, :text, :checked, :position, :urls
|
attributes :id, :text, :checked, :position, :urls, :sa_text
|
||||||
|
|
||||||
|
def sa_text
|
||||||
|
@user = scope[:user] || @instance_options[:user]
|
||||||
|
custom_auto_link(object.text,
|
||||||
|
simple_format: false,
|
||||||
|
tags: %w(img),
|
||||||
|
team: object.checklist.step.protocol.team)
|
||||||
|
end
|
||||||
|
|
||||||
def urls
|
def urls
|
||||||
return {} if object.destroyed? ||
|
return {} if object.destroyed? ||
|
||||||
|
|
|
@ -3,14 +3,24 @@
|
||||||
class ChecklistSerializer < ActiveModel::Serializer
|
class ChecklistSerializer < ActiveModel::Serializer
|
||||||
include Canaid::Helpers::PermissionsHelper
|
include Canaid::Helpers::PermissionsHelper
|
||||||
include Rails.application.routes.url_helpers
|
include Rails.application.routes.url_helpers
|
||||||
|
include ApplicationHelper
|
||||||
|
include ActionView::Helpers::TextHelper
|
||||||
|
|
||||||
attributes :id, :name, :urls, :icon
|
attributes :id, :name, :urls, :icon, :sa_name
|
||||||
has_many :checklist_items, serializer: ChecklistItemSerializer
|
has_many :checklist_items, serializer: ChecklistItemSerializer
|
||||||
|
|
||||||
def icon
|
def icon
|
||||||
'fa-list-ul'
|
'fa-list-ul'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def sa_name
|
||||||
|
@user = scope[:user] || @instance_options[:user]
|
||||||
|
custom_auto_link(object.name,
|
||||||
|
simple_format: false,
|
||||||
|
tags: %w(img),
|
||||||
|
team: object.step.protocol.team)
|
||||||
|
end
|
||||||
|
|
||||||
def urls
|
def urls
|
||||||
return {} if object.destroyed? || !can_manage_step?(scope[:user] || @instance_options[:user], object.step)
|
return {} if object.destroyed? || !can_manage_step?(scope[:user] || @instance_options[:user], object.step)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue